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