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