1/** @file
2  Interface routines for PxeBc.
3
4Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15
16#include "PxeBcImpl.h"
17
18UINT32  mPxeDhcpTimeout[4] = { 4, 8, 16, 32 };
19
20/**
21  Get and record the arp cache.
22
23  @param  This                    Pointer to EFI_PXE_BC_PROTOCOL
24
25  @retval EFI_SUCCESS             Arp cache updated successfully
26  @retval others                  If error occurs when getting arp cache
27
28**/
29EFI_STATUS
30UpdateArpCache (
31  IN EFI_PXE_BASE_CODE_PROTOCOL     * This
32  )
33{
34  PXEBC_PRIVATE_DATA      *Private;
35  EFI_PXE_BASE_CODE_MODE  *Mode;
36  EFI_STATUS              Status;
37  UINT32                  EntryLength;
38  UINT32                  EntryCount;
39  EFI_ARP_FIND_DATA       *Entries;
40  UINT32                  Index;
41
42  Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
43  Mode    = Private->PxeBc.Mode;
44
45  Status = Private->Arp->Find (
46                     Private->Arp,
47                     TRUE,
48                     NULL,
49                     &EntryLength,
50                     &EntryCount,
51                     &Entries,
52                     TRUE
53                     );
54  if (EFI_ERROR (Status)) {
55    return Status;
56  }
57
58  Mode->ArpCacheEntries = MIN (
59                           EntryCount,
60                           EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES
61                           );
62  for (Index = 0; Index < Mode->ArpCacheEntries; Index ++) {
63    CopyMem (
64      &Mode->ArpCache[Index].IpAddr,
65      Entries + 1,
66      Entries->SwAddressLength
67      );
68    CopyMem (
69      &Mode->ArpCache[Index].MacAddr,
70      (UINT8 *) (Entries + 1) + Entries->SwAddressLength,
71      Entries->HwAddressLength
72      );
73    //
74    // Slip to the next FindData.
75    //
76    Entries = (EFI_ARP_FIND_DATA *) ((UINT8 *) Entries + EntryLength);
77  }
78
79  return EFI_SUCCESS;
80}
81
82/**
83  Timeout routine to update arp cache.
84
85  @param  Event              Pointer to EFI_PXE_BC_PROTOCOL
86  @param  Context            Context of the timer event
87
88**/
89VOID
90EFIAPI
91ArpCacheUpdateTimeout (
92  IN EFI_EVENT    Event,
93  IN VOID         *Context
94  )
95{
96  UpdateArpCache ((EFI_PXE_BASE_CODE_PROTOCOL *) Context);
97}
98
99/**
100  Do arp resolution from arp cache in PxeBcMode.
101
102  @param  PxeBcMode      The PXE BC mode to look into.
103  @param  Ip4Addr        The Ip4 address for resolution.
104  @param  MacAddress     The resoluted MAC address if the resolution is successful.
105                         The value is undefined if resolution fails.
106
107  @retval TRUE           The resolution is successful.
108  @retval FALSE          Otherwise.
109
110**/
111BOOLEAN
112FindInArpCache (
113  IN  EFI_PXE_BASE_CODE_MODE    *PxeBcMode,
114  IN  EFI_IPv4_ADDRESS          *Ip4Addr,
115  OUT EFI_MAC_ADDRESS           *MacAddress
116  )
117{
118  UINT32                  Index;
119
120  for (Index = 0; Index < PxeBcMode->ArpCacheEntries; Index ++) {
121    if (EFI_IP4_EQUAL (&PxeBcMode->ArpCache[Index].IpAddr.v4, Ip4Addr)) {
122      CopyMem (
123        MacAddress,
124        &PxeBcMode->ArpCache[Index].MacAddr,
125        sizeof (EFI_MAC_ADDRESS)
126        );
127      return TRUE;
128    }
129  }
130
131  return FALSE;
132}
133
134/**
135  Notify function for the ICMP receive token, used to process
136  the received ICMP packets.
137
138  @param  Context               The PXEBC private data.
139
140**/
141VOID
142EFIAPI
143IcmpErrorListenHandlerDpc (
144  IN VOID      *Context
145  )
146{
147  EFI_STATUS              Status;
148  EFI_IP4_RECEIVE_DATA    *RxData;
149  EFI_IP4_PROTOCOL        *Ip4;
150  PXEBC_PRIVATE_DATA      *Private;
151  EFI_PXE_BASE_CODE_MODE  *Mode;
152  UINTN                   Index;
153  UINT32                  CopiedLen;
154  UINT8                   *CopiedPointer;
155
156  Private = (PXEBC_PRIVATE_DATA *) Context;
157  Mode    = &Private->Mode;
158  Status  = Private->IcmpErrorRcvToken.Status;
159  RxData  = Private->IcmpErrorRcvToken.Packet.RxData;
160  Ip4     = Private->Ip4;
161
162  if (Status == EFI_ABORTED) {
163    //
164    // The reception is actively aborted by the consumer, directly return.
165    //
166    return;
167  }
168
169  if (EFI_ERROR (Status) || (RxData == NULL)) {
170    //
171    // Only process the normal packets and the icmp error packets, if RxData is NULL
172    // with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although
173    // this should be a bug of the low layer (IP).
174    //
175    goto Resume;
176  }
177
178  if (EFI_IP4 (RxData->Header->SourceAddress) != 0 &&
179      !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {
180    //
181    // The source address is not zero and it's not a unicast IP address, discard it.
182    //
183    goto CleanUp;
184  }
185
186  if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {
187    //
188    // The dest address is not equal to Station Ip address, discard it.
189    //
190    goto CleanUp;
191  }
192
193  //
194  // Constructor ICMP error packet
195  //
196  CopiedLen = 0;
197  CopiedPointer = (UINT8 *) &Mode->IcmpError;
198
199  for (Index = 0; Index < RxData->FragmentCount; Index ++) {
200    CopiedLen += RxData->FragmentTable[Index].FragmentLength;
201    if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
202      CopyMem (
203        CopiedPointer,
204        RxData->FragmentTable[Index].FragmentBuffer,
205        RxData->FragmentTable[Index].FragmentLength
206        );
207    } else {
208      CopyMem (
209        CopiedPointer,
210        RxData->FragmentTable[Index].FragmentBuffer,
211        CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
212        );
213    }
214    CopiedPointer += CopiedLen;
215  }
216
217  goto Resume;
218
219CleanUp:
220  gBS->SignalEvent (RxData->RecycleSignal);
221
222Resume:
223  Ip4->Receive (Ip4, &(Private->IcmpErrorRcvToken));
224}
225
226/**
227  Request IcmpErrorListenHandlerDpc as a DPC at TPL_CALLBACK
228
229  @param  Event                 The event signaled.
230  @param  Context               The context passed in by the event notifier.
231
232**/
233VOID
234EFIAPI
235IcmpErrorListenHandler (
236  IN EFI_EVENT Event,
237  IN VOID      *Context
238  )
239{
240  //
241  // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
242  //
243  QueueDpc (TPL_CALLBACK, IcmpErrorListenHandlerDpc, Context);
244}
245
246/**
247  Enables the use of the PXE Base Code Protocol functions.
248
249  This function enables the use of the PXE Base Code Protocol functions. If the
250  Started field of the EFI_PXE_BASE_CODE_MODE structure is already TRUE, then
251  EFI_ALREADY_STARTED will be returned. If UseIpv6 is TRUE, then IPv6 formatted
252  addresses will be used in this session. If UseIpv6 is FALSE, then IPv4 formatted
253  addresses will be used in this session. If UseIpv6 is TRUE, and the Ipv6Supported
254  field of the EFI_PXE_BASE_CODE_MODE structure is FALSE, then EFI_UNSUPPORTED will
255  be returned. If there is not enough memory or other resources to start the PXE
256  Base Code Protocol, then EFI_OUT_OF_RESOURCES will be returned. Otherwise, the
257  PXE Base Code Protocol will be started, and all of the fields of the EFI_PXE_BASE_CODE_MODE
258  structure will be initialized as follows:
259    StartedSet to TRUE.
260    Ipv6SupportedUnchanged.
261    Ipv6AvailableUnchanged.
262    UsingIpv6Set to UseIpv6.
263    BisSupportedUnchanged.
264    BisDetectedUnchanged.
265    AutoArpSet to TRUE.
266    SendGUIDSet to FALSE.
267    TTLSet to DEFAULT_TTL.
268    ToSSet to DEFAULT_ToS.
269    DhcpCompletedSet to FALSE.
270    ProxyOfferReceivedSet to FALSE.
271    StationIpSet to an address of all zeros.
272    SubnetMaskSet to a subnet mask of all zeros.
273    DhcpDiscoverZero-filled.
274    DhcpAckZero-filled.
275    ProxyOfferZero-filled.
276    PxeDiscoverValidSet to FALSE.
277    PxeDiscoverZero-filled.
278    PxeReplyValidSet to FALSE.
279    PxeReplyZero-filled.
280    PxeBisReplyValidSet to FALSE.
281    PxeBisReplyZero-filled.
282    IpFilterSet the Filters field to 0 and the IpCnt field to 0.
283    ArpCacheEntriesSet to 0.
284    ArpCacheZero-filled.
285    RouteTableEntriesSet to 0.
286    RouteTableZero-filled.
287    IcmpErrorReceivedSet to FALSE.
288    IcmpErrorZero-filled.
289    TftpErroReceivedSet to FALSE.
290    TftpErrorZero-filled.
291    MakeCallbacksSet to TRUE if the PXE Base Code Callback Protocol is available.
292    Set to FALSE if the PXE Base Code Callback Protocol is not available.
293
294  @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
295  @param  UseIpv6               Specifies the type of IP addresses that are to be used during the session
296                                that is being started. Set to TRUE for IPv6 addresses, and FALSE for
297                                IPv4 addresses.
298
299  @retval EFI_SUCCESS           The PXE Base Code Protocol was started.
300  @retval EFI_DEVICE_ERROR      The network device encountered an error during this oper
301  @retval EFI_UNSUPPORTED       UseIpv6 is TRUE, but the Ipv6Supported field of the
302                                EFI_PXE_BASE_CODE_MODE structure is FALSE.
303  @retval EFI_ALREADY_STARTED   The PXE Base Code Protocol is already in the started state.
304  @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
305                                EFI_PXE_BASE_CODE_PROTOCOL structure.
306  @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory or other resources to start the
307                                PXE Base Code Protocol.
308
309**/
310EFI_STATUS
311EFIAPI
312EfiPxeBcStart (
313  IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
314  IN BOOLEAN                          UseIpv6
315  )
316{
317  PXEBC_PRIVATE_DATA      *Private;
318  EFI_PXE_BASE_CODE_MODE  *Mode;
319  EFI_STATUS              Status;
320
321  if (This == NULL) {
322    return EFI_INVALID_PARAMETER;
323  }
324
325  Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
326  Mode    = Private->PxeBc.Mode;
327
328  if (Mode->Started) {
329    return EFI_ALREADY_STARTED;
330  }
331
332  if (UseIpv6) {
333    //
334    // IPv6 is not supported now.
335    //
336    return EFI_UNSUPPORTED;
337  }
338
339  //
340  // Configure the udp4 instance to let it receive data
341  //
342  Status = Private->Udp4Read->Configure (
343                               Private->Udp4Read,
344                               &Private->Udp4CfgData
345                               );
346  if (EFI_ERROR (Status)) {
347    return Status;
348  }
349
350
351  //
352  // Configure block size for TFTP as a default value to handle all link layers.
353  //
354  Private->BlockSize   = (UINTN) (MIN (Private->Ip4MaxPacketSize, PXEBC_DEFAULT_PACKET_SIZE) -
355                           PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE);
356  //
357  // If PcdTftpBlockSize is set to non-zero, override the default value.
358  //
359  if (PcdGet64 (PcdTftpBlockSize) != 0) {
360    Private->BlockSize   = (UINTN) PcdGet64 (PcdTftpBlockSize);
361  }
362
363  Private->AddressIsOk = FALSE;
364
365  ZeroMem (Mode, sizeof (EFI_PXE_BASE_CODE_MODE));
366
367  Mode->Started = TRUE;
368  Mode->TTL     = DEFAULT_TTL;
369  Mode->ToS     = DEFAULT_ToS;
370  Mode->AutoArp = TRUE;
371
372  //
373  // Create the event for Arp Cache checking.
374  //
375  Status = gBS->CreateEvent (
376                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
377                  TPL_CALLBACK,
378                  ArpCacheUpdateTimeout,
379                  This,
380                  &Private->GetArpCacheEvent
381                  );
382  if (EFI_ERROR (Status)) {
383    goto ON_EXIT;
384  }
385
386  //
387  // Start the timeout timer event.
388  //
389  Status = gBS->SetTimer (
390                  Private->GetArpCacheEvent,
391                  TimerPeriodic,
392                  TICKS_PER_SECOND
393                  );
394
395  if (EFI_ERROR (Status)) {
396    goto ON_EXIT;
397  }
398
399  //
400  // Create ICMP error receiving event
401  //
402  Status = gBS->CreateEvent (
403                  EVT_NOTIFY_SIGNAL,
404                  TPL_NOTIFY,
405                  IcmpErrorListenHandler,
406                  Private,
407                  &(Private->IcmpErrorRcvToken.Event)
408                  );
409  if (EFI_ERROR (Status)) {
410    goto ON_EXIT;
411  }
412
413  //
414  //DHCP4 service allows only one of its children to be configured in
415  //the active state, If the DHCP4 D.O.R.A started by IP4 auto
416  //configuration and has not been completed, the Dhcp4 state machine
417  //will not be in the right state for the PXE to start a new round D.O.R.A.
418  //so we need to switch it's policy to static.
419  //
420  Status = PxeBcSetIp4Policy (Private);
421  if (EFI_ERROR (Status)) {
422    goto ON_EXIT;
423  }
424
425  Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4ConfigData);
426  if (EFI_ERROR (Status)) {
427    goto ON_EXIT;
428  }
429
430  //
431  // start to listen incoming packet
432  //
433  Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpErrorRcvToken);
434  if (!EFI_ERROR (Status)) {
435    return Status;
436  }
437
438ON_EXIT:
439  Private->Ip4->Configure (Private->Ip4, NULL);
440
441  if (Private->IcmpErrorRcvToken.Event != NULL) {
442    gBS->CloseEvent (Private->IcmpErrorRcvToken.Event);
443  }
444
445  if (Private->GetArpCacheEvent != NULL) {
446    gBS->SetTimer (Private->GetArpCacheEvent, TimerCancel, 0);
447    gBS->CloseEvent (Private->GetArpCacheEvent);
448  }
449
450  Mode->Started = FALSE;
451  Mode->TTL     = 0;
452  Mode->ToS     = 0;
453  Mode->AutoArp = FALSE;
454
455  return Status;
456}
457
458
459/**
460  Disables the use of the PXE Base Code Protocol functions.
461
462  This function stops all activity on the network device. All the resources allocated
463  in Start() are released, the Started field of the EFI_PXE_BASE_CODE_MODE structure is
464  set to FALSE and EFI_SUCCESS is returned. If the Started field of the EFI_PXE_BASE_CODE_MODE
465  structure is already FALSE, then EFI_NOT_STARTED will be returned.
466
467  @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
468
469  @retval EFI_SUCCESS           The PXE Base Code Protocol was stopped.
470  @retval EFI_NOT_STARTED       The PXE Base Code Protocol is already in the stopped state.
471  @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
472                                EFI_PXE_BASE_CODE_PROTOCOL structure.
473  @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
474
475**/
476EFI_STATUS
477EFIAPI
478EfiPxeBcStop (
479  IN EFI_PXE_BASE_CODE_PROTOCOL       *This
480  )
481{
482  PXEBC_PRIVATE_DATA      *Private;
483  EFI_PXE_BASE_CODE_MODE  *Mode;
484
485  if (This == NULL) {
486    return EFI_INVALID_PARAMETER;
487  }
488
489  Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
490  Mode    = Private->PxeBc.Mode;
491
492  if (!Mode->Started) {
493    return EFI_NOT_STARTED;
494  }
495
496  Private->Ip4->Cancel (Private->Ip4, NULL);
497  //
498  // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
499  // events.
500  //
501  DispatchDpc ();
502
503  Private->Ip4->Configure (Private->Ip4, NULL);
504
505  //
506  // Close the ICMP error receiving event.
507  //
508  gBS->CloseEvent (Private->IcmpErrorRcvToken.Event);
509
510  //
511  // Cancel the TimeoutEvent timer.
512  //
513  gBS->SetTimer (Private->GetArpCacheEvent, TimerCancel, 0);
514
515  //
516  // Close the TimeoutEvent event.
517  //
518  gBS->CloseEvent (Private->GetArpCacheEvent);
519
520  Mode->Started = FALSE;
521
522  Private->CurrentUdpSrcPort = 0;
523  Private->Udp4Write->Configure (Private->Udp4Write, NULL);
524  Private->Udp4Read->Groups (Private->Udp4Read, FALSE, NULL);
525  Private->Udp4Read->Configure (Private->Udp4Read, NULL);
526
527  Private->Dhcp4->Stop (Private->Dhcp4);
528  Private->Dhcp4->Configure (Private->Dhcp4, NULL);
529
530  Private->FileSize = 0;
531
532  return EFI_SUCCESS;
533}
534
535
536/**
537  Attempts to complete a DHCPv4 D.O.R.A. (discover / offer / request / acknowledge) or DHCPv6
538  S.A.R.R (solicit / advertise / request / reply) sequence.
539
540  This function attempts to complete the DHCP sequence. If this sequence is completed,
541  then EFI_SUCCESS is returned, and the DhcpCompleted, ProxyOfferReceived, StationIp,
542  SubnetMask, DhcpDiscover, DhcpAck, and ProxyOffer fields of the EFI_PXE_BASE_CODE_MODE
543  structure are filled in.
544  If SortOffers is TRUE, then the cached DHCP offer packets will be sorted before
545  they are tried. If SortOffers is FALSE, then the cached DHCP offer packets will
546  be tried in the order in which they are received. Please see the Preboot Execution
547  Environment (PXE) Specification for additional details on the implementation of DHCP.
548  This function can take at least 31 seconds to timeout and return control to the
549  caller. If the DHCP sequence does not complete, then EFI_TIMEOUT will be returned.
550  If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
551  then the DHCP sequence will be stopped and EFI_ABORTED will be returned.
552
553  @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
554  @param  SortOffers            TRUE if the offers received should be sorted. Set to FALSE to try the
555                                offers in the order that they are received.
556
557  @retval EFI_SUCCESS           Valid DHCP has completed.
558  @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
559  @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
560                                EFI_PXE_BASE_CODE_PROTOCOL structure.
561  @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
562  @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory to complete the DHCP Protocol.
563  @retval EFI_ABORTED           The callback function aborted the DHCP Protocol.
564  @retval EFI_TIMEOUT           The DHCP Protocol timed out.
565  @retval EFI_ICMP_ERROR        An ICMP error packet was received during the DHCP session.
566  @retval EFI_NO_RESPONSE       Valid PXE offer was not received.
567
568**/
569EFI_STATUS
570EFIAPI
571EfiPxeBcDhcp (
572  IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
573  IN BOOLEAN                          SortOffers
574  )
575{
576  PXEBC_PRIVATE_DATA           *Private;
577  EFI_PXE_BASE_CODE_MODE       *Mode;
578  EFI_DHCP4_PROTOCOL           *Dhcp4;
579  EFI_DHCP4_CONFIG_DATA        Dhcp4CfgData;
580  EFI_DHCP4_MODE_DATA          Dhcp4Mode;
581  EFI_DHCP4_PACKET_OPTION      *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];
582  UINT32                       OptCount;
583  EFI_STATUS                   Status;
584  EFI_ARP_CONFIG_DATA          ArpConfigData;
585  EFI_PXE_BASE_CODE_IP_FILTER  IpFilter;
586
587  if (This == NULL) {
588    return EFI_INVALID_PARAMETER;
589  }
590
591  Status              = EFI_SUCCESS;
592  Private             = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
593  Mode                = Private->PxeBc.Mode;
594  Dhcp4               = Private->Dhcp4;
595  Private->Function   = EFI_PXE_BASE_CODE_FUNCTION_DHCP;
596  Private->SortOffers = SortOffers;
597
598  if (!Mode->Started) {
599    return EFI_NOT_STARTED;
600  }
601
602  Mode->IcmpErrorReceived = FALSE;
603
604  //
605  // Stop Udp4Read instance
606  //
607  Private->Udp4Read->Configure (Private->Udp4Read, NULL);
608
609  //
610  // Initialize the DHCP options and build the option list
611  //
612  OptCount = PxeBcBuildDhcpOptions (Private, OptList, TRUE);
613
614  //
615  // Set the DHCP4 config data.
616  // The four discovery timeouts are 4, 8, 16, 32 seconds respectively.
617  //
618  ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
619  Dhcp4CfgData.OptionCount      = OptCount;
620  Dhcp4CfgData.OptionList       = OptList;
621  Dhcp4CfgData.Dhcp4Callback    = PxeBcDhcpCallBack;
622  Dhcp4CfgData.CallbackContext  = Private;
623  Dhcp4CfgData.DiscoverTryCount = 4;
624  Dhcp4CfgData.DiscoverTimeout  = mPxeDhcpTimeout;
625
626  Status          = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
627  if (EFI_ERROR (Status)) {
628    goto ON_EXIT;
629  }
630
631  //
632  // Zero those arrays to record the varies numbers of DHCP OFFERS.
633  //
634  Private->GotProxyOffer = FALSE;
635  Private->NumOffers     = 0;
636  Private->BootpIndex    = 0;
637  ZeroMem (Private->ServerCount, sizeof (Private->ServerCount));
638  ZeroMem (Private->ProxyIndex, sizeof (Private->ProxyIndex));
639
640  Status = Dhcp4->Start (Dhcp4, NULL);
641  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
642    if (Status == EFI_ICMP_ERROR) {
643      Mode->IcmpErrorReceived = TRUE;
644    }
645    goto ON_EXIT;
646  }
647
648  Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
649  if (EFI_ERROR (Status)) {
650    goto ON_EXIT;
651  }
652
653  ASSERT (Dhcp4Mode.State == Dhcp4Bound);
654
655  CopyMem (&Private->StationIp, &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
656  CopyMem (&Private->SubnetMask, &Dhcp4Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
657  CopyMem (&Private->GatewayIp, &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
658
659  CopyMem (&Mode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
660  CopyMem (&Mode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
661
662  //
663  // Check the selected offer to see whether BINL is required, if no or BINL is
664  // finished, set the various Mode members.
665  //
666  Status = PxeBcCheckSelectedOffer (Private);
667
668ON_EXIT:
669  if (EFI_ERROR (Status)) {
670    Dhcp4->Stop (Dhcp4);
671    Dhcp4->Configure (Dhcp4, NULL);
672  } else {
673    //
674    // Remove the previously configured option list and callback function
675    //
676    ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
677    Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
678
679    Private->AddressIsOk = TRUE;
680
681    if (!Mode->UsingIpv6) {
682      //
683      // If in IPv4 mode, configure the corresponding ARP with this new
684      // station IP address.
685      //
686      ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));
687
688      ArpConfigData.SwAddressType   = 0x0800;
689      ArpConfigData.SwAddressLength = (UINT8) sizeof (EFI_IPv4_ADDRESS);
690      ArpConfigData.StationAddress  = &Private->StationIp.v4;
691
692      Private->Arp->Configure (Private->Arp, NULL);
693      Private->Arp->Configure (Private->Arp, &ArpConfigData);
694
695      //
696      // Updated the route table. Fill the first entry.
697      //
698      Mode->RouteTableEntries                = 1;
699      Mode->RouteTable[0].IpAddr.Addr[0]     = Private->StationIp.Addr[0] & Private->SubnetMask.Addr[0];
700      Mode->RouteTable[0].SubnetMask.Addr[0] = Private->SubnetMask.Addr[0];
701      Mode->RouteTable[0].GwAddr.Addr[0]     = 0;
702
703      //
704      // Create the default route entry if there is a default router.
705      //
706      if (Private->GatewayIp.Addr[0] != 0) {
707        Mode->RouteTableEntries                = 2;
708        Mode->RouteTable[1].IpAddr.Addr[0]     = 0;
709        Mode->RouteTable[1].SubnetMask.Addr[0] = 0;
710        Mode->RouteTable[1].GwAddr.Addr[0]     = Private->GatewayIp.Addr[0];
711      }
712
713      //
714      // Flush new station IP address into Udp4CfgData and Ip4ConfigData
715      //
716      CopyMem (&Private->Udp4CfgData.StationAddress, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
717      CopyMem (&Private->Udp4CfgData.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
718      CopyMem (&Private->Ip4ConfigData.StationAddress, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
719      CopyMem (&Private->Ip4ConfigData.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
720
721      //
722      // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
723      //
724      Private->Ip4->Cancel (Private->Ip4, &Private->IcmpErrorRcvToken);
725      Private->Ip4->Configure (Private->Ip4, NULL);
726
727      Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4ConfigData);
728      if (EFI_ERROR (Status)) {
729        goto ON_EXIT;
730      }
731
732      Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpErrorRcvToken);
733      if (EFI_ERROR (Status)) {
734        goto ON_EXIT;
735      }
736    }
737  }
738
739  Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
740
741  //
742  // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
743  // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
744  //
745  ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
746  IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
747  This->SetIpFilter (This, &IpFilter);
748
749  return Status;
750}
751
752
753/**
754  Attempts to complete the PXE Boot Server and/or boot image discovery sequence.
755
756  This function attempts to complete the PXE Boot Server and/or boot image discovery
757  sequence. If this sequence is completed, then EFI_SUCCESS is returned, and the
758  PxeDiscoverValid, PxeDiscover, PxeReplyReceived, and PxeReply fields of the
759  EFI_PXE_BASE_CODE_MODE structure are filled in. If UseBis is TRUE, then the
760  PxeBisReplyReceived and PxeBisReply fields of the EFI_PXE_BASE_CODE_MODE structure
761  will also be filled in. If UseBis is FALSE, then PxeBisReplyValid will be set to FALSE.
762  In the structure referenced by parameter Info, the PXE Boot Server list, SrvList[],
763  has two uses: It is the Boot Server IP address list used for unicast discovery
764  (if the UseUCast field is TRUE), and it is the list used for Boot Server verification
765  (if the MustUseList field is TRUE). Also, if the MustUseList field in that structure
766  is TRUE and the AcceptAnyResponse field in the SrvList[] array is TRUE, any Boot
767  Server reply of that type will be accepted. If the AcceptAnyResponse field is
768  FALSE, only responses from Boot Servers with matching IP addresses will be accepted.
769  This function can take at least 10 seconds to timeout and return control to the
770  caller. If the Discovery sequence does not complete, then EFI_TIMEOUT will be
771  returned. Please see the Preboot Execution Environment (PXE) Specification for
772  additional details on the implementation of the Discovery sequence.
773  If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
774  then the Discovery sequence is stopped and EFI_ABORTED will be returned.
775
776  @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
777  @param  Type                  The type of bootstrap to perform.
778  @param  Layer                 Pointer to the boot server layer number to discover, which must be
779                                PXE_BOOT_LAYER_INITIAL when a new server type is being
780                                discovered.
781  @param  UseBis                TRUE if Boot Integrity Services are to be used. FALSE otherwise.
782  @param  Info                  Pointer to a data structure that contains additional information on the
783                                type of discovery operation that is to be performed.
784
785  @retval EFI_SUCCESS           The Discovery sequence has been completed.
786  @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
787  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
788  @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
789  @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory to complete Discovery.
790  @retval EFI_ABORTED           The callback function aborted the Discovery sequence.
791  @retval EFI_TIMEOUT           The Discovery sequence timed out.
792  @retval EFI_ICMP_ERROR        An ICMP error packet was received during the PXE discovery
793                                session.
794
795**/
796EFI_STATUS
797EFIAPI
798EfiPxeBcDiscover (
799  IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
800  IN UINT16                           Type,
801  IN UINT16                           *Layer,
802  IN BOOLEAN                          UseBis,
803  IN EFI_PXE_BASE_CODE_DISCOVER_INFO  *Info   OPTIONAL
804  )
805{
806  PXEBC_PRIVATE_DATA              *Private;
807  EFI_PXE_BASE_CODE_MODE          *Mode;
808  EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;
809  EFI_PXE_BASE_CODE_DISCOVER_INFO *CreatedInfo;
810  EFI_PXE_BASE_CODE_SRVLIST       *SrvList;
811  EFI_PXE_BASE_CODE_SRVLIST       DefaultSrvList;
812  PXEBC_CACHED_DHCP4_PACKET       *Packet;
813  PXEBC_VENDOR_OPTION             *VendorOpt;
814  UINT16                          Index;
815  EFI_STATUS                      Status;
816  PXEBC_BOOT_SVR_ENTRY            *BootSvrEntry;
817  EFI_PXE_BASE_CODE_IP_FILTER     IpFilter;
818
819  if (This == NULL) {
820    return EFI_INVALID_PARAMETER;
821  }
822
823  Private           = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
824  Mode              = Private->PxeBc.Mode;
825  BootSvrEntry      = NULL;
826  SrvList           = NULL;
827  CreatedInfo       = NULL;
828  Status            = EFI_DEVICE_ERROR;
829  Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;
830
831  if (!Private->AddressIsOk) {
832    return EFI_INVALID_PARAMETER;
833  }
834
835  if (!Mode->Started) {
836    return EFI_NOT_STARTED;
837  }
838
839  //
840  // Stop Udp4Read instance
841  //
842  Private->Udp4Read->Configure (Private->Udp4Read, NULL);
843
844  Mode->IcmpErrorReceived = FALSE;
845
846  //
847  // If layer isn't EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL,
848  //   use the previous setting;
849  // If info isn't offered,
850  //   use the cached DhcpAck and ProxyOffer packets.
851  //
852  ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));
853  if (*Layer != EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) {
854
855    if (!Mode->PxeDiscoverValid || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {
856
857      Status = EFI_INVALID_PARAMETER;
858      goto ON_EXIT;
859    }
860
861    DefaultInfo.IpCnt                 = 1;
862    DefaultInfo.UseUCast              = TRUE;
863
864    DefaultSrvList.Type               = Type;
865    DefaultSrvList.AcceptAnyResponse  = FALSE;
866    DefaultSrvList.IpAddr.Addr[0]     = Private->ServerIp.Addr[0];
867
868    SrvList = &DefaultSrvList;
869    Info = &DefaultInfo;
870  } else if (Info == NULL) {
871    //
872    // Create info by the cached packet before
873    //
874    Packet    = (Mode->ProxyOfferReceived) ? &Private->ProxyOffer : &Private->Dhcp4Ack;
875    VendorOpt = &Packet->PxeVendorOption;
876
877    if (!Mode->DhcpAckReceived || !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt->BitMap)) {
878      //
879      // Address is not acquired or no discovery options.
880      //
881      Status = EFI_INVALID_PARAMETER;
882      goto ON_EXIT;
883    }
884
885    DefaultInfo.UseMCast    = (BOOLEAN)!IS_DISABLE_MCAST_DISCOVER (VendorOpt->DiscoverCtrl);
886    DefaultInfo.UseBCast    = (BOOLEAN)!IS_DISABLE_BCAST_DISCOVER (VendorOpt->DiscoverCtrl);
887    DefaultInfo.MustUseList = (BOOLEAN) IS_ENABLE_USE_SERVER_LIST (VendorOpt->DiscoverCtrl);
888    DefaultInfo.UseUCast    = DefaultInfo.MustUseList;
889
890    if (DefaultInfo.UseMCast) {
891      //
892      // Get the multicast discover ip address from vendor option.
893      //
894      CopyMem (
895        &DefaultInfo.ServerMCastIp.Addr,
896        &VendorOpt->DiscoverMcastIp,
897        sizeof (EFI_IPv4_ADDRESS)
898        );
899    }
900
901    DefaultInfo.IpCnt = 0;
902    Info    = &DefaultInfo;
903    SrvList = Info->SrvList;
904
905    if (DefaultInfo.MustUseList) {
906      BootSvrEntry  = VendorOpt->BootSvr;
907      Status        = EFI_INVALID_PARAMETER;
908
909      while (((UINT8) (BootSvrEntry - VendorOpt->BootSvr)) < VendorOpt->BootSvrLen) {
910
911        if (BootSvrEntry->Type == HTONS (Type)) {
912          Status = EFI_SUCCESS;
913          break;
914        }
915
916        BootSvrEntry = GET_NEXT_BOOT_SVR_ENTRY (BootSvrEntry);
917      }
918
919      if (EFI_ERROR (Status)) {
920        goto ON_EXIT;
921      }
922
923      DefaultInfo.IpCnt = BootSvrEntry->IpCnt;
924
925      if (DefaultInfo.IpCnt >= 1) {
926        CreatedInfo = AllocatePool (sizeof (DefaultInfo) + (DefaultInfo.IpCnt - 1) * sizeof (*SrvList));
927        if (CreatedInfo == NULL) {
928          Status = EFI_OUT_OF_RESOURCES;
929          goto ON_EXIT;
930
931        }
932
933        CopyMem (CreatedInfo, &DefaultInfo, sizeof (DefaultInfo));
934        Info    = CreatedInfo;
935        SrvList = Info->SrvList;
936      }
937
938      for (Index = 0; Index < DefaultInfo.IpCnt; Index++) {
939        CopyMem (&SrvList[Index].IpAddr, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));
940        SrvList[Index].AcceptAnyResponse   = FALSE;
941        SrvList[Index].Type                = BootSvrEntry->Type;
942      }
943    }
944
945  } else {
946
947    SrvList = Info->SrvList;
948
949    if (!SrvList[0].AcceptAnyResponse) {
950
951      for (Index = 1; Index < Info->IpCnt; Index++) {
952        if (SrvList[Index].AcceptAnyResponse) {
953          break;
954        }
955      }
956
957      if (Index != Info->IpCnt) {
958        Status = EFI_INVALID_PARAMETER;
959        goto ON_EXIT;
960      }
961    }
962  }
963
964  if ((!Info->UseUCast && !Info->UseBCast && !Info->UseMCast) || (Info->MustUseList && Info->IpCnt == 0)) {
965
966    Status = EFI_INVALID_PARAMETER;
967    goto ON_EXIT;
968  }
969  //
970  // Execute discover by UniCast/BroadCast/MultiCast
971  //
972  if (Info->UseUCast) {
973
974    for (Index = 0; Index < Info->IpCnt; Index++) {
975
976      if (BootSvrEntry == NULL) {
977        Private->ServerIp.Addr[0] = SrvList[Index].IpAddr.Addr[0];
978      } else {
979        CopyMem (
980          &Private->ServerIp,
981          &BootSvrEntry->IpAddr[Index],
982          sizeof (EFI_IPv4_ADDRESS)
983          );
984      }
985
986      Status = PxeBcDiscvBootService (
987                Private,
988                Type,
989                Layer,
990                UseBis,
991                &SrvList[Index].IpAddr,
992                0,
993                NULL,
994                TRUE,
995                &Private->PxeReply.Packet.Ack
996                );
997      if (!EFI_ERROR (Status)) {
998        break;
999      }
1000    }
1001
1002  } else if (Info->UseMCast) {
1003
1004    Status = PxeBcDiscvBootService (
1005              Private,
1006              Type,
1007              Layer,
1008              UseBis,
1009              &Info->ServerMCastIp,
1010              0,
1011              NULL,
1012              TRUE,
1013              &Private->PxeReply.Packet.Ack
1014              );
1015
1016  } else if (Info->UseBCast) {
1017
1018    Status = PxeBcDiscvBootService (
1019              Private,
1020              Type,
1021              Layer,
1022              UseBis,
1023              NULL,
1024              Info->IpCnt,
1025              SrvList,
1026              TRUE,
1027              &Private->PxeReply.Packet.Ack
1028              );
1029  }
1030
1031  if (EFI_ERROR (Status) || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {
1032    if (Status == EFI_ICMP_ERROR) {
1033      Mode->IcmpErrorReceived = TRUE;
1034    } else {
1035      Status = EFI_DEVICE_ERROR;
1036    }
1037    goto ON_EXIT;
1038  } else {
1039    PxeBcParseCachedDhcpPacket (&Private->PxeReply);
1040  }
1041
1042  if (Mode->PxeBisReplyReceived) {
1043    CopyMem (
1044      &Private->ServerIp,
1045      &Mode->PxeReply.Dhcpv4.BootpSiAddr,
1046      sizeof (EFI_IPv4_ADDRESS)
1047      );
1048  }
1049
1050  if (CreatedInfo != NULL) {
1051    FreePool (CreatedInfo);
1052  }
1053
1054ON_EXIT:
1055
1056  Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
1057
1058  //
1059  // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
1060  // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
1061  //
1062  ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
1063  IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
1064  This->SetIpFilter (This, &IpFilter);
1065
1066  return Status;
1067}
1068
1069
1070/**
1071  Used to perform TFTP and MTFTP services.
1072
1073  This function is used to perform TFTP and MTFTP services. This includes the
1074  TFTP operations to get the size of a file, read a directory, read a file, and
1075  write a file. It also includes the MTFTP operations to get the size of a file,
1076  read a directory, and read a file. The type of operation is specified by Operation.
1077  If the callback function that is invoked during the TFTP/MTFTP operation does
1078  not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED will
1079  be returned.
1080  For read operations, the return data will be placed in the buffer specified by
1081  BufferPtr. If BufferSize is too small to contain the entire downloaded file,
1082  then EFI_BUFFER_TOO_SMALL will be returned and BufferSize will be set to zero
1083  or the size of the requested file (the size of the requested file is only returned
1084  if the TFTP server supports TFTP options). If BufferSize is large enough for the
1085  read operation, then BufferSize will be set to the size of the downloaded file,
1086  and EFI_SUCCESS will be returned. Applications using the PxeBc.Mtftp() services
1087  should use the get-file-size operations to determine the size of the downloaded
1088  file prior to using the read-file operations-especially when downloading large
1089  (greater than 64 MB) files-instead of making two calls to the read-file operation.
1090  Following this recommendation will save time if the file is larger than expected
1091  and the TFTP server does not support TFTP option extensions. Without TFTP option
1092  extension support, the client has to download the entire file, counting and discarding
1093  the received packets, to determine the file size.
1094  For write operations, the data to be sent is in the buffer specified by BufferPtr.
1095  BufferSize specifies the number of bytes to send. If the write operation completes
1096  successfully, then EFI_SUCCESS will be returned.
1097  For TFTP "get file size" operations, the size of the requested file or directory
1098  is returned in BufferSize, and EFI_SUCCESS will be returned. If the TFTP server
1099  does not support options, the file will be downloaded into a bit bucket and the
1100  length of the downloaded file will be returned. For MTFTP "get file size" operations,
1101  if the MTFTP server does not support the "get file size" option, EFI_UNSUPPORTED
1102  will be returned.
1103  This function can take up to 10 seconds to timeout and return control to the caller.
1104  If the TFTP sequence does not complete, EFI_TIMEOUT will be returned.
1105  If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
1106  then the TFTP sequence is stopped and EFI_ABORTED will be returned.
1107  The format of the data returned from a TFTP read directory operation is a null-terminated
1108  filename followed by a null-terminated information string, of the form
1109  "size year-month-day hour:minute:second" (i.e. %d %d-%d-%d %d:%d:%f - note that
1110  the seconds field can be a decimal number), where the date and time are UTC. For
1111  an MTFTP read directory command, there is additionally a null-terminated multicast
1112  IP address preceding the filename of the form %d.%d.%d.%d for IP v4. The final
1113  entry is itself null-terminated, so that the final information string is terminated
1114  with two null octets.
1115
1116  @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
1117  @param  Operation             The type of operation to perform.
1118  @param  BufferPtr             A pointer to the data buffer.
1119  @param  Overwrite             Only used on write file operations. TRUE if a file on a remote server can
1120                                be overwritten.
1121  @param  BufferSize            For get-file-size operations, *BufferSize returns the size of the
1122                                requested file.
1123  @param  BlockSize             The requested block size to be used during a TFTP transfer.
1124  @param  ServerIp              The TFTP / MTFTP server IP address.
1125  @param  Filename              A Null-terminated ASCII string that specifies a directory name or a file
1126                                name.
1127  @param  Info                  Pointer to the MTFTP information.
1128  @param  DontUseBuffer         Set to FALSE for normal TFTP and MTFTP read file operation.
1129
1130  @retval EFI_SUCCESS           The TFTP/MTFTP operation was completed.
1131  @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
1132  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1133  @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
1134  @retval EFI_BUFFER_TOO_SMALL  The buffer is not large enough to complete the read operation.
1135  @retval EFI_ABORTED           The callback function aborted the TFTP/MTFTP operation.
1136  @retval EFI_TIMEOUT           The TFTP/MTFTP operation timed out.
1137  @retval EFI_ICMP_ERROR        An ICMP error packet was received during the MTFTP session.
1138  @retval EFI_TFTP_ERROR        A TFTP error packet was received during the MTFTP session.
1139
1140**/
1141EFI_STATUS
1142EFIAPI
1143EfiPxeBcMtftp (
1144  IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
1145  IN EFI_PXE_BASE_CODE_TFTP_OPCODE    Operation,
1146  IN OUT VOID                         *BufferPtr,
1147  IN BOOLEAN                          Overwrite,
1148  IN OUT UINT64                       *BufferSize,
1149  IN UINTN                            *BlockSize    OPTIONAL,
1150  IN EFI_IP_ADDRESS                   *ServerIp,
1151  IN UINT8                            *Filename,
1152  IN EFI_PXE_BASE_CODE_MTFTP_INFO     *Info         OPTIONAL,
1153  IN BOOLEAN                          DontUseBuffer
1154  )
1155{
1156  PXEBC_PRIVATE_DATA           *Private;
1157  EFI_MTFTP4_CONFIG_DATA       Mtftp4Config;
1158  EFI_STATUS                   Status;
1159  EFI_PXE_BASE_CODE_MODE       *Mode;
1160  EFI_MAC_ADDRESS              TempMacAddr;
1161  EFI_PXE_BASE_CODE_IP_FILTER  IpFilter;
1162
1163  if ((This == NULL)                                                          ||
1164      (Filename == NULL)                                                      ||
1165      (BufferSize == NULL)                                                    ||
1166      ((ServerIp == NULL) || !NetIp4IsUnicast (NTOHL (ServerIp->Addr[0]), 0)) ||
1167      ((BufferPtr == NULL) && DontUseBuffer)                                  ||
1168      ((BlockSize != NULL) && (*BlockSize < 512))) {
1169
1170    return EFI_INVALID_PARAMETER;
1171  }
1172
1173  Status  = EFI_DEVICE_ERROR;
1174  Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1175  Mode    = &Private->Mode;
1176
1177  if (!Mode->AutoArp) {
1178    //
1179    // If AutoArp is set false, check arp cache
1180    //
1181    UpdateArpCache (This);
1182    if (!FindInArpCache (Mode, &ServerIp->v4, &TempMacAddr)) {
1183      return EFI_DEVICE_ERROR;
1184    }
1185  }
1186
1187  //
1188  // Stop Udp4Read instance
1189  //
1190  Private->Udp4Read->Configure (Private->Udp4Read, NULL);
1191
1192  Mode->TftpErrorReceived = FALSE;
1193  Mode->IcmpErrorReceived = FALSE;
1194
1195  Mtftp4Config.UseDefaultSetting = FALSE;
1196  Mtftp4Config.TimeoutValue      = PXEBC_MTFTP_TIMEOUT;
1197  Mtftp4Config.TryCount          = PXEBC_MTFTP_RETRIES;
1198
1199  CopyMem (
1200    &Mtftp4Config.StationIp,
1201    &Private->StationIp,
1202    sizeof (EFI_IPv4_ADDRESS)
1203    );
1204  CopyMem (
1205    &Mtftp4Config.SubnetMask,
1206    &Private->SubnetMask,
1207    sizeof (EFI_IPv4_ADDRESS)
1208    );
1209  CopyMem (
1210    &Mtftp4Config.GatewayIp,
1211    &Private->GatewayIp,
1212    sizeof (EFI_IPv4_ADDRESS)
1213    );
1214  CopyMem (
1215    &Mtftp4Config.ServerIp,
1216    ServerIp,
1217    sizeof (EFI_IPv4_ADDRESS)
1218    );
1219
1220  switch (Operation) {
1221
1222  case EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE:
1223
1224    Status = PxeBcTftpGetFileSize (
1225              Private,
1226              &Mtftp4Config,
1227              Filename,
1228              BlockSize,
1229              BufferSize
1230              );
1231
1232    break;
1233
1234  case EFI_PXE_BASE_CODE_TFTP_READ_FILE:
1235
1236    Status = PxeBcTftpReadFile (
1237              Private,
1238              &Mtftp4Config,
1239              Filename,
1240              BlockSize,
1241              BufferPtr,
1242              BufferSize,
1243              DontUseBuffer
1244              );
1245
1246    break;
1247
1248  case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:
1249
1250    Status = PxeBcTftpWriteFile (
1251              Private,
1252              &Mtftp4Config,
1253              Filename,
1254              Overwrite,
1255              BlockSize,
1256              BufferPtr,
1257              BufferSize
1258              );
1259
1260    break;
1261
1262  case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:
1263
1264    Status = PxeBcTftpReadDirectory (
1265              Private,
1266              &Mtftp4Config,
1267              Filename,
1268              BlockSize,
1269              BufferPtr,
1270              BufferSize,
1271              DontUseBuffer
1272              );
1273
1274    break;
1275
1276  case EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE:
1277  case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:
1278  case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:
1279    Status = EFI_UNSUPPORTED;
1280    break;
1281
1282  default:
1283
1284    Status = EFI_INVALID_PARAMETER;
1285    break;
1286  }
1287
1288  if (Status == EFI_ICMP_ERROR) {
1289    Mode->IcmpErrorReceived = TRUE;
1290  }
1291
1292  if (EFI_ERROR (Status)) {
1293    goto ON_EXIT;
1294  }
1295
1296ON_EXIT:
1297  Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
1298  //
1299  // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
1300  // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
1301  //
1302  ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
1303  IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
1304  This->SetIpFilter (This, &IpFilter);
1305
1306  return Status;
1307}
1308
1309
1310/**
1311  Writes a UDP packet to the network interface.
1312
1313  This function writes a UDP packet specified by the (optional HeaderPtr and)
1314  BufferPtr parameters to the network interface. The UDP header is automatically
1315  built by this routine. It uses the parameters OpFlags, DestIp, DestPort, GatewayIp,
1316  SrcIp, and SrcPort to build this header. If the packet is successfully built and
1317  transmitted through the network interface, then EFI_SUCCESS will be returned.
1318  If a timeout occurs during the transmission of the packet, then EFI_TIMEOUT will
1319  be returned. If an ICMP error occurs during the transmission of the packet, then
1320  the IcmpErrorReceived field is set to TRUE, the IcmpError field is filled in and
1321  EFI_ICMP_ERROR will be returned. If the Callback Protocol does not return
1322  EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED will be returned.
1323
1324  @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
1325  @param  OpFlags               The UDP operation flags.
1326  @param  DestIp                The destination IP address.
1327  @param  DestPort              The destination UDP port number.
1328  @param  GatewayIp             The gateway IP address.
1329  @param  SrcIp                 The source IP address.
1330  @param  SrcPort               The source UDP port number.
1331  @param  HeaderSize            An optional field which may be set to the length of a header at
1332                                HeaderPtr to be prefixed to the data at BufferPtr.
1333  @param  HeaderPtr             If HeaderSize is not NULL, a pointer to a header to be prefixed to the
1334                                data at BufferPtr.
1335  @param  BufferSize            A pointer to the size of the data at BufferPtr.
1336  @param  BufferPtr             A pointer to the data to be written.
1337
1338  @retval EFI_SUCCESS           The UDP Write operation was completed.
1339  @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
1340  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1341  @retval EFI_BAD_BUFFER_SIZE   The buffer is too long to be transmitted.
1342  @retval EFI_ABORTED           The callback function aborted the UDP Write operation.
1343  @retval EFI_TIMEOUT           The UDP Write operation timed out.
1344  @retval EFI_ICMP_ERROR        An ICMP error packet was received during the UDP write session.
1345
1346**/
1347EFI_STATUS
1348EFIAPI
1349EfiPxeBcUdpWrite (
1350  IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
1351  IN UINT16                           OpFlags,
1352  IN EFI_IP_ADDRESS                   *DestIp,
1353  IN EFI_PXE_BASE_CODE_UDP_PORT       *DestPort,
1354  IN EFI_IP_ADDRESS                   *GatewayIp  OPTIONAL,
1355  IN EFI_IP_ADDRESS                   *SrcIp      OPTIONAL,
1356  IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *SrcPort    OPTIONAL,
1357  IN UINTN                            *HeaderSize OPTIONAL,
1358  IN VOID                             *HeaderPtr  OPTIONAL,
1359  IN UINTN                            *BufferSize,
1360  IN VOID                             *BufferPtr
1361  )
1362{
1363  PXEBC_PRIVATE_DATA        *Private;
1364  EFI_UDP4_PROTOCOL         *Udp4;
1365  EFI_UDP4_COMPLETION_TOKEN Token;
1366  EFI_UDP4_TRANSMIT_DATA    *Udp4TxData;
1367  UINT32                    FragCount;
1368  UINT32                    DataLength;
1369  EFI_UDP4_SESSION_DATA     Udp4Session;
1370  EFI_STATUS                Status;
1371  BOOLEAN                   IsDone;
1372  EFI_PXE_BASE_CODE_MODE    *Mode;
1373  EFI_MAC_ADDRESS           TempMacAddr;
1374
1375  IsDone = FALSE;
1376
1377  if ((This == NULL) || (DestIp == NULL) || (DestPort == NULL)) {
1378    return EFI_INVALID_PARAMETER;
1379  }
1380
1381  if ((GatewayIp != NULL) && !NetIp4IsUnicast (NTOHL (GatewayIp->Addr[0]), 0)) {
1382    //
1383    // Gateway is provided but it's not a unicast IP address.
1384    //
1385    return EFI_INVALID_PARAMETER;
1386  }
1387
1388  if ((HeaderSize != NULL) && ((*HeaderSize == 0) || (HeaderPtr == NULL))) {
1389    //
1390    // The HeaderSize ptr isn't NULL and: 1. the value is zero; or 2. the HeaderPtr
1391    // is NULL.
1392    //
1393    return EFI_INVALID_PARAMETER;
1394  }
1395
1396  if ((BufferSize == NULL) || ((*BufferSize != 0) && (BufferPtr == NULL))) {
1397    return EFI_INVALID_PARAMETER;
1398  }
1399
1400  Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1401  Udp4    = Private->Udp4Write;
1402  Mode    = &Private->Mode;
1403  if (!Mode->Started) {
1404    return EFI_NOT_STARTED;
1405  }
1406
1407  if (!Private->AddressIsOk && (SrcIp == NULL)) {
1408    return EFI_INVALID_PARAMETER;
1409  }
1410
1411  if (!Mode->AutoArp) {
1412    //
1413    // If AutoArp is set false, check arp cache
1414    //
1415    UpdateArpCache (This);
1416    if (!FindInArpCache (Mode, &DestIp->v4, &TempMacAddr)) {
1417      return EFI_DEVICE_ERROR;
1418    }
1419  }
1420
1421  Mode->IcmpErrorReceived = FALSE;
1422
1423  if ((Private->CurrentUdpSrcPort == 0) ||
1424      ((SrcPort != NULL) && (*SrcPort != Private->CurrentUdpSrcPort))) {
1425    //
1426    // Port is changed, (re)configure the Udp4Write instance
1427    //
1428    if (SrcPort != NULL) {
1429      Private->CurrentUdpSrcPort = *SrcPort;
1430    }
1431  }
1432
1433  Status = PxeBcConfigureUdpWriteInstance (
1434             Udp4,
1435             &Private->StationIp.v4,
1436             &Private->SubnetMask.v4,
1437             &Private->GatewayIp.v4,
1438             &Private->CurrentUdpSrcPort
1439             );
1440  if (EFI_ERROR (Status)) {
1441    Private->CurrentUdpSrcPort = 0;
1442    return EFI_INVALID_PARAMETER;
1443  }
1444
1445  ZeroMem (&Token, sizeof (EFI_UDP4_COMPLETION_TOKEN));
1446  ZeroMem (&Udp4Session, sizeof (EFI_UDP4_SESSION_DATA));
1447
1448  CopyMem (&Udp4Session.DestinationAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
1449  Udp4Session.DestinationPort = *DestPort;
1450  if (SrcIp != NULL) {
1451    CopyMem (&Udp4Session.SourceAddress, SrcIp, sizeof (EFI_IPv4_ADDRESS));
1452  }
1453  if (SrcPort != NULL) {
1454    Udp4Session.SourcePort = *SrcPort;
1455  }
1456
1457  FragCount = (HeaderSize != NULL) ? 2 : 1;
1458  Udp4TxData = (EFI_UDP4_TRANSMIT_DATA *) AllocateZeroPool (sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA));
1459  if (Udp4TxData == NULL) {
1460    return EFI_OUT_OF_RESOURCES;
1461  }
1462
1463  Udp4TxData->FragmentCount = FragCount;
1464  Udp4TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;
1465  Udp4TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
1466  DataLength = (UINT32) *BufferSize;
1467
1468  if (FragCount == 2) {
1469
1470    Udp4TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;
1471    Udp4TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
1472    DataLength += (UINT32) *HeaderSize;
1473  }
1474
1475  if (GatewayIp != NULL) {
1476    Udp4TxData->GatewayAddress  = (EFI_IPv4_ADDRESS *) GatewayIp;
1477  }
1478  Udp4TxData->UdpSessionData  = &Udp4Session;
1479  Udp4TxData->DataLength      = DataLength;
1480  Token.Packet.TxData         = Udp4TxData;
1481
1482  Status = gBS->CreateEvent (
1483                  EVT_NOTIFY_SIGNAL,
1484                  TPL_NOTIFY,
1485                  PxeBcCommonNotify,
1486                  &IsDone,
1487                  &Token.Event
1488                  );
1489  if (EFI_ERROR (Status)) {
1490    goto ON_EXIT;
1491  }
1492
1493  Status = Udp4->Transmit (Udp4, &Token);
1494  if (EFI_ERROR (Status)) {
1495    if (Status == EFI_ICMP_ERROR) {
1496      Mode->IcmpErrorReceived = TRUE;
1497    }
1498    goto ON_EXIT;
1499  }
1500
1501  while (!IsDone) {
1502
1503    Udp4->Poll (Udp4);
1504  }
1505
1506  Status = Token.Status;
1507
1508ON_EXIT:
1509
1510  if (Token.Event != NULL) {
1511    gBS->CloseEvent (Token.Event);
1512  }
1513
1514  FreePool (Udp4TxData);
1515
1516  //
1517  // Reset the instance.
1518  //
1519  Udp4->Configure (Udp4, NULL);
1520  return Status;
1521}
1522
1523/**
1524  Decide whether the incoming UDP packet is acceptable per IP filter settings
1525  in provided PxeBcMode.
1526
1527  @param  PxeBcMode          Pointer to EFI_PXE_BASE_CODE_MODE.
1528  @param  Session            Received UDP session.
1529
1530  @retval TRUE               The UDP package matches IP filters.
1531  @retval FALSE              The UDP package doesn't matches IP filters.
1532
1533**/
1534BOOLEAN
1535CheckIpByFilter (
1536  IN EFI_PXE_BASE_CODE_MODE    *PxeBcMode,
1537  IN EFI_UDP4_SESSION_DATA     *Session
1538  )
1539{
1540  UINTN                   Index;
1541  EFI_IPv4_ADDRESS        Ip4Address;
1542  EFI_IPv4_ADDRESS        DestIp4Address;
1543
1544  if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) {
1545    return TRUE;
1546  }
1547
1548  CopyMem (&DestIp4Address, &Session->DestinationAddress, sizeof (DestIp4Address));
1549  if (((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0) &&
1550      IP4_IS_MULTICAST (EFI_NTOHL (DestIp4Address))
1551      ) {
1552    return TRUE;
1553  }
1554
1555  if (((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0) &&
1556      IP4_IS_LOCAL_BROADCAST (EFI_NTOHL (DestIp4Address))
1557      ) {
1558    return TRUE;
1559  }
1560
1561  CopyMem (&Ip4Address, &PxeBcMode->StationIp.v4, sizeof (Ip4Address));
1562  if (((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) &&
1563      EFI_IP4_EQUAL (&Ip4Address, &DestIp4Address)
1564      ) {
1565    return TRUE;
1566  }
1567
1568  ASSERT (PxeBcMode->IpFilter.IpCnt < EFI_PXE_BASE_CODE_MAX_IPCNT);
1569
1570  for (Index = 0; Index < PxeBcMode->IpFilter.IpCnt; Index++) {
1571    CopyMem (
1572      &Ip4Address,
1573      &PxeBcMode->IpFilter.IpList[Index].v4,
1574      sizeof (Ip4Address)
1575      );
1576    if (EFI_IP4_EQUAL (&Ip4Address, &DestIp4Address)) {
1577      return TRUE;
1578    }
1579  }
1580
1581  return FALSE;
1582}
1583
1584/**
1585  Reads a UDP packet from the network interface.
1586
1587  This function reads a UDP packet from a network interface. The data contents
1588  are returned in (the optional HeaderPtr and) BufferPtr, and the size of the
1589  buffer received is returned in BufferSize . If the input BufferSize is smaller
1590  than the UDP packet received (less optional HeaderSize), it will be set to the
1591  required size, and EFI_BUFFER_TOO_SMALL will be returned. In this case, the
1592  contents of BufferPtr are undefined, and the packet is lost. If a UDP packet is
1593  successfully received, then EFI_SUCCESS will be returned, and the information
1594  from the UDP header will be returned in DestIp, DestPort, SrcIp, and SrcPort if
1595  they are not NULL. Depending on the values of OpFlags and the DestIp, DestPort,
1596  SrcIp, and SrcPort input values, different types of UDP packet receive filtering
1597  will be performed. The following tables summarize these receive filter operations.
1598
1599  @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
1600  @param  OpFlags               The UDP operation flags.
1601  @param  DestIp                The destination IP address.
1602  @param  DestPort              The destination UDP port number.
1603  @param  SrcIp                 The source IP address.
1604  @param  SrcPort               The source UDP port number.
1605  @param  HeaderSize            An optional field which may be set to the length of a header at
1606                                HeaderPtr to be prefixed to the data at BufferPtr.
1607  @param  HeaderPtr             If HeaderSize is not NULL, a pointer to a header to be prefixed to the
1608                                data at BufferPtr.
1609  @param  BufferSize            A pointer to the size of the data at BufferPtr.
1610  @param  BufferPtr             A pointer to the data to be read.
1611
1612  @retval EFI_SUCCESS           The UDP Read operation was completed.
1613  @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
1614  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1615  @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
1616  @retval EFI_BUFFER_TOO_SMALL  The packet is larger than Buffer can hold.
1617  @retval EFI_ABORTED           The callback function aborted the UDP Read operation.
1618  @retval EFI_TIMEOUT           The UDP Read operation timed out.
1619
1620**/
1621EFI_STATUS
1622EFIAPI
1623EfiPxeBcUdpRead (
1624  IN EFI_PXE_BASE_CODE_PROTOCOL                *This,
1625  IN UINT16                                    OpFlags,
1626  IN OUT EFI_IP_ADDRESS                        *DestIp     OPTIONAL,
1627  IN OUT EFI_PXE_BASE_CODE_UDP_PORT            *DestPort   OPTIONAL,
1628  IN OUT EFI_IP_ADDRESS                        *SrcIp      OPTIONAL,
1629  IN OUT EFI_PXE_BASE_CODE_UDP_PORT            *SrcPort    OPTIONAL,
1630  IN UINTN                                     *HeaderSize OPTIONAL,
1631  IN VOID                                      *HeaderPtr  OPTIONAL,
1632  IN OUT UINTN                                 *BufferSize,
1633  IN VOID                                      *BufferPtr
1634  )
1635{
1636  PXEBC_PRIVATE_DATA        *Private;
1637  EFI_PXE_BASE_CODE_MODE    *Mode;
1638  EFI_UDP4_PROTOCOL         *Udp4;
1639  EFI_UDP4_COMPLETION_TOKEN Token;
1640  EFI_UDP4_RECEIVE_DATA     *RxData;
1641  EFI_UDP4_SESSION_DATA     *Session;
1642  EFI_STATUS                Status;
1643  BOOLEAN                   IsDone;
1644  BOOLEAN                   Matched;
1645  UINTN                     CopiedLen;
1646  UINTN                     HeaderLen;
1647  UINTN                     HeaderCopiedLen;
1648  UINTN                     BufferCopiedLen;
1649  UINT32                    FragmentLength;
1650  UINTN                     FragmentIndex;
1651  UINT8                     *FragmentBuffer;
1652
1653  if (This == NULL || DestIp == NULL || DestPort == NULL) {
1654    return EFI_INVALID_PARAMETER;
1655  }
1656
1657  if (((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) == 0 && (DestPort == NULL)) ||
1658      ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) == 0 && (SrcIp == NULL)) ||
1659      ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) == 0 && (SrcPort == NULL))) {
1660    return EFI_INVALID_PARAMETER;
1661  }
1662
1663  if (((HeaderSize != NULL) && (*HeaderSize == 0)) || ((HeaderSize != NULL) && (HeaderPtr == NULL))) {
1664    return EFI_INVALID_PARAMETER;
1665  }
1666
1667  if ((BufferSize == NULL) || (BufferPtr == NULL)) {
1668    return EFI_INVALID_PARAMETER;
1669  }
1670
1671  Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1672  Mode    = Private->PxeBc.Mode;
1673  Udp4    = Private->Udp4Read;
1674
1675  if (!Mode->Started) {
1676    return EFI_NOT_STARTED;
1677  }
1678
1679  Mode->IcmpErrorReceived = FALSE;
1680
1681  Status = gBS->CreateEvent (
1682                  EVT_NOTIFY_SIGNAL,
1683                  TPL_NOTIFY,
1684                  PxeBcCommonNotify,
1685                  &IsDone,
1686                  &Token.Event
1687                  );
1688  if (EFI_ERROR (Status)) {
1689    return EFI_OUT_OF_RESOURCES;
1690  }
1691
1692TRY_AGAIN:
1693
1694  IsDone = FALSE;
1695  Status = Udp4->Receive (Udp4, &Token);
1696  if (EFI_ERROR (Status)) {
1697    if (Status == EFI_ICMP_ERROR) {
1698      Mode->IcmpErrorReceived = TRUE;
1699    }
1700    goto ON_EXIT;
1701  }
1702
1703  Udp4->Poll (Udp4);
1704
1705  if (!IsDone) {
1706    Status = EFI_TIMEOUT;
1707  } else {
1708
1709    //
1710    // check whether this packet matches the filters
1711    //
1712    if (EFI_ERROR (Token.Status)){
1713      goto ON_EXIT;
1714    }
1715
1716    RxData  = Token.Packet.RxData;
1717    Session = &RxData->UdpSession;
1718
1719    Matched = TRUE;
1720
1721    if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) != 0) {
1722      Matched = FALSE;
1723      //
1724      // Check UDP package by IP filter settings
1725      //
1726      if (CheckIpByFilter (Mode, Session)) {
1727        Matched = TRUE;
1728      }
1729    }
1730
1731    if (Matched) {
1732      Matched = FALSE;
1733
1734      //
1735      // Match the destination ip of the received udp dgram
1736      //
1737      if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) != 0) {
1738        Matched = TRUE;
1739
1740        if (DestIp != NULL) {
1741          CopyMem (DestIp, &Session->DestinationAddress, sizeof (EFI_IPv4_ADDRESS));
1742        }
1743      } else {
1744        if (DestIp != NULL) {
1745          if (EFI_IP4_EQUAL (DestIp, &Session->DestinationAddress)) {
1746            Matched = TRUE;
1747          }
1748        } else {
1749          if (EFI_IP4_EQUAL (&Private->StationIp, &Session->DestinationAddress)) {
1750            Matched = TRUE;
1751          }
1752        }
1753      }
1754    }
1755
1756    if (Matched) {
1757      //
1758      // Match the destination port of the received udp dgram
1759      //
1760      if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) != 0) {
1761
1762        if (DestPort != NULL) {
1763          *DestPort = Session->DestinationPort;
1764        }
1765      } else {
1766
1767        if (*DestPort != Session->DestinationPort) {
1768          Matched = FALSE;
1769        }
1770      }
1771    }
1772
1773    if (Matched) {
1774      //
1775      // Match the source ip of the received udp dgram
1776      //
1777      if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) != 0) {
1778
1779        if (SrcIp != NULL) {
1780          CopyMem (SrcIp, &Session->SourceAddress, sizeof (EFI_IPv4_ADDRESS));
1781        }
1782      } else {
1783
1784        if (!EFI_IP4_EQUAL (SrcIp, &Session->SourceAddress)) {
1785          Matched = FALSE;
1786        }
1787      }
1788    }
1789
1790    if (Matched) {
1791      //
1792      // Match the source port of the received udp dgram
1793      //
1794      if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) != 0) {
1795
1796        if (SrcPort != NULL) {
1797          *SrcPort = Session->SourcePort;
1798        }
1799      } else {
1800
1801        if (*SrcPort != Session->SourcePort) {
1802          Matched = FALSE;
1803        }
1804      }
1805    }
1806
1807    if (Matched) {
1808      ASSERT (RxData != NULL);
1809
1810      HeaderLen = 0;
1811      if (HeaderSize != NULL) {
1812        HeaderLen = MIN (*HeaderSize, RxData->DataLength);
1813      }
1814
1815      if (RxData->DataLength - HeaderLen > *BufferSize) {
1816        Status = EFI_BUFFER_TOO_SMALL;
1817      } else {
1818        *HeaderSize = HeaderLen;
1819        *BufferSize = RxData->DataLength - HeaderLen;
1820
1821        HeaderCopiedLen = 0;
1822        BufferCopiedLen = 0;
1823        for (FragmentIndex = 0; FragmentIndex < RxData->FragmentCount; FragmentIndex++) {
1824          FragmentLength = RxData->FragmentTable[FragmentIndex].FragmentLength;
1825          FragmentBuffer = RxData->FragmentTable[FragmentIndex].FragmentBuffer;
1826          if (HeaderCopiedLen + FragmentLength < HeaderLen) {
1827            //
1828            // Copy the header part of received data.
1829            //
1830            CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, FragmentLength);
1831            HeaderCopiedLen += FragmentLength;
1832          } else if (HeaderCopiedLen < HeaderLen) {
1833            //
1834            // Copy the header part of received data.
1835            //
1836            CopiedLen = HeaderLen - HeaderCopiedLen;
1837            CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, CopiedLen);
1838            HeaderCopiedLen += CopiedLen;
1839
1840            //
1841            // Copy the other part of received data.
1842            //
1843            CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer + CopiedLen, FragmentLength - CopiedLen);
1844            BufferCopiedLen += (FragmentLength - CopiedLen);
1845          } else {
1846            //
1847            // Copy the other part of received data.
1848            //
1849            CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer, FragmentLength);
1850            BufferCopiedLen += FragmentLength;
1851          }
1852        }
1853      }
1854    } else {
1855
1856      Status = EFI_TIMEOUT;
1857    }
1858
1859    //
1860    // Recycle the RxData
1861    //
1862    gBS->SignalEvent (RxData->RecycleSignal);
1863
1864    if (!Matched) {
1865      goto TRY_AGAIN;
1866    }
1867  }
1868
1869ON_EXIT:
1870
1871  Udp4->Cancel (Udp4, &Token);
1872
1873  gBS->CloseEvent (Token.Event);
1874
1875  return Status;
1876}
1877
1878/**
1879  Updates the IP receive filters of a network device and enables software filtering.
1880
1881  The NewFilter field is used to modify the network device's current IP receive
1882  filter settings and to enable a software filter. This function updates the IpFilter
1883  field of the EFI_PXE_BASE_CODE_MODE structure with the contents of NewIpFilter.
1884  The software filter is used when the USE_FILTER in OpFlags is set to UdpRead().
1885  The current hardware filter remains in effect no matter what the settings of OpFlags
1886  are, so that the meaning of ANY_DEST_IP set in OpFlags to UdpRead() is from those
1887  packets whose reception is enabled in hardware-physical NIC address (unicast),
1888  broadcast address, logical address or addresses (multicast), or all (promiscuous).
1889  UdpRead() does not modify the IP filter settings.
1890  Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP receive
1891  filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
1892  If an application or driver wishes to preserve the IP receive filter settings,
1893  it will have to preserve the IP receive filter settings before these calls, and
1894  use SetIpFilter() to restore them after the calls. If incompatible filtering is
1895  requested (for example, PROMISCUOUS with anything else) or if the device does not
1896  support a requested filter setting and it cannot be accommodated in software
1897  (for example, PROMISCUOUS not supported), EFI_INVALID_PARAMETER will be returned.
1898  The IPlist field is used to enable IPs other than the StationIP. They may be
1899  multicast or unicast. If IPcnt is set as well as EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP,
1900  then both the StationIP and the IPs from the IPlist will be used.
1901
1902  @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
1903  @param  NewFilter             Pointer to the new set of IP receive filters.
1904
1905  @retval EFI_SUCCESS           The IP receive filter settings were updated.
1906  @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
1907  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1908
1909**/
1910EFI_STATUS
1911EFIAPI
1912EfiPxeBcSetIpFilter (
1913  IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
1914  IN EFI_PXE_BASE_CODE_IP_FILTER      *NewFilter
1915  )
1916{
1917  EFI_STATUS                Status;
1918  PXEBC_PRIVATE_DATA        *Private;
1919  EFI_PXE_BASE_CODE_MODE    *Mode;
1920  UINTN                     Index;
1921  EFI_UDP4_CONFIG_DATA      *Udp4Cfg;
1922  BOOLEAN                   PromiscuousNeed;
1923  BOOLEAN                   AcceptPromiscuous;
1924  BOOLEAN                   AcceptBroadcast;
1925  BOOLEAN                   MultiCastUpdate;
1926
1927  if (This == NULL) {
1928    DEBUG ((EFI_D_ERROR, "This == NULL.\n"));
1929    return EFI_INVALID_PARAMETER;
1930  }
1931
1932  Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1933  Mode = Private->PxeBc.Mode;
1934
1935  if (NewFilter == NULL) {
1936    DEBUG ((EFI_D_ERROR, "NewFilter == NULL.\n"));
1937    return EFI_INVALID_PARAMETER;
1938  }
1939
1940  if (NewFilter->IpCnt > EFI_PXE_BASE_CODE_MAX_IPCNT) {
1941    DEBUG ((EFI_D_ERROR, "NewFilter->IpCnt > %d.\n", EFI_PXE_BASE_CODE_MAX_IPCNT));
1942    return EFI_INVALID_PARAMETER;
1943  }
1944
1945  if (!Mode->Started) {
1946    DEBUG ((EFI_D_ERROR, "BC was not started.\n"));
1947    return EFI_NOT_STARTED;
1948  }
1949
1950  if (Mode->UsingIpv6) {
1951    DEBUG ((EFI_D_ERROR, "This driver is PXE for IPv4 Only.\n"));
1952    return EFI_INVALID_PARAMETER;
1953  }
1954
1955  PromiscuousNeed = FALSE;
1956
1957  for (Index = 0; Index < NewFilter->IpCnt; ++Index) {
1958    if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (NewFilter->IpList[Index].v4))) {
1959      //
1960      // The IP is a broadcast address.
1961      //
1962      DEBUG ((EFI_D_ERROR, "There is broadcast address in NewFilter.\n"));
1963      return EFI_INVALID_PARAMETER;
1964    }
1965    if (NetIp4IsUnicast (EFI_IP4 (NewFilter->IpList[Index].v4), 0) &&
1966        ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0)
1967       ) {
1968      //
1969      // If EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP is set and IP4 address is in IpList,
1970      // promiscuous mode is needed.
1971      //
1972      PromiscuousNeed = TRUE;
1973    }
1974  }
1975
1976  AcceptPromiscuous = FALSE;
1977  AcceptBroadcast   = FALSE;
1978  MultiCastUpdate   = FALSE;
1979
1980  if (PromiscuousNeed ||
1981      ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) ||
1982      ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0)
1983     ) {
1984    //
1985    // Configure the udp4 filter to receive all packages.
1986    //
1987    AcceptPromiscuous  = TRUE;
1988  } else if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0) {
1989    //
1990    // Configure the udp4 filter to receive all broadcast packages.
1991    //
1992    AcceptBroadcast   = TRUE;
1993  }
1994
1995  //
1996  // In multicast condition when Promiscuous FALSE and IpCnt no-zero.
1997  // Here check if there is any update of the multicast ip address. If yes,
1998  // we need leave the old multicast group (by Config UDP instance to NULL),
1999  // and join the new multicast group.
2000  //
2001  if (!AcceptPromiscuous) {
2002    if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) {
2003      if (Mode->IpFilter.IpCnt != NewFilter->IpCnt) {
2004        MultiCastUpdate = TRUE;
2005      } else if (CompareMem (Mode->IpFilter.IpList, NewFilter->IpList, NewFilter->IpCnt * sizeof (EFI_IP_ADDRESS)) != 0 ) {
2006        MultiCastUpdate = TRUE;
2007      }
2008    }
2009  }
2010
2011  //
2012  // Check whether we need reconfigure the UDP instance.
2013  //
2014  Udp4Cfg = &Private->Udp4CfgData;
2015  if ((AcceptPromiscuous != Udp4Cfg->AcceptPromiscuous) ||
2016  	  (AcceptBroadcast != Udp4Cfg->AcceptBroadcast)     || MultiCastUpdate) {
2017    //
2018    // Clear the UDP instance configuration, all joined groups will be left
2019    // during the operation.
2020    //
2021    Private->Udp4Read->Configure (Private->Udp4Read, NULL);
2022
2023    //
2024    // Configure the UDP instance with the new configuration.
2025    //
2026    Udp4Cfg->AcceptPromiscuous = AcceptPromiscuous;
2027    Udp4Cfg->AcceptBroadcast   = AcceptBroadcast;
2028    Status = Private->Udp4Read->Configure (Private->Udp4Read, Udp4Cfg);
2029    if (EFI_ERROR (Status)) {
2030      return Status;
2031    }
2032
2033    //
2034    // In not Promiscuous mode, need to join the new multicast group.
2035    //
2036    if (!AcceptPromiscuous) {
2037      for (Index = 0; Index < NewFilter->IpCnt; ++Index) {
2038        if (IP4_IS_MULTICAST (EFI_NTOHL (NewFilter->IpList[Index].v4))) {
2039          //
2040          // Join the mutilcast group.
2041          //
2042          Status = Private->Udp4Read->Groups (Private->Udp4Read, TRUE, &NewFilter->IpList[Index].v4);
2043          if (EFI_ERROR (Status)) {
2044            return Status;
2045          }
2046        }
2047      }
2048    }
2049  }
2050
2051
2052  //
2053  // Save the new filter.
2054  //
2055  CopyMem (&Mode->IpFilter, NewFilter, sizeof (Mode->IpFilter));
2056
2057  return EFI_SUCCESS;
2058}
2059
2060
2061/**
2062  Uses the ARP protocol to resolve a MAC address.
2063
2064  This function uses the ARP protocol to resolve a MAC address. The UsingIpv6 field
2065  of the EFI_PXE_BASE_CODE_MODE structure is used to determine if IPv4 or IPv6
2066  addresses are being used. The IP address specified by IpAddr is used to resolve
2067  a MAC address. If the ARP protocol succeeds in resolving the specified address,
2068  then the ArpCacheEntries and ArpCache fields of the EFI_PXE_BASE_CODE_MODE structure
2069  are updated, and EFI_SUCCESS is returned. If MacAddr is not NULL, the resolved
2070  MAC address is placed there as well.  If the PXE Base Code protocol is in the
2071  stopped state, then EFI_NOT_STARTED is returned. If the ARP protocol encounters
2072  a timeout condition while attempting to resolve an address, then EFI_TIMEOUT is
2073  returned. If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
2074  then EFI_ABORTED is returned.
2075
2076  @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
2077  @param  IpAddr                Pointer to the IP address that is used to resolve a MAC address.
2078  @param  MacAddr               If not NULL, a pointer to the MAC address that was resolved with the
2079                                ARP protocol.
2080
2081  @retval EFI_SUCCESS           The IP or MAC address was resolved.
2082  @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
2083  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
2084  @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
2085  @retval EFI_ICMP_ERROR        Something error occur with the ICMP packet message.
2086
2087**/
2088EFI_STATUS
2089EFIAPI
2090EfiPxeBcArp (
2091  IN EFI_PXE_BASE_CODE_PROTOCOL       * This,
2092  IN EFI_IP_ADDRESS                   * IpAddr,
2093  IN EFI_MAC_ADDRESS                  * MacAddr OPTIONAL
2094  )
2095{
2096  PXEBC_PRIVATE_DATA      *Private;
2097  EFI_PXE_BASE_CODE_MODE  *Mode;
2098  EFI_STATUS              Status;
2099  EFI_MAC_ADDRESS         TempMacAddr;
2100
2101  if (This == NULL || IpAddr == NULL) {
2102    return EFI_INVALID_PARAMETER;
2103  }
2104
2105  Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
2106  Mode    = Private->PxeBc.Mode;
2107
2108  if (!Mode->Started) {
2109    return EFI_NOT_STARTED;
2110  }
2111
2112  if (!Private->AddressIsOk || Mode->UsingIpv6) {
2113    //
2114    // We can't resolve the IP address if we don't have a local address now.
2115    // Don't have ARP for IPv6.
2116    //
2117    return EFI_INVALID_PARAMETER;
2118  }
2119
2120  Mode->IcmpErrorReceived = FALSE;
2121
2122  if (!Mode->AutoArp) {
2123    //
2124    // If AutoArp is set false, check arp cache
2125    //
2126    UpdateArpCache (This);
2127    if (!FindInArpCache (Mode, &IpAddr->v4, &TempMacAddr)) {
2128      return EFI_DEVICE_ERROR;
2129    }
2130  } else {
2131    Status = Private->Arp->Request (Private->Arp, &IpAddr->v4, NULL, &TempMacAddr);
2132    if (EFI_ERROR (Status)) {
2133      if (Status == EFI_ICMP_ERROR) {
2134        Mode->IcmpErrorReceived = TRUE;
2135      }
2136      return Status;
2137    }
2138  }
2139
2140  if (MacAddr != NULL) {
2141    CopyMem (MacAddr, &TempMacAddr, sizeof (EFI_MAC_ADDRESS));
2142  }
2143
2144  return EFI_SUCCESS;
2145}
2146
2147/**
2148  Updates the parameters that affect the operation of the PXE Base Code Protocol.
2149
2150  This function sets parameters that affect the operation of the PXE Base Code Protocol.
2151  The parameter specified by NewAutoArp is used to control the generation of ARP
2152  protocol packets. If NewAutoArp is TRUE, then ARP Protocol packets will be generated
2153  as required by the PXE Base Code Protocol. If NewAutoArp is FALSE, then no ARP
2154  Protocol packets will be generated. In this case, the only mappings that are
2155  available are those stored in the ArpCache of the EFI_PXE_BASE_CODE_MODE structure.
2156  If there are not enough mappings in the ArpCache to perform a PXE Base Code Protocol
2157  service, then the service will fail. This function updates the AutoArp field of
2158  the EFI_PXE_BASE_CODE_MODE structure to NewAutoArp.
2159  The SetParameters() call must be invoked after a Callback Protocol is installed
2160  to enable the use of callbacks.
2161
2162  @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
2163  @param  NewAutoArp            If not NULL, a pointer to a value that specifies whether to replace the
2164                                current value of AutoARP.
2165  @param  NewSendGUID           If not NULL, a pointer to a value that specifies whether to replace the
2166                                current value of SendGUID.
2167  @param  NewTTL                If not NULL, a pointer to be used in place of the current value of TTL,
2168                                the "time to live" field of the IP header.
2169  @param  NewToS                If not NULL, a pointer to be used in place of the current value of ToS,
2170                                the "type of service" field of the IP header.
2171  @param  NewMakeCallback       If not NULL, a pointer to a value that specifies whether to replace the
2172                                current value of the MakeCallback field of the Mode structure.
2173
2174  @retval EFI_SUCCESS           The new parameters values were updated.
2175  @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
2176  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
2177
2178**/
2179EFI_STATUS
2180EFIAPI
2181EfiPxeBcSetParameters (
2182  IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
2183  IN BOOLEAN                          *NewAutoArp OPTIONAL,
2184  IN BOOLEAN                          *NewSendGUID OPTIONAL,
2185  IN UINT8                            *NewTTL OPTIONAL,
2186  IN UINT8                            *NewToS OPTIONAL,
2187  IN BOOLEAN                          *NewMakeCallback  // OPTIONAL
2188  )
2189{
2190  PXEBC_PRIVATE_DATA      *Private;
2191  EFI_PXE_BASE_CODE_MODE  *Mode;
2192  EFI_STATUS              Status;
2193
2194  Status = EFI_SUCCESS;
2195
2196  if (This == NULL) {
2197    Status = EFI_INVALID_PARAMETER;
2198    goto ON_EXIT;
2199  }
2200
2201  Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
2202  Mode    = Private->PxeBc.Mode;
2203
2204  if (NewSendGUID != NULL && *NewSendGUID) {
2205    //
2206    // FixMe, cann't locate SendGuid
2207    //
2208  }
2209
2210  if (NewMakeCallback != NULL && *NewMakeCallback) {
2211
2212    Status = gBS->HandleProtocol (
2213                    Private->Controller,
2214                    &gEfiPxeBaseCodeCallbackProtocolGuid,
2215                    (VOID **) &Private->PxeBcCallback
2216                    );
2217    if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {
2218
2219      Status = EFI_INVALID_PARAMETER;
2220      goto ON_EXIT;
2221    }
2222  }
2223
2224  if (!Mode->Started) {
2225    Status = EFI_NOT_STARTED;
2226    goto ON_EXIT;
2227  }
2228
2229  if (NewMakeCallback != NULL) {
2230
2231    if (*NewMakeCallback) {
2232      //
2233      // Update the Callback protocol.
2234      //
2235      Status = gBS->HandleProtocol (
2236                      Private->Controller,
2237                      &gEfiPxeBaseCodeCallbackProtocolGuid,
2238                      (VOID **) &Private->PxeBcCallback
2239                      );
2240
2241      if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {
2242        Status = EFI_INVALID_PARAMETER;
2243        goto ON_EXIT;
2244      }
2245    } else {
2246      Private->PxeBcCallback = NULL;
2247    }
2248
2249    Mode->MakeCallbacks = *NewMakeCallback;
2250  }
2251
2252  if (NewAutoArp != NULL) {
2253    Mode->AutoArp = *NewAutoArp;
2254  }
2255
2256  if (NewSendGUID != NULL) {
2257    Mode->SendGUID = *NewSendGUID;
2258  }
2259
2260  if (NewTTL != NULL) {
2261    Mode->TTL = *NewTTL;
2262  }
2263
2264  if (NewToS != NULL) {
2265    Mode->ToS = *NewToS;
2266  }
2267
2268ON_EXIT:
2269  return Status;
2270}
2271
2272/**
2273  Updates the station IP address and/or subnet mask values of a network device.
2274
2275  This function updates the station IP address and/or subnet mask values of a network
2276  device. The NewStationIp field is used to modify the network device's current IP address.
2277  If NewStationIP is NULL, then the current IP address will not be modified. Otherwise,
2278  this function updates the StationIp field of the EFI_PXE_BASE_CODE_MODE structure
2279  with NewStationIp. The NewSubnetMask field is used to modify the network device's current subnet
2280  mask. If NewSubnetMask is NULL, then the current subnet mask will not be modified.
2281  Otherwise, this function updates the SubnetMask field of the EFI_PXE_BASE_CODE_MODE
2282  structure with NewSubnetMask.
2283
2284  @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
2285  @param  NewStationIp          Pointer to the new IP address to be used by the network device.
2286  @param  NewSubnetMask         Pointer to the new subnet mask to be used by the network device.
2287
2288  @retval EFI_SUCCESS           The new station IP address and/or subnet mask were updated.
2289  @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
2290  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
2291
2292**/
2293EFI_STATUS
2294EFIAPI
2295EfiPxeBcSetStationIP (
2296  IN EFI_PXE_BASE_CODE_PROTOCOL       * This,
2297  IN EFI_IP_ADDRESS                   * NewStationIp  OPTIONAL,
2298  IN EFI_IP_ADDRESS                   * NewSubnetMask OPTIONAL
2299  )
2300{
2301  PXEBC_PRIVATE_DATA      *Private;
2302  EFI_PXE_BASE_CODE_MODE  *Mode;
2303  EFI_ARP_CONFIG_DATA     ArpConfigData;
2304
2305  if (This == NULL) {
2306    return EFI_INVALID_PARAMETER;
2307  }
2308
2309  if (NewStationIp != NULL && !NetIp4IsUnicast (NTOHL (NewStationIp->Addr[0]), 0)) {
2310    return EFI_INVALID_PARAMETER;
2311  }
2312
2313  if (NewSubnetMask != NULL && !IP4_IS_VALID_NETMASK (NTOHL (NewSubnetMask->Addr[0]))) {
2314    return EFI_INVALID_PARAMETER;
2315  }
2316
2317  Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
2318  Mode    = Private->PxeBc.Mode;
2319
2320  if (!Mode->Started) {
2321    return EFI_NOT_STARTED;
2322  }
2323
2324  if (NewStationIp != NULL) {
2325    CopyMem (&Mode->StationIp, NewStationIp, sizeof (EFI_IP_ADDRESS));
2326    CopyMem (&Private->StationIp, NewStationIp, sizeof (EFI_IP_ADDRESS));
2327  }
2328
2329  if (NewSubnetMask != NULL) {
2330    CopyMem (&Mode->SubnetMask, NewSubnetMask, sizeof (EFI_IP_ADDRESS));
2331    CopyMem (&Private->SubnetMask ,NewSubnetMask, sizeof (EFI_IP_ADDRESS));
2332  }
2333
2334  Private->AddressIsOk = TRUE;
2335
2336  if (!Mode->UsingIpv6) {
2337    //
2338    // If in IPv4 mode, configure the corresponding ARP with this new
2339    // station IP address.
2340    //
2341    ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));
2342
2343    ArpConfigData.SwAddressType   = 0x0800;
2344    ArpConfigData.SwAddressLength = (UINT8) sizeof (EFI_IPv4_ADDRESS);
2345    ArpConfigData.StationAddress  = &Private->StationIp.v4;
2346
2347    Private->Arp->Configure (Private->Arp, NULL);
2348    Private->Arp->Configure (Private->Arp, &ArpConfigData);
2349
2350    //
2351    // Update the route table.
2352    //
2353    Mode->RouteTableEntries                = 1;
2354    Mode->RouteTable[0].IpAddr.Addr[0]     = Private->StationIp.Addr[0] & Private->SubnetMask.Addr[0];
2355    Mode->RouteTable[0].SubnetMask.Addr[0] = Private->SubnetMask.Addr[0];
2356    Mode->RouteTable[0].GwAddr.Addr[0]     = 0;
2357  }
2358
2359  return EFI_SUCCESS;
2360}
2361
2362/**
2363  Updates the contents of the cached DHCP and Discover packets.
2364
2365  The pointers to the new packets are used to update the contents of the cached
2366  packets in the EFI_PXE_BASE_CODE_MODE structure.
2367
2368  @param  This                   Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
2369  @param  NewDhcpDiscoverValid   Pointer to a value that will replace the current
2370                                 DhcpDiscoverValid field.
2371  @param  NewDhcpAckReceived     Pointer to a value that will replace the current
2372                                 DhcpAckReceived field.
2373  @param  NewProxyOfferReceived  Pointer to a value that will replace the current
2374                                 ProxyOfferReceived field.
2375  @param  NewPxeDiscoverValid    Pointer to a value that will replace the current
2376                                 ProxyOfferReceived field.
2377  @param  NewPxeReplyReceived    Pointer to a value that will replace the current
2378                                 PxeReplyReceived field.
2379  @param  NewPxeBisReplyReceived Pointer to a value that will replace the current
2380                                 PxeBisReplyReceived field.
2381  @param  NewDhcpDiscover        Pointer to the new cached DHCP Discover packet contents.
2382  @param  NewDhcpAck             Pointer to the new cached DHCP Ack packet contents.
2383  @param  NewProxyOffer          Pointer to the new cached Proxy Offer packet contents.
2384  @param  NewPxeDiscover         Pointer to the new cached PXE Discover packet contents.
2385  @param  NewPxeReply            Pointer to the new cached PXE Reply packet contents.
2386  @param  NewPxeBisReply         Pointer to the new cached PXE BIS Reply packet contents.
2387
2388  @retval EFI_SUCCESS            The cached packet contents were updated.
2389  @retval EFI_NOT_STARTED        The PXE Base Code Protocol is in the stopped state.
2390  @retval EFI_INVALID_PARAMETER  This is NULL or not point to a valid EFI_PXE_BASE_CODE_PROTOCOL structure.
2391
2392**/
2393EFI_STATUS
2394EFIAPI
2395EfiPxeBcSetPackets (
2396  IN EFI_PXE_BASE_CODE_PROTOCOL       * This,
2397  IN BOOLEAN                          * NewDhcpDiscoverValid OPTIONAL,
2398  IN BOOLEAN                          * NewDhcpAckReceived OPTIONAL,
2399  IN BOOLEAN                          * NewProxyOfferReceived OPTIONAL,
2400  IN BOOLEAN                          * NewPxeDiscoverValid OPTIONAL,
2401  IN BOOLEAN                          * NewPxeReplyReceived OPTIONAL,
2402  IN BOOLEAN                          * NewPxeBisReplyReceived OPTIONAL,
2403  IN EFI_PXE_BASE_CODE_PACKET         * NewDhcpDiscover OPTIONAL,
2404  IN EFI_PXE_BASE_CODE_PACKET         * NewDhcpAck OPTIONAL,
2405  IN EFI_PXE_BASE_CODE_PACKET         * NewProxyOffer OPTIONAL,
2406  IN EFI_PXE_BASE_CODE_PACKET         * NewPxeDiscover OPTIONAL,
2407  IN EFI_PXE_BASE_CODE_PACKET         * NewPxeReply OPTIONAL,
2408  IN EFI_PXE_BASE_CODE_PACKET         * NewPxeBisReply OPTIONAL
2409  )
2410{
2411  PXEBC_PRIVATE_DATA      *Private;
2412  EFI_PXE_BASE_CODE_MODE  *Mode;
2413
2414  if (This == NULL) {
2415    return EFI_INVALID_PARAMETER;
2416  }
2417
2418  Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
2419  Mode    = Private->PxeBc.Mode;
2420
2421  if (!Mode->Started) {
2422    return EFI_NOT_STARTED;
2423  }
2424
2425  if (NewDhcpDiscoverValid != NULL) {
2426    Mode->DhcpDiscoverValid = *NewDhcpDiscoverValid;
2427  }
2428
2429  if (NewDhcpAckReceived != NULL) {
2430    Mode->DhcpAckReceived = *NewDhcpAckReceived;
2431  }
2432
2433  if (NewProxyOfferReceived != NULL) {
2434    Mode->ProxyOfferReceived = *NewProxyOfferReceived;
2435  }
2436
2437  if (NewPxeDiscoverValid != NULL) {
2438    Mode->PxeDiscoverValid = *NewPxeDiscoverValid;
2439  }
2440
2441  if (NewPxeReplyReceived != NULL) {
2442    Mode->PxeReplyReceived = *NewPxeReplyReceived;
2443  }
2444
2445  if (NewPxeBisReplyReceived != NULL) {
2446    Mode->PxeBisReplyReceived = *NewPxeBisReplyReceived;
2447  }
2448
2449  if (NewDhcpDiscover != NULL) {
2450    CopyMem (&Mode->DhcpDiscover, NewDhcpDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
2451  }
2452
2453  if (NewDhcpAck != NULL) {
2454    CopyMem (&Mode->DhcpAck, NewDhcpAck, sizeof (EFI_PXE_BASE_CODE_PACKET));
2455  }
2456
2457  if (NewProxyOffer != NULL) {
2458    CopyMem (&Mode->ProxyOffer, NewProxyOffer, sizeof (EFI_PXE_BASE_CODE_PACKET));
2459  }
2460
2461  if (NewPxeDiscover != NULL) {
2462    CopyMem (&Mode->PxeDiscover, NewPxeDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
2463  }
2464
2465  if (NewPxeReply != NULL) {
2466    CopyMem (&Mode->PxeReply, NewPxeReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
2467  }
2468
2469  if (NewPxeBisReply != NULL) {
2470    CopyMem (&Mode->PxeBisReply, NewPxeBisReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
2471  }
2472
2473  return EFI_SUCCESS;
2474}
2475
2476EFI_PXE_BASE_CODE_PROTOCOL  mPxeBcProtocolTemplate = {
2477  EFI_PXE_BASE_CODE_PROTOCOL_REVISION,
2478  EfiPxeBcStart,
2479  EfiPxeBcStop,
2480  EfiPxeBcDhcp,
2481  EfiPxeBcDiscover,
2482  EfiPxeBcMtftp,
2483  EfiPxeBcUdpWrite,
2484  EfiPxeBcUdpRead,
2485  EfiPxeBcSetIpFilter,
2486  EfiPxeBcArp,
2487  EfiPxeBcSetParameters,
2488  EfiPxeBcSetStationIP,
2489  EfiPxeBcSetPackets,
2490  NULL
2491};
2492
2493/**
2494  Callback function that is invoked when the PXE Base Code Protocol is about to transmit, has
2495  received, or is waiting to receive a packet.
2496
2497  This function is invoked when the PXE Base Code Protocol is about to transmit, has received,
2498  or is waiting to receive a packet. Parameters Function and Received specify the type of event.
2499  Parameters PacketLen and Packet specify the packet that generated the event. If these fields
2500  are zero and NULL respectively, then this is a status update callback. If the operation specified
2501  by Function is to continue, then CALLBACK_STATUS_CONTINUE should be returned. If the operation
2502  specified by Function should be aborted, then CALLBACK_STATUS_ABORT should be returned. Due to
2503  the polling nature of UEFI device drivers, a callback function should not execute for more than 5 ms.
2504  The SetParameters() function must be called after a Callback Protocol is installed to enable the
2505  use of callbacks.
2506
2507  @param  This                  Pointer to the EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL instance.
2508  @param  Function              The PXE Base Code Protocol function that is waiting for an event.
2509  @param  Received              TRUE if the callback is being invoked due to a receive event. FALSE if
2510                                the callback is being invoked due to a transmit event.
2511  @param  PacketLength          The length, in bytes, of Packet. This field will have a value of zero if
2512                                this is a wait for receive event.
2513  @param  PacketPtr             If Received is TRUE, a pointer to the packet that was just received;
2514                                otherwise a pointer to the packet that is about to be transmitted.
2515
2516  @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE if Function specifies a continue operation
2517  @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT    if Function specifies an abort operation
2518
2519**/
2520EFI_PXE_BASE_CODE_CALLBACK_STATUS
2521EFIAPI
2522EfiPxeLoadFileCallback (
2523  IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL  * This,
2524  IN EFI_PXE_BASE_CODE_FUNCTION           Function,
2525  IN BOOLEAN                              Received,
2526  IN UINT32                               PacketLength,
2527  IN EFI_PXE_BASE_CODE_PACKET             * PacketPtr OPTIONAL
2528  )
2529{
2530  EFI_INPUT_KEY Key;
2531  EFI_STATUS    Status;
2532
2533  //
2534  // Catch Ctrl-C or ESC to abort.
2535  //
2536  Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
2537
2538  if (!EFI_ERROR (Status)) {
2539
2540    if (Key.ScanCode == SCAN_ESC || Key.UnicodeChar == (0x1F & 'c')) {
2541
2542      return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
2543    }
2544  }
2545  //
2546  // No print if receive packet
2547  //
2548  if (Received) {
2549    return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
2550  }
2551  //
2552  // Print only for three functions
2553  //
2554  switch (Function) {
2555
2556  case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:
2557    //
2558    // Print only for open MTFTP packets, not every MTFTP packets
2559    //
2560    if (PacketLength != 0 && PacketPtr != NULL) {
2561      if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {
2562        return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
2563      }
2564    }
2565    break;
2566
2567  case EFI_PXE_BASE_CODE_FUNCTION_DHCP:
2568  case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:
2569    break;
2570
2571  default:
2572    return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
2573  }
2574
2575  if (PacketLength != 0 && PacketPtr != NULL) {
2576    //
2577    // Print '.' when transmit a packet
2578    //
2579    AsciiPrint (".");
2580
2581  }
2582
2583  return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
2584}
2585
2586EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL mPxeBcCallBackTemplate = {
2587  EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION,
2588  EfiPxeLoadFileCallback
2589};
2590
2591
2592/**
2593  Find the boot file.
2594
2595  @param  Private      Pointer to PxeBc private data.
2596  @param  BufferSize   Pointer to buffer size.
2597  @param  Buffer       Pointer to buffer.
2598
2599  @retval EFI_SUCCESS          Discover the boot file successfully.
2600  @retval EFI_TIMEOUT          The TFTP/MTFTP operation timed out.
2601  @retval EFI_ABORTED          PXE bootstrap server, so local boot need abort.
2602  @retval EFI_BUFFER_TOO_SMALL The buffer is too small to load the boot file.
2603
2604**/
2605EFI_STATUS
2606DiscoverBootFile (
2607  IN     PXEBC_PRIVATE_DATA  *Private,
2608  IN OUT UINT64              *BufferSize,
2609  IN     VOID                *Buffer
2610  )
2611{
2612  EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
2613  EFI_PXE_BASE_CODE_MODE      *Mode;
2614  EFI_STATUS                  Status;
2615  UINT16                      Type;
2616  UINT16                      Layer;
2617  BOOLEAN                     UseBis;
2618  PXEBC_CACHED_DHCP4_PACKET   *Packet;
2619  UINT16                      Value;
2620
2621  PxeBc = &Private->PxeBc;
2622  Mode  = PxeBc->Mode;
2623  Type  = EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP;
2624  Layer = EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL;
2625
2626  //
2627  // do DHCP.
2628  //
2629  Status = PxeBc->Dhcp (PxeBc, TRUE);
2630  if (EFI_ERROR (Status)) {
2631    return Status;
2632  }
2633
2634  //
2635  // Select a boot server
2636  //
2637  Status = PxeBcSelectBootPrompt (Private);
2638
2639  if (Status == EFI_SUCCESS) {
2640    Status = PxeBcSelectBootMenu (Private, &Type, TRUE);
2641  } else if (Status == EFI_TIMEOUT) {
2642    Status = PxeBcSelectBootMenu (Private, &Type, FALSE);
2643  }
2644
2645  if (!EFI_ERROR (Status)) {
2646
2647    if (Type == EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP) {
2648      //
2649      // Local boot(PXE bootstrap server) need abort
2650      //
2651      return EFI_ABORTED;
2652    }
2653
2654    UseBis  = (BOOLEAN) (Mode->BisSupported && Mode->BisDetected);
2655    Status  = PxeBc->Discover (PxeBc, Type, &Layer, UseBis, NULL);
2656    if (EFI_ERROR (Status)) {
2657      return Status;
2658    }
2659  }
2660
2661  *BufferSize = 0;
2662
2663  //
2664  // Get bootfile name and (m)tftp server ip addresss
2665  //
2666  if (Mode->PxeReplyReceived) {
2667    Packet = &Private->PxeReply;
2668  } else if (Mode->ProxyOfferReceived) {
2669    Packet = &Private->ProxyOffer;
2670  } else {
2671    Packet = &Private->Dhcp4Ack;
2672  }
2673
2674  //
2675  // Use siaddr(next server) in DHCPOFFER packet header, if zero, use option 54(server identifier)
2676  // in DHCPOFFER packet.
2677  // (It does not comply with PXE Spec, Ver2.1)
2678  //
2679  if (EFI_IP4_EQUAL (&Packet->Packet.Offer.Dhcp4.Header.ServerAddr, &mZeroIp4Addr)) {
2680    CopyMem (
2681      &Private->ServerIp,
2682      Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
2683      sizeof (EFI_IPv4_ADDRESS)
2684      );
2685  } else {
2686    CopyMem (
2687      &Private->ServerIp,
2688      &Packet->Packet.Offer.Dhcp4.Header.ServerAddr,
2689      sizeof (EFI_IPv4_ADDRESS)
2690      );
2691  }
2692  if (Private->ServerIp.Addr[0] == 0) {
2693    return EFI_DEVICE_ERROR;
2694  }
2695
2696  ASSERT (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);
2697
2698  //
2699  // bootlfile name
2700  //
2701  Private->BootFileName = (CHAR8 *) (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data);
2702
2703  if (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {
2704    //
2705    // Already have the bootfile length option, compute the file size
2706    //
2707    CopyMem (&Value, Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value));
2708    Value       = NTOHS (Value);
2709    *BufferSize = 512 * Value;
2710    Status      = EFI_BUFFER_TOO_SMALL;
2711  } else {
2712    //
2713    // Get the bootfile size from tftp
2714    //
2715    Status = PxeBc->Mtftp (
2716                      PxeBc,
2717                      EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
2718                      Buffer,
2719                      FALSE,
2720                      BufferSize,
2721                      &Private->BlockSize,
2722                      &Private->ServerIp,
2723                      (UINT8 *) Private->BootFileName,
2724                      NULL,
2725                      FALSE
2726                      );
2727  }
2728
2729  Private->FileSize = (UINTN) *BufferSize;
2730
2731  return Status;
2732}
2733
2734/**
2735  Causes the driver to load a specified file.
2736
2737  @param  This                  Protocol instance pointer.
2738  @param  FilePath              The device specific path of the file to load.
2739  @param  BootPolicy            If TRUE, indicates that the request originates from the
2740                                boot manager is attempting to load FilePath as a boot
2741                                selection. If FALSE, then FilePath must match as exact file
2742                                to be loaded.
2743  @param  BufferSize            On input the size of Buffer in bytes. On output with a return
2744                                code of EFI_SUCCESS, the amount of data transferred to
2745                                Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
2746                                the size of Buffer required to retrieve the requested file.
2747  @param  Buffer                The memory buffer to transfer the file to. IF Buffer is NULL,
2748                                then no the size of the requested file is returned in
2749                                BufferSize.
2750
2751  @retval EFI_SUCCESS                 The file was loaded.
2752  @retval EFI_UNSUPPORTED             The device does not support the provided BootPolicy
2753  @retval EFI_INVALID_PARAMETER       FilePath is not a valid device path, or
2754                                      BufferSize is NULL.
2755  @retval EFI_NO_MEDIA                No medium was present to load the file.
2756  @retval EFI_DEVICE_ERROR            The file was not loaded due to a device error.
2757  @retval EFI_NO_RESPONSE             The remote system did not respond.
2758  @retval EFI_NOT_FOUND               The file was not found.
2759  @retval EFI_ABORTED                 The file load process was manually cancelled.
2760
2761**/
2762EFI_STATUS
2763EFIAPI
2764EfiPxeLoadFile (
2765  IN EFI_LOAD_FILE_PROTOCOL           * This,
2766  IN EFI_DEVICE_PATH_PROTOCOL         * FilePath,
2767  IN BOOLEAN                          BootPolicy,
2768  IN OUT UINTN                        *BufferSize,
2769  IN VOID                             *Buffer OPTIONAL
2770  )
2771{
2772  PXEBC_PRIVATE_DATA          *Private;
2773  EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
2774  BOOLEAN                     NewMakeCallback;
2775  EFI_STATUS                  Status;
2776  UINT64                      TmpBufSize;
2777  BOOLEAN                     MediaPresent;
2778
2779  if (FilePath == NULL || !IsDevicePathEnd (FilePath)) {
2780    return EFI_INVALID_PARAMETER;
2781  }
2782
2783  Private         = PXEBC_PRIVATE_DATA_FROM_LOADFILE (This);
2784  PxeBc           = &Private->PxeBc;
2785  NewMakeCallback = FALSE;
2786  Status          = EFI_DEVICE_ERROR;
2787
2788  if (This == NULL || BufferSize == NULL) {
2789
2790    return EFI_INVALID_PARAMETER;
2791  }
2792
2793  //
2794  // Only support BootPolicy
2795  //
2796  if (!BootPolicy) {
2797    return EFI_UNSUPPORTED;
2798  }
2799
2800  //
2801  // Check media status before PXE start
2802  //
2803  MediaPresent = TRUE;
2804  NetLibDetectMedia (Private->Controller, &MediaPresent);
2805  if (!MediaPresent) {
2806    return EFI_NO_MEDIA;
2807  }
2808
2809  Status = PxeBc->Start (PxeBc, FALSE);
2810  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
2811    return Status;
2812  }
2813
2814  Status = gBS->HandleProtocol (
2815                  Private->Controller,
2816                  &gEfiPxeBaseCodeCallbackProtocolGuid,
2817                  (VOID **) &Private->PxeBcCallback
2818                  );
2819  if (Status == EFI_UNSUPPORTED) {
2820
2821    CopyMem (&Private->LoadFileCallback, &mPxeBcCallBackTemplate, sizeof (Private->LoadFileCallback));
2822
2823    Status = gBS->InstallProtocolInterface (
2824                    &Private->Controller,
2825                    &gEfiPxeBaseCodeCallbackProtocolGuid,
2826                    EFI_NATIVE_INTERFACE,
2827                    &Private->LoadFileCallback
2828                    );
2829
2830    NewMakeCallback = (BOOLEAN) (Status == EFI_SUCCESS);
2831
2832    Status          = PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);
2833    if (EFI_ERROR (Status)) {
2834      PxeBc->Stop (PxeBc);
2835      return Status;
2836    }
2837  }
2838
2839  if (Private->FileSize == 0) {
2840    TmpBufSize  = 0;
2841    Status      = DiscoverBootFile (Private, &TmpBufSize, Buffer);
2842
2843    if (sizeof (UINTN) < sizeof (UINT64) && (TmpBufSize > 0xFFFFFFFF)) {
2844      Status = EFI_DEVICE_ERROR;
2845    } else if (TmpBufSize > 0 && *BufferSize >= (UINTN) TmpBufSize && Buffer != NULL) {
2846      *BufferSize = (UINTN) TmpBufSize;
2847      Status = PxeBc->Mtftp (
2848                        PxeBc,
2849                        EFI_PXE_BASE_CODE_TFTP_READ_FILE,
2850                        Buffer,
2851                        FALSE,
2852                        &TmpBufSize,
2853                        &Private->BlockSize,
2854                        &Private->ServerIp,
2855                        (UINT8 *) Private->BootFileName,
2856                        NULL,
2857                        FALSE
2858                        );
2859    } else if (TmpBufSize > 0) {
2860      *BufferSize = (UINTN) TmpBufSize;
2861      Status      = EFI_BUFFER_TOO_SMALL;
2862    }
2863  } else if (Buffer == NULL || Private->FileSize > *BufferSize) {
2864    *BufferSize = Private->FileSize;
2865    Status      = EFI_BUFFER_TOO_SMALL;
2866  } else {
2867    //
2868    // Download the file.
2869    //
2870    TmpBufSize = (UINT64) (*BufferSize);
2871    Status = PxeBc->Mtftp (
2872                      PxeBc,
2873                      EFI_PXE_BASE_CODE_TFTP_READ_FILE,
2874                      Buffer,
2875                      FALSE,
2876                      &TmpBufSize,
2877                      &Private->BlockSize,
2878                      &Private->ServerIp,
2879                      (UINT8 *) Private->BootFileName,
2880                      NULL,
2881                      FALSE
2882                      );
2883  }
2884  //
2885  // If we added a callback protocol, now is the time to remove it.
2886  //
2887  if (NewMakeCallback) {
2888
2889    NewMakeCallback = FALSE;
2890
2891    PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);
2892
2893    gBS->UninstallProtocolInterface (
2894          Private->Controller,
2895          &gEfiPxeBaseCodeCallbackProtocolGuid,
2896          &Private->LoadFileCallback
2897          );
2898  }
2899
2900  //
2901  // Check download status
2902  //
2903  if (Status == EFI_SUCCESS) {
2904    //
2905    // The DHCP4 can have only one configured child instance so we need to stop
2906    // reset the DHCP4 child before we return. Otherwise the other programs which
2907    // also need to use DHCP4 will be impacted.
2908    // The functionality of PXE Base Code protocol will not be stopped,
2909    // when downloading is successfully.
2910    //
2911    Private->Dhcp4->Stop (Private->Dhcp4);
2912    Private->Dhcp4->Configure (Private->Dhcp4, NULL);
2913    return EFI_SUCCESS;
2914
2915  } else if (Status == EFI_BUFFER_TOO_SMALL) {
2916    if (Buffer != NULL) {
2917      AsciiPrint ("PXE-E05: Download buffer is smaller than requested file.\n");
2918    } else {
2919      //
2920      // The functionality of PXE Base Code protocol will not be stopped.
2921      //
2922      return Status;
2923    }
2924
2925  } else if (Status == EFI_DEVICE_ERROR) {
2926    AsciiPrint ("PXE-E07: Network device error.\n");
2927
2928  } else if (Status == EFI_OUT_OF_RESOURCES) {
2929    AsciiPrint ("PXE-E09: Could not allocate I/O buffers.\n");
2930
2931  } else if (Status == EFI_NO_MEDIA) {
2932    AsciiPrint ("PXE-E12: Could not detect network connection.\n");
2933
2934  } else if (Status == EFI_NO_RESPONSE) {
2935    AsciiPrint ("PXE-E16: No offer received.\n");
2936
2937  } else if (Status == EFI_TIMEOUT) {
2938    AsciiPrint ("PXE-E18: Server response timeout.\n");
2939
2940  } else if (Status == EFI_ABORTED) {
2941    AsciiPrint ("PXE-E21: Remote boot cancelled.\n");
2942
2943  } else if (Status == EFI_ICMP_ERROR) {
2944    AsciiPrint ("PXE-E22: Client received ICMP error from server.\n");
2945
2946  } else if (Status == EFI_TFTP_ERROR) {
2947    AsciiPrint ("PXE-E23: Client received TFTP error from server.\n");
2948
2949  } else {
2950    AsciiPrint ("PXE-E99: Unexpected network error.\n");
2951  }
2952
2953  PxeBc->Stop (PxeBc);
2954
2955  return Status;
2956}
2957
2958EFI_LOAD_FILE_PROTOCOL  mLoadFileProtocolTemplate = { EfiPxeLoadFile };
2959
2960