1 /** @file
2   This implementation of EFI_PXE_BASE_CODE_PROTOCOL and EFI_LOAD_FILE_PROTOCOL.
3 
4   Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php.
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "PxeBcImpl.h"
17 
18 
19 /**
20   Enables the use of the PXE Base Code Protocol functions.
21 
22   This function enables the use of the PXE Base Code Protocol functions. If the
23   Started field of the EFI_PXE_BASE_CODE_MODE structure is already TRUE, then
24   EFI_ALREADY_STARTED will be returned. If UseIpv6 is TRUE, then IPv6 formatted
25   addresses will be used in this session. If UseIpv6 is FALSE, then IPv4 formatted
26   addresses will be used in this session. If UseIpv6 is TRUE, and the Ipv6Supported
27   field of the EFI_PXE_BASE_CODE_MODE structure is FALSE, then EFI_UNSUPPORTED will
28   be returned. If there is not enough memory or other resources to start the PXE
29   Base Code Protocol, then EFI_OUT_OF_RESOURCES will be returned. Otherwise, the
30   PXE Base Code Protocol will be started.
31 
32   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
33   @param[in]  UseIpv6           Specifies the type of IP addresses that are to be
34                                 used during the session that is being started.
35                                 Set to TRUE for IPv6, and FALSE for IPv4.
36 
37   @retval EFI_SUCCESS           The PXE Base Code Protocol was started.
38   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
39   @retval EFI_UNSUPPORTED       UseIpv6 is TRUE, but the Ipv6Supported field of the
40                                 EFI_PXE_BASE_CODE_MODE structure is FALSE.
41   @retval EFI_ALREADY_STARTED   The PXE Base Code Protocol is already in the started state.
42   @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
43                                 EFI_PXE_BASE_CODE_PROTOCOL structure.
44   @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory or other resources to start the
45                                 PXE Base Code Protocol.
46 
47 **/
48 EFI_STATUS
49 EFIAPI
EfiPxeBcStart(IN EFI_PXE_BASE_CODE_PROTOCOL * This,IN BOOLEAN UseIpv6)50 EfiPxeBcStart (
51   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
52   IN BOOLEAN                          UseIpv6
53   )
54 {
55   PXEBC_PRIVATE_DATA      *Private;
56   EFI_PXE_BASE_CODE_MODE  *Mode;
57   UINTN                   Index;
58   EFI_STATUS              Status;
59 
60   if (This == NULL) {
61     return EFI_INVALID_PARAMETER;
62   }
63 
64   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
65   Mode    = Private->PxeBc.Mode;
66 
67   if (Mode->Started) {
68     return EFI_ALREADY_STARTED;
69   }
70 
71   //
72   // Detect whether using IPv6 or not, and set it into mode data.
73   //
74   if (UseIpv6 && Mode->Ipv6Available && Mode->Ipv6Supported && Private->Ip6Nic != NULL) {
75     Mode->UsingIpv6 = TRUE;
76   } else if (!UseIpv6 && Private->Ip4Nic != NULL) {
77     Mode->UsingIpv6 = FALSE;
78   } else {
79     return EFI_UNSUPPORTED;
80   }
81 
82   if (Mode->UsingIpv6) {
83     AsciiPrint ("\n>>Start PXE over IPv6");
84     //
85     // Configure udp6 instance to receive data.
86     //
87     Status = Private->Udp6Read->Configure (
88                                   Private->Udp6Read,
89                                   &Private->Udp6CfgData
90                                   );
91     if (EFI_ERROR (Status)) {
92       goto ON_ERROR;
93     }
94 
95     //
96     // Configure block size for TFTP as a default value to handle all link layers.
97     //
98     Private->BlockSize = (UINTN) (Private->Ip6MaxPacketSize -
99                            PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE);
100 
101     //
102     // PXE over IPv6 starts here, initialize the fields and list header.
103     //
104     Private->Ip6Policy                          = PXEBC_IP6_POLICY_MAX;
105     Private->ProxyOffer.Dhcp6.Packet.Offer.Size = PXEBC_DHCP6_PACKET_MAX_SIZE;
106     Private->DhcpAck.Dhcp6.Packet.Ack.Size      = PXEBC_DHCP6_PACKET_MAX_SIZE;
107     Private->PxeReply.Dhcp6.Packet.Ack.Size     = PXEBC_DHCP6_PACKET_MAX_SIZE;
108 
109     for (Index = 0; Index < PXEBC_OFFER_MAX_NUM; Index++) {
110       Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size = PXEBC_DHCP6_PACKET_MAX_SIZE;
111     }
112 
113     //
114     // Create event and set status for token to capture ICMP6 error message.
115     //
116     Private->Icmp6Token.Status = EFI_NOT_READY;
117     Status = gBS->CreateEvent (
118                     EVT_NOTIFY_SIGNAL,
119                     TPL_NOTIFY,
120                     PxeBcIcmp6ErrorUpdate,
121                     Private,
122                     &Private->Icmp6Token.Event
123                     );
124     if (EFI_ERROR (Status)) {
125       goto ON_ERROR;
126     }
127 
128     //
129     // Set Ip6 policy to Automatic to start the IP6 router discovery.
130     //
131     Status = PxeBcSetIp6Policy (Private);
132     if (EFI_ERROR (Status)) {
133       goto ON_ERROR;
134     }
135   } else {
136     AsciiPrint ("\n>>Start PXE over IPv4");
137     //
138     // Configure udp4 instance to receive data.
139     //
140     Status = Private->Udp4Read->Configure (
141                                   Private->Udp4Read,
142                                   &Private->Udp4CfgData
143                                   );
144     if (EFI_ERROR (Status)) {
145       goto ON_ERROR;
146     }
147 
148     //
149     // Configure block size for TFTP as a default value to handle all link layers.
150     //
151     Private->BlockSize = (UINTN) (Private->Ip4MaxPacketSize -
152                            PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE);
153 
154     //
155     // PXE over IPv4 starts here, initialize the fields.
156     //
157     Private->ProxyOffer.Dhcp4.Packet.Offer.Size = PXEBC_DHCP4_PACKET_MAX_SIZE;
158     Private->DhcpAck.Dhcp4.Packet.Ack.Size      = PXEBC_DHCP4_PACKET_MAX_SIZE;
159     Private->PxeReply.Dhcp4.Packet.Ack.Size     = PXEBC_DHCP4_PACKET_MAX_SIZE;
160 
161     for (Index = 0; Index < PXEBC_OFFER_MAX_NUM; Index++) {
162       Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = PXEBC_DHCP4_PACKET_MAX_SIZE;
163     }
164 
165     PxeBcSeedDhcp4Packet (&Private->SeedPacket, Private->Udp4Read);
166 
167     //
168     // Create the event for Arp cache update.
169     //
170     Status = gBS->CreateEvent (
171                     EVT_TIMER | EVT_NOTIFY_SIGNAL,
172                     TPL_CALLBACK,
173                     PxeBcArpCacheUpdate,
174                     Private,
175                     &Private->ArpUpdateEvent
176                     );
177     if (EFI_ERROR (Status)) {
178       goto ON_ERROR;
179     }
180 
181     //
182     // Start a periodic timer by second to update Arp cache.
183     //
184     Status = gBS->SetTimer (
185                     Private->ArpUpdateEvent,
186                     TimerPeriodic,
187                     TICKS_PER_SECOND
188                     );
189     if (EFI_ERROR (Status)) {
190       goto ON_ERROR;
191     }
192 
193     //
194     // Create event and set status for token to capture ICMP error message.
195     //
196     Private->Icmp6Token.Status = EFI_NOT_READY;
197     Status = gBS->CreateEvent (
198                     EVT_NOTIFY_SIGNAL,
199                     TPL_NOTIFY,
200                     PxeBcIcmpErrorUpdate,
201                     Private,
202                     &Private->IcmpToken.Event
203                     );
204     if (EFI_ERROR (Status)) {
205       goto ON_ERROR;
206     }
207 
208     //
209     //DHCP4 service allows only one of its children to be configured in
210     //the active state, If the DHCP4 D.O.R.A started by IP4 auto
211     //configuration and has not been completed, the Dhcp4 state machine
212     //will not be in the right state for the PXE to start a new round D.O.R.A.
213     //so we need to switch it's policy to static.
214     //
215     Status = PxeBcSetIp4Policy (Private);
216     if (EFI_ERROR (Status)) {
217       goto ON_ERROR;
218     }
219   }
220 
221   //
222   // If PcdTftpBlockSize is set to non-zero, override the default value.
223   //
224   if (PcdGet64 (PcdTftpBlockSize) != 0) {
225     Private->BlockSize   = (UINTN) PcdGet64 (PcdTftpBlockSize);
226   }
227 
228   //
229   // Create event for UdpRead/UdpWrite timeout since they are both blocking API.
230   //
231   Status = gBS->CreateEvent (
232                   EVT_TIMER,
233                   TPL_CALLBACK,
234                   NULL,
235                   NULL,
236                   &Private->UdpTimeOutEvent
237                   );
238   if (EFI_ERROR (Status)) {
239     goto ON_ERROR;
240   }
241 
242   Private->IsAddressOk = FALSE;
243   Mode->Started        = TRUE;
244 
245   return EFI_SUCCESS;
246 
247 ON_ERROR:
248   if (Mode->UsingIpv6) {
249     if (Private->Icmp6Token.Event != NULL) {
250       gBS->CloseEvent (Private->Icmp6Token.Event);
251       Private->Icmp6Token.Event = NULL;
252     }
253     Private->Udp6Read->Configure (Private->Udp6Read, NULL);
254     Private->Ip6->Configure (Private->Ip6, NULL);
255   } else {
256     if (Private->ArpUpdateEvent != NULL) {
257       gBS->CloseEvent (Private->ArpUpdateEvent);
258       Private->ArpUpdateEvent = NULL;
259     }
260     if (Private->IcmpToken.Event != NULL) {
261       gBS->CloseEvent (Private->IcmpToken.Event);
262       Private->IcmpToken.Event = NULL;
263     }
264     Private->Udp4Read->Configure (Private->Udp4Read, NULL);
265     Private->Ip4->Configure (Private->Ip4, NULL);
266   }
267   return Status;
268 }
269 
270 
271 /**
272   Disable the use of the PXE Base Code Protocol functions.
273 
274   This function stops all activity on the network device. All the resources allocated
275   in Start() are released, the Started field of the EFI_PXE_BASE_CODE_MODE structure is
276   set to FALSE, and EFI_SUCCESS is returned. If the Started field of the EFI_PXE_BASE_CODE_MODE
277   structure is already FALSE, then EFI_NOT_STARTED will be returned.
278 
279   @param[in]  This               Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
280 
281   @retval EFI_SUCCESS           The PXE Base Code Protocol was stopped.
282   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is already in the stopped state.
283   @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
284                                 EFI_PXE_BASE_CODE_PROTOCOL structure.
285   @retval Others
286 
287 **/
288 EFI_STATUS
289 EFIAPI
EfiPxeBcStop(IN EFI_PXE_BASE_CODE_PROTOCOL * This)290 EfiPxeBcStop (
291   IN EFI_PXE_BASE_CODE_PROTOCOL       *This
292   )
293 {
294   PXEBC_PRIVATE_DATA      *Private;
295   EFI_PXE_BASE_CODE_MODE  *Mode;
296   BOOLEAN                 Ipv6Supported;
297   BOOLEAN                 Ipv6Available;
298 
299   if (This == NULL) {
300     return EFI_INVALID_PARAMETER;
301   }
302 
303   Private       = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
304   Mode          = Private->PxeBc.Mode;
305   Ipv6Supported = Mode->Ipv6Supported;
306   Ipv6Available = Mode->Ipv6Available;
307 
308   if (!Mode->Started) {
309     return EFI_NOT_STARTED;
310   }
311 
312   if (Mode->UsingIpv6) {
313     //
314     // Configure all the instances for IPv6 as NULL.
315     //
316     ZeroMem (&Private->Udp6CfgData.StationAddress, sizeof (EFI_IPv6_ADDRESS));
317     ZeroMem (&Private->Ip6CfgData.StationAddress, sizeof (EFI_IPv6_ADDRESS));
318     Private->Dhcp6->Stop (Private->Dhcp6);
319     Private->Dhcp6->Configure (Private->Dhcp6, NULL);
320     Private->Udp6Write->Configure (Private->Udp6Write, NULL);
321     Private->Udp6Read->Groups (Private->Udp6Read, FALSE, NULL);
322     Private->Udp6Read->Configure (Private->Udp6Read, NULL);
323     Private->Ip6->Cancel (Private->Ip6, &Private->Icmp6Token);
324     Private->Ip6->Configure (Private->Ip6, NULL);
325     PxeBcUnregisterIp6Address (Private);
326     if (Private->Icmp6Token.Event != NULL) {
327       gBS->CloseEvent (Private->Icmp6Token.Event);
328       Private->Icmp6Token.Event = NULL;
329     }
330     if (Private->Dhcp6Request != NULL) {
331       FreePool (Private->Dhcp6Request);
332       Private->Dhcp6Request = NULL;
333     }
334     if (Private->BootFileName != NULL) {
335       FreePool (Private->BootFileName);
336       Private->BootFileName = NULL;
337     }
338   } else {
339     //
340     // Configure all the instances for IPv4 as NULL.
341     //
342     ZeroMem (&Private->Udp4CfgData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
343     ZeroMem (&Private->Udp4CfgData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
344     ZeroMem (&Private->Ip4CfgData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
345     ZeroMem (&Private->Ip4CfgData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
346     Private->Dhcp4->Stop (Private->Dhcp4);
347     Private->Dhcp4->Configure (Private->Dhcp4, NULL);
348     Private->Udp4Write->Configure (Private->Udp4Write, NULL);
349     Private->Udp4Read->Groups (Private->Udp4Read, FALSE, NULL);
350     Private->Udp4Read->Configure (Private->Udp4Read, NULL);
351     Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken);
352     Private->Ip4->Configure (Private->Ip4, NULL);
353     if (Private->ArpUpdateEvent != NULL) {
354       gBS->CloseEvent (Private->ArpUpdateEvent);
355       Private->ArpUpdateEvent = NULL;
356     }
357     if (Private->IcmpToken.Event != NULL) {
358       gBS->CloseEvent (Private->IcmpToken.Event);
359       Private->IcmpToken.Event = NULL;
360     }
361     Private->BootFileName = NULL;
362   }
363 
364   gBS->CloseEvent (Private->UdpTimeOutEvent);
365   Private->CurSrcPort   = 0;
366   Private->BootFileSize = 0;
367   Private->SolicitTimes = 0;
368   Private->ElapsedTime  = 0;
369   ZeroMem (&Private->StationIp, sizeof (EFI_IP_ADDRESS));
370   ZeroMem (&Private->SubnetMask, sizeof (EFI_IP_ADDRESS));
371   ZeroMem (&Private->GatewayIp, sizeof (EFI_IP_ADDRESS));
372   ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));
373 
374   //
375   // Reset the mode data.
376   //
377   ZeroMem (Mode, sizeof (EFI_PXE_BASE_CODE_MODE));
378   Mode->Ipv6Available = Ipv6Available;
379   Mode->Ipv6Supported = Ipv6Supported;
380   Mode->AutoArp       = TRUE;
381   Mode->TTL           = DEFAULT_TTL;
382   Mode->ToS           = DEFAULT_ToS;
383 
384   return EFI_SUCCESS;
385 }
386 
387 
388 /**
389   Attempts to complete a DHCPv4 D.O.R.A. (discover / offer / request / acknowledge) or DHCPv6
390   S.A.R.R (solicit / advertise / request / reply) sequence.
391 
392   If SortOffers is TRUE, then the cached DHCP offer packets will be sorted before
393   they are tried. If SortOffers is FALSE, then the cached DHCP offer packets will
394   be tried in the order in which they are received. Please see the Preboot Execution
395   Environment (PXE) Specification and Unified Extensible Firmware Interface (UEFI)
396   Specification for additional details on the implementation of DHCP.
397   If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
398   then the DHCP sequence will be stopped and EFI_ABORTED will be returned.
399 
400   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
401   @param[in]  SortOffers        TRUE if the offers received should be sorted. Set to FALSE to
402                                 try the offers in the order that they are received.
403 
404   @retval EFI_SUCCESS           Valid DHCP has completed.
405   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
406   @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
407                                 EFI_PXE_BASE_CODE_PROTOCOL structure.
408   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
409   @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory to complete the DHCP Protocol.
410   @retval EFI_ABORTED           The callback function aborted the DHCP Protocol.
411   @retval EFI_TIMEOUT           The DHCP Protocol timed out.
412   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the DHCP session.
413   @retval EFI_NO_RESPONSE       Valid PXE offer was not received.
414 
415 **/
416 EFI_STATUS
417 EFIAPI
EfiPxeBcDhcp(IN EFI_PXE_BASE_CODE_PROTOCOL * This,IN BOOLEAN SortOffers)418 EfiPxeBcDhcp (
419   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
420   IN BOOLEAN                          SortOffers
421   )
422 {
423   PXEBC_PRIVATE_DATA           *Private;
424   EFI_PXE_BASE_CODE_MODE       *Mode;
425   EFI_STATUS                   Status;
426   EFI_PXE_BASE_CODE_IP_FILTER  IpFilter;
427 
428   if (This == NULL) {
429     return EFI_INVALID_PARAMETER;
430   }
431 
432   Status                  = EFI_SUCCESS;
433   Private                 = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
434   Mode                    = Private->PxeBc.Mode;
435   Mode->IcmpErrorReceived = FALSE;
436   Private->Function       = EFI_PXE_BASE_CODE_FUNCTION_DHCP;
437   Private->IsOfferSorted  = SortOffers;
438   Private->SolicitTimes   = 0;
439   Private->ElapsedTime    = 0;
440 
441   if (!Mode->Started) {
442     return EFI_NOT_STARTED;
443   }
444 
445   if (Mode->UsingIpv6) {
446 
447     //
448     // Stop Udp6Read instance
449     //
450     Private->Udp6Read->Configure (Private->Udp6Read, NULL);
451 
452     //
453     // Start S.A.R.R. process to get a IPv6 address and other boot information.
454     //
455     Status = PxeBcDhcp6Sarr (Private, Private->Dhcp6);
456   } else {
457 
458     //
459     // Stop Udp4Read instance
460     //
461     Private->Udp4Read->Configure (Private->Udp4Read, NULL);
462 
463     //
464     // Start D.O.R.A. process to get a IPv4 address and other boot information.
465     //
466     Status = PxeBcDhcp4Dora (Private, Private->Dhcp4);
467   }
468 
469   //
470   // Reconfigure the UDP instance with the default configuration.
471   //
472   if (Mode->UsingIpv6) {
473     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);
474   } else {
475     Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
476   }
477   //
478   // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
479   // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
480   //
481   ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
482   IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
483   This->SetIpFilter (This, &IpFilter);
484 
485   return Status;
486 }
487 
488 
489 /**
490   Attempts to complete the PXE Boot Server and/or boot image discovery sequence.
491 
492   This function attempts to complete the PXE Boot Server and/or boot image discovery
493   sequence. If this sequence is completed, then EFI_SUCCESS is returned, and the
494   PxeDiscoverValid, PxeDiscover, PxeReplyReceived, and PxeReply fields of the
495   EFI_PXE_BASE_CODE_MODE structure are filled in. If UseBis is TRUE, then the
496   PxeBisReplyReceived and PxeBisReply fields of the EFI_PXE_BASE_CODE_MODE structure
497   will also be filled in. If UseBis is FALSE, then PxeBisReplyValid will be set to FALSE.
498   In the structure referenced by parameter Info, the PXE Boot Server list, SrvList[],
499   has two uses: It is the Boot Server IP address list used for unicast discovery
500   (if the UseUCast field is TRUE), and it is the list used for Boot Server verification
501   (if the MustUseList field is TRUE). Also, if the MustUseList field in that structure
502   is TRUE and the AcceptAnyResponse field in the SrvList[] array is TRUE, any Boot
503   Server reply of that type will be accepted. If the AcceptAnyResponse field is
504   FALSE, only responses from Boot Servers with matching IP addresses will be accepted.
505   This function can take at least 10 seconds to timeout and return control to the
506   caller. If the Discovery sequence does not complete, then EFI_TIMEOUT will be
507   returned. Please see the Preboot Execution Environment (PXE) Specification for
508   additional details on the implementation of the Discovery sequence.
509   If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
510   then the Discovery sequence is stopped and EFI_ABORTED will be returned.
511 
512   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
513   @param[in]  Type              The type of bootstrap to perform.
514   @param[in]  Layer             Pointer to the boot server layer number to discover, which must be
515                                 PXE_BOOT_LAYER_INITIAL when a new server type is being
516                                 discovered.
517   @param[in]  UseBis            TRUE if Boot Integrity Services are to be used. FALSE otherwise.
518   @param[in]  Info              Pointer to a data structure that contains additional information
519                                 on the type of discovery operation that is to be performed.
520                                 It is optional.
521 
522   @retval EFI_SUCCESS           The Discovery sequence has been completed.
523   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
524   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
525   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
526   @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory to complete Discovery.
527   @retval EFI_ABORTED           The callback function aborted the Discovery sequence.
528   @retval EFI_TIMEOUT           The Discovery sequence timed out.
529   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the PXE discovery
530                                 session.
531 
532 **/
533 EFI_STATUS
534 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)535 EfiPxeBcDiscover (
536   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
537   IN UINT16                           Type,
538   IN UINT16                           *Layer,
539   IN BOOLEAN                          UseBis,
540   IN EFI_PXE_BASE_CODE_DISCOVER_INFO  *Info   OPTIONAL
541   )
542 {
543   PXEBC_PRIVATE_DATA              *Private;
544   EFI_PXE_BASE_CODE_MODE          *Mode;
545   EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;
546   EFI_PXE_BASE_CODE_SRVLIST       *SrvList;
547   PXEBC_BOOT_SVR_ENTRY            *BootSvrEntry;
548   UINT16                          Index;
549   EFI_STATUS                      Status;
550   EFI_PXE_BASE_CODE_IP_FILTER     IpFilter;
551   EFI_PXE_BASE_CODE_DISCOVER_INFO *NewCreatedInfo;
552 
553   if (This == NULL) {
554     return EFI_INVALID_PARAMETER;
555   }
556 
557   Private                 = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
558   Mode                    = Private->PxeBc.Mode;
559   Mode->IcmpErrorReceived = FALSE;
560   BootSvrEntry            = NULL;
561   SrvList                 = NULL;
562   Status                  = EFI_DEVICE_ERROR;
563   Private->Function       = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;
564   NewCreatedInfo          = NULL;
565 
566   if (!Mode->Started) {
567     return EFI_NOT_STARTED;
568   }
569 
570   //
571   // Station address should be ready before do discover.
572   //
573   if (!Private->IsAddressOk) {
574     return EFI_INVALID_PARAMETER;
575   }
576 
577   if (Mode->UsingIpv6) {
578 
579     //
580     // Stop Udp6Read instance
581     //
582     Private->Udp6Read->Configure (Private->Udp6Read, NULL);
583   } else {
584 
585     //
586     // Stop Udp4Read instance
587     //
588     Private->Udp4Read->Configure (Private->Udp4Read, NULL);
589   }
590 
591   //
592   // There are 3 methods to get the information for discover.
593   //
594   ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));
595   if (*Layer != EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) {
596     //
597     // 1. Take the previous setting as the discover info.
598     //
599     if (!Mode->PxeDiscoverValid ||
600         !Mode->PxeReplyReceived ||
601         (!Mode->PxeBisReplyReceived && UseBis)) {
602       Status = EFI_INVALID_PARAMETER;
603       goto ON_EXIT;
604     }
605 
606     Info                         = &DefaultInfo;
607     Info->IpCnt                  = 1;
608     Info->UseUCast               = TRUE;
609     SrvList                      = Info->SrvList;
610     SrvList[0].Type              = Type;
611     SrvList[0].AcceptAnyResponse = FALSE;
612 
613     CopyMem (&SrvList->IpAddr, &Private->ServerIp, sizeof (EFI_IP_ADDRESS));
614 
615   } else if (Info == NULL) {
616     //
617     // 2. Extract the discover information from the cached packets if unspecified.
618     //
619     NewCreatedInfo = &DefaultInfo;
620     Status = PxeBcExtractDiscoverInfo (Private, Type, &NewCreatedInfo, &BootSvrEntry, &SrvList);
621     if (EFI_ERROR (Status)) {
622       goto ON_EXIT;
623     }
624     ASSERT (NewCreatedInfo != NULL);
625     Info = NewCreatedInfo;
626   } else {
627     //
628     // 3. Take the pass-in information as the discover info, and validate the server list.
629     //
630     SrvList = Info->SrvList;
631 
632     if (!SrvList[0].AcceptAnyResponse) {
633       for (Index = 1; Index < Info->IpCnt; Index++) {
634         if (SrvList[Index].AcceptAnyResponse) {
635           break;
636         }
637       }
638       if (Index != Info->IpCnt) {
639         //
640         // It's invalid if the first server doesn't accecpt any response
641         // but any of the other servers does accept any response.
642         //
643         Status = EFI_INVALID_PARAMETER;
644         goto ON_EXIT;
645       }
646     }
647   }
648 
649   //
650   // Info and BootSvrEntry/SrvList are all ready by now, so execute discover by UniCast/BroadCast/MultiCast.
651   //
652   if ((!Info->UseUCast && !Info->UseBCast && !Info->UseMCast) ||
653       (Info->MustUseList && Info->IpCnt == 0)) {
654     Status = EFI_INVALID_PARAMETER;
655     goto ON_EXIT;
656   }
657 
658   Private->IsDoDiscover = TRUE;
659 
660   if (Info->UseMCast) {
661     //
662     // Do discover by multicast.
663     //
664     Status = PxeBcDiscoverBootServer (
665                Private,
666                Type,
667                Layer,
668                UseBis,
669                &Info->ServerMCastIp,
670                Info->IpCnt,
671                SrvList
672                );
673 
674   } else if (Info->UseBCast) {
675     //
676     // Do discover by broadcast, but only valid for IPv4.
677     //
678     ASSERT (!Mode->UsingIpv6);
679     Status = PxeBcDiscoverBootServer (
680                Private,
681                Type,
682                Layer,
683                UseBis,
684                NULL,
685                Info->IpCnt,
686                SrvList
687                );
688 
689   } else if (Info->UseUCast) {
690     //
691     // Do discover by unicast.
692     //
693     for (Index = 0; Index < Info->IpCnt; Index++) {
694       if (BootSvrEntry == NULL) {
695         CopyMem (&Private->ServerIp, &SrvList[Index].IpAddr, sizeof (EFI_IP_ADDRESS));
696       } else {
697         ASSERT (!Mode->UsingIpv6);
698         ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));
699         CopyMem (&Private->ServerIp, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));
700       }
701 
702       Status = PxeBcDiscoverBootServer (
703                  Private,
704                  Type,
705                  Layer,
706                  UseBis,
707                  &Private->ServerIp,
708                  Info->IpCnt,
709                  SrvList
710                  );
711       }
712   }
713 
714   if (!EFI_ERROR (Status)) {
715     //
716     // Parse the cached PXE reply packet, and store it into mode data if valid.
717     //
718     if (Mode->UsingIpv6) {
719       Status = PxeBcParseDhcp6Packet (&Private->PxeReply.Dhcp6);
720       if (!EFI_ERROR (Status)) {
721         CopyMem (
722           &Mode->PxeReply.Dhcpv6,
723           &Private->PxeReply.Dhcp6.Packet.Ack.Dhcp6,
724           Private->PxeReply.Dhcp6.Packet.Ack.Length
725           );
726         Mode->PxeReplyReceived = TRUE;
727         Mode->PxeDiscoverValid = TRUE;
728       }
729     } else {
730       Status = PxeBcParseDhcp4Packet (&Private->PxeReply.Dhcp4);
731       if (!EFI_ERROR (Status)) {
732         CopyMem (
733           &Mode->PxeReply.Dhcpv4,
734           &Private->PxeReply.Dhcp4.Packet.Ack.Dhcp4,
735           Private->PxeReply.Dhcp4.Packet.Ack.Length
736           );
737         Mode->PxeReplyReceived = TRUE;
738         Mode->PxeDiscoverValid = TRUE;
739       }
740     }
741   }
742 
743 ON_EXIT:
744 
745   if (NewCreatedInfo != NULL && NewCreatedInfo != &DefaultInfo) {
746     FreePool (NewCreatedInfo);
747   }
748 
749   if (Mode->UsingIpv6) {
750     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);
751   } else {
752     Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
753   }
754 
755   //
756   // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
757   // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
758   //
759   ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
760   IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
761   This->SetIpFilter (This, &IpFilter);
762 
763   return Status;
764 }
765 
766 
767 /**
768   Used to perform TFTP and MTFTP services.
769 
770   This function is used to perform TFTP and MTFTP services. This includes the
771   TFTP operations to get the size of a file, read a directory, read a file, and
772   write a file. It also includes the MTFTP operations to get the size of a file,
773   read a directory, and read a file. The type of operation is specified by Operation.
774   If the callback function that is invoked during the TFTP/MTFTP operation does
775   not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED will
776   be returned.
777   For read operations, the return data will be placed in the buffer specified by
778   BufferPtr. If BufferSize is too small to contain the entire downloaded file,
779   then EFI_BUFFER_TOO_SMALL will be returned and BufferSize will be set to zero,
780   or the size of the requested file. (NOTE: the size of the requested file is only returned
781   if the TFTP server supports TFTP options). If BufferSize is large enough for the
782   read operation, then BufferSize will be set to the size of the downloaded file,
783   and EFI_SUCCESS will be returned. Applications using the PxeBc.Mtftp() services
784   should use the get-file-size operations to determine the size of the downloaded
785   file prior to using the read-file operations-especially when downloading large
786   (greater than 64 MB) files-instead of making two calls to the read-file operation.
787   Following this recommendation will save time if the file is larger than expected
788   and the TFTP server does not support TFTP option extensions. Without TFTP option
789   extension support, the client must download the entire file, counting and discarding
790   the received packets, to determine the file size.
791   For write operations, the data to be sent is in the buffer specified by BufferPtr.
792   BufferSize specifies the number of bytes to send. If the write operation completes
793   successfully, then EFI_SUCCESS will be returned.
794   For TFTP "get file size" operations, the size of the requested file or directory
795   is returned in BufferSize, and EFI_SUCCESS will be returned. If the TFTP server
796   does not support options, the file will be downloaded into a bit bucket and the
797   length of the downloaded file will be returned. For MTFTP "get file size" operations,
798   if the MTFTP server does not support the "get file size" option, EFI_UNSUPPORTED
799   will be returned.
800   This function can take up to 10 seconds to timeout and return control to the caller.
801   If the TFTP sequence does not complete, EFI_TIMEOUT will be returned.
802   If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
803   then the TFTP sequence is stopped and EFI_ABORTED will be returned.
804 
805   @param[in]      This          Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
806   @param[in]      Operation     The type of operation to perform.
807   @param[in, out] BufferPtr     A pointer to the data buffer.
808   @param[in]      Overwrite     Only used on write file operations. TRUE if a file on a remote
809                                 server can be overwritten.
810   @param[in, out] BufferSize    For get-file-size operations, *BufferSize returns the size of the
811                                 requested file.
812   @param[in]      BlockSize     The requested block size to be used during a TFTP transfer.
813   @param[in]      ServerIp      The TFTP / MTFTP server IP address.
814   @param[in]      Filename      A Null-terminated ASCII string that specifies a directory name
815                                 or a file name.
816   @param[in]      Info          Pointer to the MTFTP information.
817   @param[in]      DontUseBuffer Set to FALSE for normal TFTP and MTFTP read file operation.
818 
819   @retval EFI_SUCCESS           The TFTP/MTFTP operation was completed.
820   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
821   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
822   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
823   @retval EFI_BUFFER_TOO_SMALL  The buffer is not large enough to complete the read operation.
824   @retval EFI_ABORTED           The callback function aborted the TFTP/MTFTP operation.
825   @retval EFI_TIMEOUT           The TFTP/MTFTP operation timed out.
826   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the MTFTP session.
827   @retval EFI_TFTP_ERROR        A TFTP error packet was received during the MTFTP session.
828 
829 **/
830 EFI_STATUS
831 EFIAPI
EfiPxeBcMtftp(IN EFI_PXE_BASE_CODE_PROTOCOL * This,IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,IN OUT VOID * BufferPtr OPTIONAL,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)832 EfiPxeBcMtftp (
833   IN     EFI_PXE_BASE_CODE_PROTOCOL       *This,
834   IN     EFI_PXE_BASE_CODE_TFTP_OPCODE    Operation,
835   IN OUT VOID                             *BufferPtr    OPTIONAL,
836   IN     BOOLEAN                          Overwrite,
837   IN OUT UINT64                           *BufferSize,
838   IN     UINTN                            *BlockSize    OPTIONAL,
839   IN     EFI_IP_ADDRESS                   *ServerIp,
840   IN     UINT8                            *Filename,
841   IN     EFI_PXE_BASE_CODE_MTFTP_INFO     *Info         OPTIONAL,
842   IN     BOOLEAN                          DontUseBuffer
843   )
844 {
845   PXEBC_PRIVATE_DATA              *Private;
846   EFI_PXE_BASE_CODE_MODE          *Mode;
847   EFI_MTFTP4_CONFIG_DATA          Mtftp4Config;
848   EFI_MTFTP6_CONFIG_DATA          Mtftp6Config;
849   VOID                            *Config;
850   EFI_STATUS                      Status;
851   EFI_PXE_BASE_CODE_IP_FILTER     IpFilter;
852 
853 
854   if ((This == NULL) ||
855       (Filename == NULL) ||
856       (BufferSize == NULL) ||
857       (ServerIp == NULL) ||
858       ((BufferPtr == NULL) && DontUseBuffer) ||
859       ((BlockSize != NULL) && (*BlockSize < PXE_MTFTP_DEFAULT_BLOCK_SIZE)) ||
860       (!NetIp4IsUnicast (NTOHL (ServerIp->Addr[0]), 0) && !NetIp6IsValidUnicast (&ServerIp->v6))) {
861     return EFI_INVALID_PARAMETER;
862   }
863 
864   Config    = NULL;
865   Status    = EFI_DEVICE_ERROR;
866   Private   = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
867   Mode      = Private->PxeBc.Mode;
868 
869   if (Mode->UsingIpv6) {
870     //
871     // Set configuration data for Mtftp6 instance.
872     //
873     ZeroMem (&Mtftp6Config, sizeof (EFI_MTFTP6_CONFIG_DATA));
874     Config                         = &Mtftp6Config;
875     Mtftp6Config.TimeoutValue      = PXEBC_MTFTP_TIMEOUT;
876     Mtftp6Config.TryCount          = PXEBC_MTFTP_RETRIES;
877     CopyMem (&Mtftp6Config.StationIp, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
878     CopyMem (&Mtftp6Config.ServerIp, &ServerIp->v6, sizeof (EFI_IPv6_ADDRESS));
879     //
880     // Stop Udp6Read instance
881     //
882     Private->Udp6Read->Configure (Private->Udp6Read, NULL);
883   } else {
884     //
885     // Set configuration data for Mtftp4 instance.
886     //
887     ZeroMem (&Mtftp4Config, sizeof (EFI_MTFTP4_CONFIG_DATA));
888     Config                         = &Mtftp4Config;
889     Mtftp4Config.UseDefaultSetting = FALSE;
890     Mtftp4Config.TimeoutValue      = PXEBC_MTFTP_TIMEOUT;
891     Mtftp4Config.TryCount          = PXEBC_MTFTP_RETRIES;
892     CopyMem (&Mtftp4Config.StationIp, &Private->StationIp.v4, sizeof (EFI_IPv4_ADDRESS));
893     CopyMem (&Mtftp4Config.SubnetMask, &Private->SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS));
894     CopyMem (&Mtftp4Config.GatewayIp, &Private->GatewayIp.v4, sizeof (EFI_IPv4_ADDRESS));
895     CopyMem (&Mtftp4Config.ServerIp, &ServerIp->v4, sizeof (EFI_IPv4_ADDRESS));
896     //
897     // Stop Udp4Read instance
898     //
899     Private->Udp4Read->Configure (Private->Udp4Read, NULL);
900   }
901 
902   Mode->TftpErrorReceived = FALSE;
903   Mode->IcmpErrorReceived = FALSE;
904 
905   switch (Operation) {
906 
907   case EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE:
908     //
909     // Send TFTP request to get file size.
910     //
911     Status = PxeBcTftpGetFileSize (
912                Private,
913                Config,
914                Filename,
915                BlockSize,
916                BufferSize
917                );
918 
919     break;
920 
921   case EFI_PXE_BASE_CODE_TFTP_READ_FILE:
922     //
923     // Send TFTP request to read file.
924     //
925     Status = PxeBcTftpReadFile (
926                Private,
927                Config,
928                Filename,
929                BlockSize,
930                BufferPtr,
931                BufferSize,
932                DontUseBuffer
933                );
934 
935     break;
936 
937   case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:
938     //
939     // Send TFTP request to write file.
940     //
941     Status = PxeBcTftpWriteFile (
942                Private,
943                Config,
944                Filename,
945                Overwrite,
946                BlockSize,
947                BufferPtr,
948                BufferSize
949                );
950 
951     break;
952 
953   case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:
954     //
955     // Send TFTP request to read directory.
956     //
957     Status = PxeBcTftpReadDirectory (
958                Private,
959                Config,
960                Filename,
961                BlockSize,
962                BufferPtr,
963                BufferSize,
964                DontUseBuffer
965                );
966 
967     break;
968 
969   case EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE:
970   case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:
971   case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:
972     Status = EFI_UNSUPPORTED;
973 
974     break;
975 
976   default:
977     Status = EFI_INVALID_PARAMETER;
978 
979     break;
980   }
981 
982   if (Status == EFI_ICMP_ERROR) {
983     Mode->IcmpErrorReceived = TRUE;
984   }
985 
986   //
987   // Reconfigure the UDP instance with the default configuration.
988   //
989   if (Mode->UsingIpv6) {
990     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);
991   } else {
992     Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
993   }
994   //
995   // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
996   // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
997   //
998   ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
999   IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
1000   This->SetIpFilter (This, &IpFilter);
1001 
1002   return Status;
1003 }
1004 
1005 
1006 /**
1007   Writes a UDP packet to the network interface.
1008 
1009   This function writes a UDP packet specified by the (optional HeaderPtr and)
1010   BufferPtr parameters to the network interface. The UDP header is automatically
1011   built by this routine. It uses the parameters OpFlags, DestIp, DestPort, GatewayIp,
1012   SrcIp, and SrcPort to build this header. If the packet is successfully built and
1013   transmitted through the network interface, then EFI_SUCCESS will be returned.
1014   If a timeout occurs during the transmission of the packet, then EFI_TIMEOUT will
1015   be returned. If an ICMP error occurs during the transmission of the packet, then
1016   the IcmpErrorReceived field is set to TRUE, the IcmpError field is filled in and
1017   EFI_ICMP_ERROR will be returned. If the Callback Protocol does not return
1018   EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED will be returned.
1019 
1020   @param[in]      This          Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
1021   @param[in]      OpFlags       The UDP operation flags.
1022   @param[in]      DestIp        The destination IP address.
1023   @param[in]      DestPort      The destination UDP port number.
1024   @param[in]      GatewayIp     The gateway IP address.
1025   @param[in]      SrcIp         The source IP address.
1026   @param[in, out] SrcPort       The source UDP port number.
1027   @param[in]      HeaderSize    An optional field which may be set to the length of a header
1028                                 at HeaderPtr to be prefixed to the data at BufferPtr.
1029   @param[in]  HeaderPtr         If HeaderSize is not NULL, a pointer to a header to be
1030                                 prefixed to the data at BufferPtr.
1031   @param[in]  BufferSize        A pointer to the size of the data at BufferPtr.
1032   @param[in]  BufferPtr         A pointer to the data to be written.
1033 
1034   @retval EFI_SUCCESS           The UDP Write operation completed.
1035   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
1036   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1037   @retval EFI_BAD_BUFFER_SIZE   The buffer is too long to be transmitted.
1038   @retval EFI_ABORTED           The callback function aborted the UDP Write operation.
1039   @retval EFI_TIMEOUT           The UDP Write operation timed out.
1040   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the UDP write session.
1041 
1042 **/
1043 EFI_STATUS
1044 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)1045 EfiPxeBcUdpWrite (
1046   IN     EFI_PXE_BASE_CODE_PROTOCOL       *This,
1047   IN     UINT16                           OpFlags,
1048   IN     EFI_IP_ADDRESS                   *DestIp,
1049   IN     EFI_PXE_BASE_CODE_UDP_PORT       *DestPort,
1050   IN     EFI_IP_ADDRESS                   *GatewayIp  OPTIONAL,
1051   IN     EFI_IP_ADDRESS                   *SrcIp      OPTIONAL,
1052   IN OUT EFI_PXE_BASE_CODE_UDP_PORT       *SrcPort    OPTIONAL,
1053   IN     UINTN                            *HeaderSize OPTIONAL,
1054   IN     VOID                             *HeaderPtr  OPTIONAL,
1055   IN     UINTN                            *BufferSize,
1056   IN     VOID                             *BufferPtr
1057   )
1058 {
1059   PXEBC_PRIVATE_DATA        *Private;
1060   EFI_PXE_BASE_CODE_MODE    *Mode;
1061   EFI_UDP4_SESSION_DATA     Udp4Session;
1062   EFI_UDP6_SESSION_DATA     Udp6Session;
1063   EFI_STATUS                Status;
1064   BOOLEAN                   DoNotFragment;
1065 
1066   if (This == NULL || DestIp == NULL || DestPort == NULL) {
1067     return EFI_INVALID_PARAMETER;
1068   }
1069 
1070   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1071   Mode    = Private->PxeBc.Mode;
1072 
1073   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT) != 0) {
1074     DoNotFragment = FALSE;
1075   } else {
1076     DoNotFragment = TRUE;
1077   }
1078 
1079   if (!Mode->UsingIpv6 && GatewayIp != NULL && !NetIp4IsUnicast (NTOHL (GatewayIp->Addr[0]), 0)) {
1080     //
1081     // Gateway is provided but it's not a unicast IPv4 address, while it will be ignored for IPv6.
1082     //
1083     return EFI_INVALID_PARAMETER;
1084   }
1085 
1086   if (HeaderSize != NULL && (*HeaderSize == 0 || HeaderPtr == NULL)) {
1087     return EFI_INVALID_PARAMETER;
1088   }
1089 
1090   if (BufferSize == NULL || (*BufferSize != 0 && BufferPtr == NULL)) {
1091     return EFI_INVALID_PARAMETER;
1092   }
1093 
1094   if (!Mode->Started) {
1095     return EFI_NOT_STARTED;
1096   }
1097 
1098   if (!Private->IsAddressOk && SrcIp == NULL) {
1099     return EFI_INVALID_PARAMETER;
1100   }
1101 
1102   if (Private->CurSrcPort == 0 ||
1103       (SrcPort != NULL && *SrcPort != Private->CurSrcPort)) {
1104     //
1105     // Reconfigure UDPv4/UDPv6 for UdpWrite if the source port changed.
1106     //
1107     if (SrcPort != NULL) {
1108       Private->CurSrcPort = *SrcPort;
1109     }
1110   }
1111 
1112   if (Mode->UsingIpv6) {
1113     Status = PxeBcConfigUdp6Write (
1114                Private->Udp6Write,
1115                &Private->StationIp.v6,
1116                &Private->CurSrcPort
1117                );
1118   } else {
1119     //
1120     // Configure the UDPv4 instance with gateway information from DHCP server as default.
1121     //
1122     Status = PxeBcConfigUdp4Write (
1123                Private->Udp4Write,
1124                &Private->StationIp.v4,
1125                &Private->SubnetMask.v4,
1126                &Private->GatewayIp.v4,
1127                &Private->CurSrcPort,
1128                DoNotFragment
1129                );
1130   }
1131 
1132   if (EFI_ERROR (Status)) {
1133     Private->CurSrcPort = 0;
1134     return EFI_INVALID_PARAMETER;
1135   } else if (SrcPort != NULL) {
1136     *SrcPort = Private->CurSrcPort;
1137   }
1138 
1139   //
1140   // Start a timer as timeout event for this blocking API.
1141   //
1142   gBS->SetTimer (Private->UdpTimeOutEvent, TimerRelative, PXEBC_UDP_TIMEOUT);
1143 
1144   if (Mode->UsingIpv6) {
1145     //
1146     // Construct UDPv6 session data.
1147     //
1148     ZeroMem (&Udp6Session, sizeof (EFI_UDP6_SESSION_DATA));
1149     CopyMem (&Udp6Session.DestinationAddress, DestIp, sizeof (EFI_IPv6_ADDRESS));
1150     Udp6Session.DestinationPort = *DestPort;
1151     if (SrcIp != NULL) {
1152       CopyMem (&Udp6Session.SourceAddress, SrcIp, sizeof (EFI_IPv6_ADDRESS));
1153     }
1154     if (SrcPort != NULL) {
1155       Udp6Session.SourcePort = *SrcPort;
1156     }
1157 
1158     Status = PxeBcUdp6Write (
1159                Private->Udp6Write,
1160                &Udp6Session,
1161                Private->UdpTimeOutEvent,
1162                HeaderSize,
1163                HeaderPtr,
1164                BufferSize,
1165                BufferPtr
1166                );
1167   } else {
1168     //
1169     // Construct UDPv4 session data.
1170     //
1171     ZeroMem (&Udp4Session, sizeof (EFI_UDP4_SESSION_DATA));
1172     CopyMem (&Udp4Session.DestinationAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
1173     Udp4Session.DestinationPort = *DestPort;
1174     if (SrcIp != NULL) {
1175       CopyMem (&Udp4Session.SourceAddress, SrcIp, sizeof (EFI_IPv4_ADDRESS));
1176     }
1177     if (SrcPort != NULL) {
1178       Udp4Session.SourcePort = *SrcPort;
1179     }
1180     //
1181     // Override the gateway information if user specified.
1182     //
1183     Status = PxeBcUdp4Write (
1184                Private->Udp4Write,
1185                &Udp4Session,
1186                Private->UdpTimeOutEvent,
1187                (EFI_IPv4_ADDRESS *) GatewayIp,
1188                HeaderSize,
1189                HeaderPtr,
1190                BufferSize,
1191                BufferPtr
1192                );
1193   }
1194 
1195   gBS->SetTimer (Private->UdpTimeOutEvent, TimerCancel, 0);
1196 
1197 
1198   //
1199   // Reset the UdpWrite instance.
1200   //
1201   if (Mode->UsingIpv6) {
1202     Private->Udp6Write->Configure (Private->Udp6Write, NULL);
1203   } else {
1204     Private->Udp4Write->Configure (Private->Udp4Write, NULL);
1205   }
1206 
1207   return Status;
1208 }
1209 
1210 
1211 /**
1212   Reads a UDP packet from the network interface.
1213 +
1214   This function reads a UDP packet from a network interface. The data contents
1215   are returned in (the optional HeaderPtr and) BufferPtr, and the size of the
1216   buffer received is returned in BufferSize . If the input BufferSize is smaller
1217   than the UDP packet received (less optional HeaderSize), it will be set to the
1218   required size, and EFI_BUFFER_TOO_SMALL will be returned. In this case, the
1219   contents of BufferPtr are undefined, and the packet is lost. If a UDP packet is
1220   successfully received, then EFI_SUCCESS will be returned, and the information
1221   from the UDP header will be returned in DestIp, DestPort, SrcIp, and SrcPort if
1222   they are not NULL. Depending on the values of OpFlags and the DestIp, DestPort,
1223   SrcIp, and SrcPort input values, different types of UDP packet receive filtering
1224   will be performed. The following tables summarize these receive filter operations.
1225 
1226   @param[in]      This          Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
1227   @param[in]      OpFlags       The UDP operation flags.
1228   @param[in, out] DestIp        The destination IP address.
1229   @param[in, out] DestPort      The destination UDP port number.
1230   @param[in, out] SrcIp         The source IP address.
1231   @param[in, out] SrcPort       The source UDP port number.
1232   @param[in]      HeaderSize    An optional field which may be set to the length of a
1233                                 header at HeaderPtr to be prefixed to the data at BufferPtr.
1234   @param[in]      HeaderPtr     If HeaderSize is not NULL, a pointer to a header to be
1235                                 prefixed to the data at BufferPtr.
1236   @param[in, out] BufferSize    A pointer to the size of the data at BufferPtr.
1237   @param[in]      BufferPtr     A pointer to the data to be read.
1238 
1239   @retval EFI_SUCCESS           The UDP Read operation was completed.
1240   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
1241   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1242   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
1243   @retval EFI_BUFFER_TOO_SMALL  The packet is larger than Buffer can hold.
1244   @retval EFI_ABORTED           The callback function aborted the UDP Read operation.
1245   @retval EFI_TIMEOUT           The UDP Read operation timed out.
1246 
1247 **/
1248 EFI_STATUS
1249 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)1250 EfiPxeBcUdpRead (
1251   IN     EFI_PXE_BASE_CODE_PROTOCOL   *This,
1252   IN     UINT16                       OpFlags,
1253   IN OUT EFI_IP_ADDRESS               *DestIp      OPTIONAL,
1254   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *DestPort    OPTIONAL,
1255   IN OUT EFI_IP_ADDRESS               *SrcIp       OPTIONAL,
1256   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *SrcPort     OPTIONAL,
1257   IN     UINTN                        *HeaderSize  OPTIONAL,
1258   IN     VOID                         *HeaderPtr   OPTIONAL,
1259   IN OUT UINTN                        *BufferSize,
1260   IN     VOID                         *BufferPtr
1261   )
1262 {
1263   PXEBC_PRIVATE_DATA          *Private;
1264   EFI_PXE_BASE_CODE_MODE      *Mode;
1265   EFI_UDP4_COMPLETION_TOKEN   Udp4Token;
1266   EFI_UDP6_COMPLETION_TOKEN   Udp6Token;
1267   EFI_UDP4_RECEIVE_DATA       *Udp4Rx;
1268   EFI_UDP6_RECEIVE_DATA       *Udp6Rx;
1269   EFI_STATUS                  Status;
1270   BOOLEAN                     IsDone;
1271   BOOLEAN                     IsMatched;
1272   UINTN                       CopiedLen;
1273   UINTN                       HeaderLen;
1274   UINTN                       HeaderCopiedLen;
1275   UINTN                       BufferCopiedLen;
1276   UINT32                      FragmentLength;
1277   UINTN                       FragmentIndex;
1278   UINT8                       *FragmentBuffer;
1279 
1280   if (This == NULL) {
1281     return EFI_INVALID_PARAMETER;
1282   }
1283 
1284   Private   = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1285   Mode      = Private->PxeBc.Mode;
1286   IsDone    = FALSE;
1287   IsMatched = FALSE;
1288   Udp4Rx    = NULL;
1289   Udp6Rx    = NULL;
1290 
1291   if (((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) == 0 && DestPort == NULL) ||
1292       ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) == 0 && SrcIp == NULL) ||
1293       ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) == 0 && SrcPort == NULL)) {
1294     return EFI_INVALID_PARAMETER;
1295   }
1296 
1297   if ((HeaderSize != NULL && *HeaderSize == 0) || (HeaderSize != NULL && HeaderPtr == NULL)) {
1298     return EFI_INVALID_PARAMETER;
1299   }
1300 
1301   if ((BufferSize == NULL) || (BufferPtr == NULL)) {
1302     return EFI_INVALID_PARAMETER;
1303   }
1304 
1305   if (!Mode->Started) {
1306     return EFI_NOT_STARTED;
1307   }
1308 
1309   ZeroMem (&Udp6Token, sizeof (EFI_UDP6_COMPLETION_TOKEN));
1310   ZeroMem (&Udp4Token, sizeof (EFI_UDP4_COMPLETION_TOKEN));
1311 
1312   if (Mode->UsingIpv6) {
1313     Status = gBS->CreateEvent (
1314                     EVT_NOTIFY_SIGNAL,
1315                     TPL_NOTIFY,
1316                     PxeBcCommonNotify,
1317                     &IsDone,
1318                     &Udp6Token.Event
1319                     );
1320     if (EFI_ERROR (Status)) {
1321       return EFI_OUT_OF_RESOURCES;
1322     }
1323   } else {
1324     Status = gBS->CreateEvent (
1325                     EVT_NOTIFY_SIGNAL,
1326                     TPL_NOTIFY,
1327                     PxeBcCommonNotify,
1328                     &IsDone,
1329                     &Udp4Token.Event
1330                     );
1331     if (EFI_ERROR (Status)) {
1332       return EFI_OUT_OF_RESOURCES;
1333     }
1334   }
1335 
1336   //
1337   // Start a timer as timeout event for this blocking API.
1338   //
1339   gBS->SetTimer (Private->UdpTimeOutEvent, TimerRelative, PXEBC_UDP_TIMEOUT);
1340   Mode->IcmpErrorReceived = FALSE;
1341 
1342   //
1343   // Read packet by Udp4Read/Udp6Read until matched or timeout.
1344   //
1345   while (!IsMatched && !EFI_ERROR (Status)) {
1346     if (Mode->UsingIpv6) {
1347       Status = PxeBcUdp6Read (
1348                  Private->Udp6Read,
1349                  &Udp6Token,
1350                  Mode,
1351                  Private->UdpTimeOutEvent,
1352                  OpFlags,
1353                  &IsDone,
1354                  &IsMatched,
1355                  DestIp,
1356                  DestPort,
1357                  SrcIp,
1358                  SrcPort
1359                  );
1360     } else {
1361       Status = PxeBcUdp4Read (
1362                  Private->Udp4Read,
1363                  &Udp4Token,
1364                  Mode,
1365                  Private->UdpTimeOutEvent,
1366                  OpFlags,
1367                  &IsDone,
1368                  &IsMatched,
1369                  DestIp,
1370                  DestPort,
1371                  SrcIp,
1372                  SrcPort
1373                  );
1374     }
1375   }
1376 
1377   if (Status == EFI_ICMP_ERROR ||
1378       Status == EFI_NETWORK_UNREACHABLE ||
1379       Status == EFI_HOST_UNREACHABLE ||
1380       Status == EFI_PROTOCOL_UNREACHABLE ||
1381       Status == EFI_PORT_UNREACHABLE) {
1382     //
1383     // Get different return status for icmp error from Udp, refers to UEFI spec.
1384     //
1385     Mode->IcmpErrorReceived = TRUE;
1386   }
1387   gBS->SetTimer (Private->UdpTimeOutEvent, TimerCancel, 0);
1388 
1389   if (IsMatched) {
1390     //
1391     // Copy the rececived packet to user if matched by filter.
1392     //
1393     if (Mode->UsingIpv6) {
1394       Udp6Rx = Udp6Token.Packet.RxData;
1395       ASSERT (Udp6Rx != NULL);
1396 
1397       HeaderLen = 0;
1398       if (HeaderSize != NULL) {
1399         HeaderLen = MIN (*HeaderSize, Udp6Rx->DataLength);
1400       }
1401 
1402       if (Udp6Rx->DataLength - HeaderLen > *BufferSize) {
1403         Status = EFI_BUFFER_TOO_SMALL;
1404       } else {
1405         if (HeaderSize != NULL) {
1406           *HeaderSize = HeaderLen;
1407         }
1408         *BufferSize = Udp6Rx->DataLength - HeaderLen;
1409 
1410         HeaderCopiedLen = 0;
1411         BufferCopiedLen = 0;
1412         for (FragmentIndex = 0; FragmentIndex < Udp6Rx->FragmentCount; FragmentIndex++) {
1413           FragmentLength = Udp6Rx->FragmentTable[FragmentIndex].FragmentLength;
1414           FragmentBuffer = Udp6Rx->FragmentTable[FragmentIndex].FragmentBuffer;
1415           if (HeaderCopiedLen + FragmentLength < HeaderLen) {
1416             //
1417             // Copy the header part of received data.
1418             //
1419             CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, FragmentLength);
1420             HeaderCopiedLen += FragmentLength;
1421           } else if (HeaderCopiedLen < HeaderLen) {
1422             //
1423             // Copy the header part of received data.
1424             //
1425             CopiedLen = HeaderLen - HeaderCopiedLen;
1426             CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, CopiedLen);
1427             HeaderCopiedLen += CopiedLen;
1428 
1429             //
1430             // Copy the other part of received data.
1431             //
1432             CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer + CopiedLen, FragmentLength - CopiedLen);
1433             BufferCopiedLen += (FragmentLength - CopiedLen);
1434           } else {
1435             //
1436             // Copy the other part of received data.
1437             //
1438             CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer, FragmentLength);
1439             BufferCopiedLen += FragmentLength;
1440           }
1441         }
1442       }
1443       //
1444       // Recycle the receiving buffer after copy to user.
1445       //
1446       gBS->SignalEvent (Udp6Rx->RecycleSignal);
1447     } else {
1448       Udp4Rx = Udp4Token.Packet.RxData;
1449       ASSERT (Udp4Rx != NULL);
1450 
1451       HeaderLen = 0;
1452       if (HeaderSize != NULL) {
1453         HeaderLen = MIN (*HeaderSize, Udp4Rx->DataLength);
1454       }
1455 
1456       if (Udp4Rx->DataLength - HeaderLen > *BufferSize) {
1457         Status = EFI_BUFFER_TOO_SMALL;
1458       } else {
1459         if (HeaderSize != NULL) {
1460           *HeaderSize = HeaderLen;
1461         }
1462         *BufferSize = Udp4Rx->DataLength - HeaderLen;
1463 
1464         HeaderCopiedLen = 0;
1465         BufferCopiedLen = 0;
1466         for (FragmentIndex = 0; FragmentIndex < Udp4Rx->FragmentCount; FragmentIndex++) {
1467           FragmentLength = Udp4Rx->FragmentTable[FragmentIndex].FragmentLength;
1468           FragmentBuffer = Udp4Rx->FragmentTable[FragmentIndex].FragmentBuffer;
1469           if (HeaderCopiedLen + FragmentLength < HeaderLen) {
1470             //
1471             // Copy the header part of received data.
1472             //
1473             CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, FragmentLength);
1474             HeaderCopiedLen += FragmentLength;
1475           } else if (HeaderCopiedLen < HeaderLen) {
1476             //
1477             // Copy the header part of received data.
1478             //
1479             CopiedLen = HeaderLen - HeaderCopiedLen;
1480             CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, CopiedLen);
1481             HeaderCopiedLen += CopiedLen;
1482 
1483             //
1484             // Copy the other part of received data.
1485             //
1486             CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer + CopiedLen, FragmentLength - CopiedLen);
1487             BufferCopiedLen += (FragmentLength - CopiedLen);
1488           } else {
1489             //
1490             // Copy the other part of received data.
1491             //
1492             CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer, FragmentLength);
1493             BufferCopiedLen += FragmentLength;
1494           }
1495         }
1496       }
1497       //
1498       // Recycle the receiving buffer after copy to user.
1499       //
1500       gBS->SignalEvent (Udp4Rx->RecycleSignal);
1501     }
1502   }
1503 
1504   if (Mode->UsingIpv6) {
1505     Private->Udp6Read->Cancel (Private->Udp6Read, &Udp6Token);
1506     gBS->CloseEvent (Udp6Token.Event);
1507   } else {
1508     Private->Udp4Read->Cancel (Private->Udp4Read, &Udp4Token);
1509     gBS->CloseEvent (Udp4Token.Event);
1510   }
1511 
1512   return Status;
1513 }
1514 
1515 
1516 /**
1517   Updates the IP receive filters of a network device and enables software filtering.
1518 
1519   The NewFilter field is used to modify the network device's current IP receive
1520   filter settings and to enable a software filter. This function updates the IpFilter
1521   field of the EFI_PXE_BASE_CODE_MODE structure with the contents of NewIpFilter.
1522   The software filter is used when the USE_FILTER in OpFlags is set to UdpRead().
1523   The current hardware filter remains in effect no matter what the settings of OpFlags.
1524   This is so that the meaning of ANY_DEST_IP set in OpFlags to UdpRead() is from those
1525   packets whose reception is enabled in hardware-physical NIC address (unicast),
1526   broadcast address, logical address or addresses (multicast), or all (promiscuous).
1527   UdpRead() does not modify the IP filter settings.
1528   Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP receive
1529   filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
1530   If an application or driver wishes to preserve the IP receive filter settings,
1531   it will have to preserve the IP receive filter settings before these calls, and
1532   use SetIpFilter() to restore them after the calls. If incompatible filtering is
1533   requested (for example, PROMISCUOUS with anything else), or if the device does not
1534   support a requested filter setting and it cannot be accommodated in software
1535   (for example, PROMISCUOUS not supported), EFI_INVALID_PARAMETER will be returned.
1536   The IPlist field is used to enable IPs other than the StationIP. They may be
1537   multicast or unicast. If IPcnt is set as well as EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP,
1538   then both the StationIP and the IPs from the IPlist will be used.
1539 
1540   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
1541   @param[in]  NewFilter         Pointer to the new set of IP receive filters.
1542 
1543   @retval EFI_SUCCESS           The IP receive filter settings were updated.
1544   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
1545   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1546 
1547 **/
1548 EFI_STATUS
1549 EFIAPI
EfiPxeBcSetIpFilter(IN EFI_PXE_BASE_CODE_PROTOCOL * This,IN EFI_PXE_BASE_CODE_IP_FILTER * NewFilter)1550 EfiPxeBcSetIpFilter (
1551   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
1552   IN EFI_PXE_BASE_CODE_IP_FILTER      *NewFilter
1553   )
1554 {
1555   EFI_STATUS                Status;
1556   PXEBC_PRIVATE_DATA        *Private;
1557   EFI_PXE_BASE_CODE_MODE    *Mode;
1558   EFI_UDP4_CONFIG_DATA      *Udp4Cfg;
1559   EFI_UDP6_CONFIG_DATA      *Udp6Cfg;
1560   UINTN                     Index;
1561   BOOLEAN                   NeedPromiscuous;
1562   BOOLEAN                   AcceptPromiscuous;
1563   BOOLEAN                   AcceptBroadcast;
1564   BOOLEAN                   MultiCastUpdate;
1565 
1566   if (This == NULL || NewFilter == NULL) {
1567     return EFI_INVALID_PARAMETER;
1568   }
1569 
1570   Private         = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1571   Mode            = Private->PxeBc.Mode;
1572   Status          = EFI_SUCCESS;
1573   NeedPromiscuous = FALSE;
1574 
1575   if (!Mode->Started) {
1576     return EFI_NOT_STARTED;
1577   }
1578 
1579   for (Index = 0; Index < NewFilter->IpCnt; Index++) {
1580     ASSERT (Index < EFI_PXE_BASE_CODE_MAX_IPCNT);
1581     if (!Mode->UsingIpv6 &&
1582         IP4_IS_LOCAL_BROADCAST (EFI_IP4 (NewFilter->IpList[Index].v4))) {
1583       //
1584       // IPv4 broadcast address should not be in IP filter.
1585       //
1586       return EFI_INVALID_PARAMETER;
1587     }
1588     if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0 &&
1589         (NetIp4IsUnicast (EFI_IP4 (NewFilter->IpList[Index].v4), 0) ||
1590          NetIp6IsValidUnicast (&NewFilter->IpList[Index].v6))) {
1591       //
1592       // If EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP is set and IPv4/IPv6 address
1593       // is in IpList, promiscuous mode is needed.
1594       //
1595       NeedPromiscuous = TRUE;
1596     }
1597   }
1598 
1599   AcceptPromiscuous = FALSE;
1600   AcceptBroadcast   = FALSE;
1601   MultiCastUpdate   = FALSE;
1602 
1603   if (NeedPromiscuous ||
1604       (NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0 ||
1605       (NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0) {
1606     //
1607     // Configure UDPv4/UDPv6 as promiscuous mode to receive all packets.
1608     //
1609     AcceptPromiscuous = TRUE;
1610   } else if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0) {
1611     //
1612     // Configure UDPv4 to receive all broadcast packets.
1613     //
1614     AcceptBroadcast  = TRUE;
1615   }
1616 
1617   //
1618   // In multicast condition when Promiscuous FALSE and IpCnt no-zero.
1619   // Here check if there is any update of the multicast ip address. If yes,
1620   // we need leave the old multicast group (by Config UDP instance to NULL),
1621   // and join the new multicast group.
1622   //
1623   if (!AcceptPromiscuous) {
1624     if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) {
1625       if (Mode->IpFilter.IpCnt != NewFilter->IpCnt) {
1626         MultiCastUpdate = TRUE;
1627       } else if (CompareMem (Mode->IpFilter.IpList, NewFilter->IpList, NewFilter->IpCnt * sizeof (EFI_IP_ADDRESS)) != 0 ) {
1628         MultiCastUpdate = TRUE;
1629       }
1630     }
1631   }
1632 
1633   if (!Mode->UsingIpv6) {
1634     //
1635     // Check whether we need reconfigure the UDP4 instance.
1636     //
1637     Udp4Cfg = &Private->Udp4CfgData;
1638     if ((AcceptPromiscuous != Udp4Cfg->AcceptPromiscuous)   ||
1639     	  (AcceptBroadcast != Udp4Cfg->AcceptBroadcast)     || MultiCastUpdate) {
1640       //
1641       // Clear the UDP4 instance configuration, all joined groups will be left
1642       // during the operation.
1643       //
1644       Private->Udp4Read->Configure (Private->Udp4Read, NULL);
1645 
1646       //
1647       // Configure the UDP instance with the new configuration.
1648       //
1649       Udp4Cfg->AcceptPromiscuous = AcceptPromiscuous;
1650       Udp4Cfg->AcceptBroadcast   = AcceptBroadcast;
1651       Status = Private->Udp4Read->Configure (Private->Udp4Read, Udp4Cfg);
1652       if (EFI_ERROR (Status)) {
1653         return Status;
1654       }
1655 
1656       //
1657       // In not Promiscuous mode, need to join the new multicast group.
1658       //
1659       if (!AcceptPromiscuous) {
1660         for (Index = 0; Index < NewFilter->IpCnt; ++Index) {
1661           if (IP4_IS_MULTICAST (EFI_NTOHL (NewFilter->IpList[Index].v4))) {
1662             //
1663             // Join the mutilcast group.
1664             //
1665             Status = Private->Udp4Read->Groups (Private->Udp4Read, TRUE, &NewFilter->IpList[Index].v4);
1666             if (EFI_ERROR (Status)) {
1667               return Status;
1668             }
1669           }
1670         }
1671       }
1672     }
1673   } else {
1674     //
1675     // Check whether we need reconfigure the UDP6 instance.
1676     //
1677     Udp6Cfg = &Private->Udp6CfgData;
1678     if ((AcceptPromiscuous != Udp6Cfg->AcceptPromiscuous) || MultiCastUpdate) {
1679       //
1680       // Clear the UDP6 instance configuration, all joined groups will be left
1681       // during the operation.
1682       //
1683       Private->Udp6Read->Configure (Private->Udp6Read, NULL);
1684 
1685       //
1686       // Configure the UDP instance with the new configuration.
1687       //
1688       Udp6Cfg->AcceptPromiscuous = AcceptPromiscuous;
1689       Status = Private->Udp6Read->Configure (Private->Udp6Read, Udp6Cfg);
1690       if (EFI_ERROR (Status)) {
1691         return Status;
1692       }
1693 
1694       //
1695       // In not Promiscuous mode, need to join the new multicast group.
1696       //
1697       if (!AcceptPromiscuous) {
1698         for (Index = 0; Index < NewFilter->IpCnt; ++Index) {
1699           if (IP6_IS_MULTICAST (&NewFilter->IpList[Index].v6)) {
1700             //
1701             // Join the mutilcast group.
1702             //
1703             Status = Private->Udp6Read->Groups (Private->Udp6Read, TRUE, &NewFilter->IpList[Index].v6);
1704             if (EFI_ERROR (Status)) {
1705               return Status;
1706             }
1707           }
1708         }
1709       }
1710     }
1711   }
1712 
1713   //
1714   // Save the new IP filter into mode data.
1715   //
1716   CopyMem (&Mode->IpFilter, NewFilter, sizeof (Mode->IpFilter));
1717 
1718   return Status;
1719 }
1720 
1721 
1722 /**
1723   Uses the ARP protocol to resolve a MAC address. It is not supported for IPv6.
1724 
1725   This function uses the ARP protocol to resolve a MAC address. The IP address specified
1726   by IpAddr is used to resolve a MAC address. If the ARP protocol succeeds in resolving
1727   the specified address, then the ArpCacheEntries and ArpCache fields of the mode data
1728   are updated, and EFI_SUCCESS is returned. If MacAddr is not NULL, the resolved
1729   MAC address is placed there as well.  If the PXE Base Code protocol is in the
1730   stopped state, then EFI_NOT_STARTED is returned. If the ARP protocol encounters
1731   a timeout condition while attempting to resolve an address, then EFI_TIMEOUT is
1732   returned. If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
1733   then EFI_ABORTED is returned.
1734 
1735   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
1736   @param[in]  IpAddr            Pointer to the IP address that is used to resolve a MAC address.
1737   @param[in]  MacAddr           If not NULL, a pointer to the MAC address that was resolved with the
1738                                 ARP protocol.
1739 
1740   @retval EFI_SUCCESS           The IP or MAC address was resolved.
1741   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
1742   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1743   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
1744   @retval EFI_ICMP_ERROR        An error occur with the ICMP packet message.
1745 
1746 **/
1747 EFI_STATUS
1748 EFIAPI
EfiPxeBcArp(IN EFI_PXE_BASE_CODE_PROTOCOL * This,IN EFI_IP_ADDRESS * IpAddr,IN EFI_MAC_ADDRESS * MacAddr OPTIONAL)1749 EfiPxeBcArp (
1750   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
1751   IN EFI_IP_ADDRESS                   *IpAddr,
1752   IN EFI_MAC_ADDRESS                  *MacAddr OPTIONAL
1753   )
1754 {
1755   PXEBC_PRIVATE_DATA      *Private;
1756   EFI_PXE_BASE_CODE_MODE  *Mode;
1757   EFI_EVENT               ResolvedEvent;
1758   EFI_STATUS              Status;
1759   EFI_MAC_ADDRESS         TempMac;
1760   EFI_MAC_ADDRESS         ZeroMac;
1761   BOOLEAN                 IsResolved;
1762 
1763   if (This == NULL || IpAddr == NULL) {
1764     return EFI_INVALID_PARAMETER;
1765   }
1766 
1767   Private       = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1768   Mode          = Private->PxeBc.Mode;
1769   ResolvedEvent = NULL;
1770   Status        = EFI_SUCCESS;
1771   IsResolved    = FALSE;
1772 
1773   if (!Mode->Started) {
1774     return EFI_NOT_STARTED;
1775   }
1776 
1777   if (Mode->UsingIpv6) {
1778     return EFI_UNSUPPORTED;
1779   }
1780 
1781   //
1782   // Station address should be ready before do arp.
1783   //
1784   if (!Private->IsAddressOk) {
1785     return EFI_INVALID_PARAMETER;
1786   }
1787 
1788   Mode->IcmpErrorReceived = FALSE;
1789   ZeroMem (&TempMac, sizeof (EFI_MAC_ADDRESS));
1790   ZeroMem (&ZeroMac, sizeof (EFI_MAC_ADDRESS));
1791 
1792   if (!Mode->AutoArp) {
1793     //
1794     // If AutoArp is FALSE, only search in the current Arp cache.
1795     //
1796     PxeBcArpCacheUpdate (NULL, Private);
1797     if (!PxeBcCheckArpCache (Mode, &IpAddr->v4, &TempMac)) {
1798       Status = EFI_DEVICE_ERROR;
1799       goto ON_EXIT;
1800     }
1801   } else {
1802     Status = gBS->CreateEvent (
1803                     EVT_NOTIFY_SIGNAL,
1804                     TPL_NOTIFY,
1805                     PxeBcCommonNotify,
1806                     &IsResolved,
1807                     &ResolvedEvent
1808                     );
1809     if (EFI_ERROR (Status)) {
1810       goto ON_EXIT;
1811     }
1812 
1813     //
1814     // If AutoArp is TRUE, try to send Arp request on initiative.
1815     //
1816     Status = Private->Arp->Request (Private->Arp, &IpAddr->v4, ResolvedEvent, &TempMac);
1817     if (EFI_ERROR (Status) && Status != EFI_NOT_READY) {
1818       goto ON_EXIT;
1819     }
1820 
1821     while (!IsResolved) {
1822       if (CompareMem (&TempMac, &ZeroMac, sizeof (EFI_MAC_ADDRESS)) != 0) {
1823         break;
1824       }
1825     }
1826     if (CompareMem (&TempMac, &ZeroMac, sizeof (EFI_MAC_ADDRESS)) != 0) {
1827       Status = EFI_SUCCESS;
1828     } else {
1829       Status = EFI_TIMEOUT;
1830     }
1831   }
1832 
1833   //
1834   // Copy the Mac address to user if needed.
1835   //
1836   if (MacAddr != NULL && !EFI_ERROR (Status)) {
1837     CopyMem (MacAddr, &TempMac, sizeof (EFI_MAC_ADDRESS));
1838   }
1839 
1840 ON_EXIT:
1841   if (ResolvedEvent != NULL) {
1842     gBS->CloseEvent (ResolvedEvent);
1843   }
1844   return Status;
1845 }
1846 
1847 
1848 /**
1849   Updates the parameters that affect the operation of the PXE Base Code Protocol.
1850 
1851   This function sets parameters that affect the operation of the PXE Base Code Protocol.
1852   The parameter specified by NewAutoArp is used to control the generation of ARP
1853   protocol packets. If NewAutoArp is TRUE, then ARP Protocol packets will be generated
1854   as required by the PXE Base Code Protocol. If NewAutoArp is FALSE, then no ARP
1855   Protocol packets will be generated. In this case, the only mappings that are
1856   available are those stored in the ArpCache of the EFI_PXE_BASE_CODE_MODE structure.
1857   If there are not enough mappings in the ArpCache to perform a PXE Base Code Protocol
1858   service, then the service will fail. This function updates the AutoArp field of
1859   the EFI_PXE_BASE_CODE_MODE structure to NewAutoArp.
1860   The SetParameters() call must be invoked after a Callback Protocol is installed
1861   to enable the use of callbacks.
1862 
1863   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
1864   @param[in]  NewAutoArp        If not NULL, a pointer to a value that specifies whether to replace the
1865                                 current value of AutoARP.
1866   @param[in]  NewSendGUID       If not NULL, a pointer to a value that specifies whether to replace the
1867                                 current value of SendGUID.
1868   @param[in]  NewTTL            If not NULL, a pointer to be used in place of the current value of TTL,
1869                                 the "time to live" field of the IP header.
1870   @param[in]  NewToS            If not NULL, a pointer to be used in place of the current value of ToS,
1871                                 the "type of service" field of the IP header.
1872   @param[in]  NewMakeCallback   If not NULL, a pointer to a value that specifies whether to replace the
1873                                 current value of the MakeCallback field of the Mode structure.
1874 
1875   @retval EFI_SUCCESS           The new parameters values were updated.
1876   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
1877   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1878 
1879 **/
1880 EFI_STATUS
1881 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 OPTIONAL)1882 EfiPxeBcSetParameters (
1883   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
1884   IN BOOLEAN                          *NewAutoArp         OPTIONAL,
1885   IN BOOLEAN                          *NewSendGUID        OPTIONAL,
1886   IN UINT8                            *NewTTL             OPTIONAL,
1887   IN UINT8                            *NewToS             OPTIONAL,
1888   IN BOOLEAN                          *NewMakeCallback    OPTIONAL
1889   )
1890 {
1891   PXEBC_PRIVATE_DATA      *Private;
1892   EFI_PXE_BASE_CODE_MODE  *Mode;
1893   EFI_GUID                SystemGuid;
1894   EFI_STATUS              Status;
1895 
1896   if (This == NULL) {
1897     return EFI_INVALID_PARAMETER;
1898   }
1899 
1900   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1901   Mode    = Private->PxeBc.Mode;
1902 
1903   if (!Mode->Started) {
1904     return EFI_NOT_STARTED;
1905   }
1906 
1907   if (NewMakeCallback != NULL) {
1908     if (*NewMakeCallback) {
1909       //
1910       // Update the previous PxeBcCallback protocol.
1911       //
1912       Status = gBS->HandleProtocol (
1913                       Private->Controller,
1914                       &gEfiPxeBaseCodeCallbackProtocolGuid,
1915                       (VOID **) &Private->PxeBcCallback
1916                       );
1917 
1918       if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {
1919         return EFI_INVALID_PARAMETER;
1920       }
1921     } else {
1922       Private->PxeBcCallback = NULL;
1923     }
1924     Mode->MakeCallbacks = *NewMakeCallback;
1925   }
1926 
1927   if (NewSendGUID != NULL) {
1928     if (*NewSendGUID && EFI_ERROR (NetLibGetSystemGuid (&SystemGuid))) {
1929       return EFI_INVALID_PARAMETER;
1930     }
1931     Mode->SendGUID = *NewSendGUID;
1932   }
1933 
1934   if (NewAutoArp != NULL) {
1935     Mode->AutoArp = *NewAutoArp;
1936   }
1937 
1938   if (NewTTL != NULL) {
1939     Mode->TTL = *NewTTL;
1940   }
1941 
1942   if (NewToS != NULL) {
1943     Mode->ToS = *NewToS;
1944   }
1945 
1946   return EFI_SUCCESS;
1947 }
1948 
1949 
1950 /**
1951   Updates the station IP address and/or subnet mask values of a network device.
1952 
1953   This function updates the station IP address and/or subnet mask values of a network
1954   device. The NewStationIp field is used to modify the network device's current IP address.
1955   If NewStationIP is NULL, then the current IP address will not be modified. Otherwise,
1956   this function updates the StationIp field of the EFI_PXE_BASE_CODE_MODE structure
1957   with NewStationIp. The NewSubnetMask field is used to modify the network device's current subnet
1958   mask. If NewSubnetMask is NULL, then the current subnet mask will not be modified.
1959   Otherwise, this function updates the SubnetMask field of the EFI_PXE_BASE_CODE_MODE
1960   structure with NewSubnetMask.
1961 
1962   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
1963   @param[in]  NewStationIp      Pointer to the new IP address to be used by the network device.
1964   @param[in]  NewSubnetMask     Pointer to the new subnet mask to be used by the network device.
1965 
1966   @retval EFI_SUCCESS           The new station IP address and/or subnet mask were updated.
1967   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
1968   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1969 
1970 **/
1971 EFI_STATUS
1972 EFIAPI
EfiPxeBcSetStationIP(IN EFI_PXE_BASE_CODE_PROTOCOL * This,IN EFI_IP_ADDRESS * NewStationIp OPTIONAL,IN EFI_IP_ADDRESS * NewSubnetMask OPTIONAL)1973 EfiPxeBcSetStationIP (
1974   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
1975   IN EFI_IP_ADDRESS                   *NewStationIp    OPTIONAL,
1976   IN EFI_IP_ADDRESS                   *NewSubnetMask   OPTIONAL
1977   )
1978 {
1979   EFI_STATUS              Status;
1980   PXEBC_PRIVATE_DATA      *Private;
1981   EFI_PXE_BASE_CODE_MODE  *Mode;
1982   EFI_ARP_CONFIG_DATA     ArpConfigData;
1983 
1984   if (This == NULL) {
1985     return EFI_INVALID_PARAMETER;
1986   }
1987 
1988   if (NewStationIp != NULL &&
1989       (!NetIp4IsUnicast (NTOHL (NewStationIp->Addr[0]), 0) &&
1990        !NetIp6IsValidUnicast (&NewStationIp->v6))) {
1991     return EFI_INVALID_PARAMETER;
1992   }
1993 
1994   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1995   Mode    = Private->PxeBc.Mode;
1996   Status  = EFI_SUCCESS;
1997 
1998   if (!Mode->UsingIpv6 &&
1999       NewSubnetMask != NULL &&
2000       !IP4_IS_VALID_NETMASK (NTOHL (NewSubnetMask->Addr[0]))) {
2001     return EFI_INVALID_PARAMETER;
2002   }
2003 
2004   if (!Mode->Started) {
2005     return EFI_NOT_STARTED;
2006   }
2007 
2008   if (Mode->UsingIpv6 && NewStationIp != NULL) {
2009     //
2010     // Set the IPv6 address by Ip6Config protocol.
2011     //
2012     Status = PxeBcRegisterIp6Address (Private, &NewStationIp->v6);
2013     if (EFI_ERROR (Status)) {
2014       goto ON_EXIT;
2015     }
2016   } else if (!Mode->UsingIpv6 && NewStationIp != NULL) {
2017     //
2018     // Configure the corresponding ARP with the IPv4 address.
2019     //
2020     ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));
2021 
2022     ArpConfigData.SwAddressType   = 0x0800;
2023     ArpConfigData.SwAddressLength = (UINT8) sizeof (EFI_IPv4_ADDRESS);
2024     ArpConfigData.StationAddress  = &NewStationIp->v4;
2025 
2026     Private->Arp->Configure (Private->Arp, NULL);
2027     Private->Arp->Configure (Private->Arp, &ArpConfigData);
2028 
2029     if (NewSubnetMask != NULL) {
2030       Mode->RouteTableEntries                = 1;
2031       Mode->RouteTable[0].IpAddr.Addr[0]     = NewStationIp->Addr[0] & NewSubnetMask->Addr[0];
2032       Mode->RouteTable[0].SubnetMask.Addr[0] = NewSubnetMask->Addr[0];
2033       Mode->RouteTable[0].GwAddr.Addr[0]     = 0;
2034     }
2035 
2036     Private->IsAddressOk = TRUE;
2037   }
2038 
2039   if (NewStationIp != NULL) {
2040     CopyMem (&Mode->StationIp, NewStationIp, sizeof (EFI_IP_ADDRESS));
2041     CopyMem (&Private->StationIp, NewStationIp, sizeof (EFI_IP_ADDRESS));
2042   }
2043 
2044   if (!Mode->UsingIpv6 && NewSubnetMask != NULL) {
2045     CopyMem (&Mode->SubnetMask, NewSubnetMask, sizeof (EFI_IP_ADDRESS));
2046     CopyMem (&Private->SubnetMask ,NewSubnetMask, sizeof (EFI_IP_ADDRESS));
2047   }
2048 
2049   Status = PxeBcFlushStationIp (Private, NewStationIp, NewSubnetMask);
2050 ON_EXIT:
2051   return Status;
2052 }
2053 
2054 
2055 /**
2056   Updates the contents of the cached DHCP and Discover packets.
2057 
2058   The pointers to the new packets are used to update the contents of the cached
2059   packets in the EFI_PXE_BASE_CODE_MODE structure.
2060 
2061   @param[in]  This                   Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
2062   @param[in]  NewDhcpDiscoverValid   Pointer to a value that will replace the current
2063                                      DhcpDiscoverValid field.
2064   @param[in]  NewDhcpAckReceived     Pointer to a value that will replace the current
2065                                      DhcpAckReceived field.
2066   @param[in]  NewProxyOfferReceived  Pointer to a value that will replace the current
2067                                      ProxyOfferReceived field.
2068   @param[in]  NewPxeDiscoverValid    Pointer to a value that will replace the current
2069                                      ProxyOfferReceived field.
2070   @param[in]  NewPxeReplyReceived    Pointer to a value that will replace the current
2071                                      PxeReplyReceived field.
2072   @param[in]  NewPxeBisReplyReceived Pointer to a value that will replace the current
2073                                      PxeBisReplyReceived field.
2074   @param[in]  NewDhcpDiscover        Pointer to the new cached DHCP Discover packet contents.
2075   @param[in]  NewDhcpAck             Pointer to the new cached DHCP Ack packet contents.
2076   @param[in]  NewProxyOffer          Pointer to the new cached Proxy Offer packet contents.
2077   @param[in]  NewPxeDiscover         Pointer to the new cached PXE Discover packet contents.
2078   @param[in]  NewPxeReply            Pointer to the new cached PXE Reply packet contents.
2079   @param[in]  NewPxeBisReply         Pointer to the new cached PXE BIS Reply packet contents.
2080 
2081   @retval EFI_SUCCESS            The cached packet contents were updated.
2082   @retval EFI_NOT_STARTED        The PXE Base Code Protocol is in the stopped state.
2083   @retval EFI_INVALID_PARAMETER  This is NULL or does not point to a valid
2084                                  EFI_PXE_BASE_CODE_PROTOCOL structure.
2085 
2086 **/
2087 EFI_STATUS
2088 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)2089 EfiPxeBcSetPackets (
2090   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
2091   IN BOOLEAN                          *NewDhcpDiscoverValid      OPTIONAL,
2092   IN BOOLEAN                          *NewDhcpAckReceived        OPTIONAL,
2093   IN BOOLEAN                          *NewProxyOfferReceived     OPTIONAL,
2094   IN BOOLEAN                          *NewPxeDiscoverValid       OPTIONAL,
2095   IN BOOLEAN                          *NewPxeReplyReceived       OPTIONAL,
2096   IN BOOLEAN                          *NewPxeBisReplyReceived    OPTIONAL,
2097   IN EFI_PXE_BASE_CODE_PACKET         *NewDhcpDiscover           OPTIONAL,
2098   IN EFI_PXE_BASE_CODE_PACKET         *NewDhcpAck                OPTIONAL,
2099   IN EFI_PXE_BASE_CODE_PACKET         *NewProxyOffer             OPTIONAL,
2100   IN EFI_PXE_BASE_CODE_PACKET         *NewPxeDiscover            OPTIONAL,
2101   IN EFI_PXE_BASE_CODE_PACKET         *NewPxeReply               OPTIONAL,
2102   IN EFI_PXE_BASE_CODE_PACKET         *NewPxeBisReply            OPTIONAL
2103   )
2104 {
2105   PXEBC_PRIVATE_DATA      *Private;
2106   EFI_PXE_BASE_CODE_MODE  *Mode;
2107 
2108   if (This == NULL) {
2109     return EFI_INVALID_PARAMETER;
2110   }
2111 
2112   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
2113   Mode    = Private->PxeBc.Mode;
2114 
2115   if (!Mode->Started) {
2116     return EFI_NOT_STARTED;
2117   }
2118 
2119   if (NewDhcpDiscoverValid != NULL) {
2120     Mode->DhcpDiscoverValid = *NewDhcpDiscoverValid;
2121   }
2122 
2123   if (NewDhcpAckReceived != NULL) {
2124     Mode->DhcpAckReceived = *NewDhcpAckReceived;
2125   }
2126 
2127   if (NewProxyOfferReceived != NULL) {
2128     Mode->ProxyOfferReceived = *NewProxyOfferReceived;
2129   }
2130 
2131   if (NewPxeDiscoverValid != NULL) {
2132     Mode->PxeDiscoverValid = *NewPxeDiscoverValid;
2133   }
2134 
2135   if (NewPxeReplyReceived != NULL) {
2136     Mode->PxeReplyReceived = *NewPxeReplyReceived;
2137   }
2138 
2139   if (NewPxeBisReplyReceived != NULL) {
2140     Mode->PxeBisReplyReceived = *NewPxeBisReplyReceived;
2141   }
2142 
2143   if (NewDhcpDiscover != NULL) {
2144     CopyMem (&Mode->DhcpDiscover, NewDhcpDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
2145   }
2146 
2147   if (NewDhcpAck != NULL) {
2148     CopyMem (&Mode->DhcpAck, NewDhcpAck, sizeof (EFI_PXE_BASE_CODE_PACKET));
2149   }
2150 
2151   if (NewProxyOffer != NULL) {
2152     CopyMem (&Mode->ProxyOffer, NewProxyOffer, sizeof (EFI_PXE_BASE_CODE_PACKET));
2153   }
2154 
2155   if (NewPxeDiscover != NULL) {
2156     CopyMem (&Mode->PxeDiscover, NewPxeDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
2157   }
2158 
2159   if (NewPxeReply != NULL) {
2160     CopyMem (&Mode->PxeReply, NewPxeReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
2161   }
2162 
2163   if (NewPxeBisReply != NULL) {
2164     CopyMem (&Mode->PxeBisReply, NewPxeBisReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
2165   }
2166 
2167   return EFI_SUCCESS;
2168 }
2169 
2170 EFI_PXE_BASE_CODE_PROTOCOL  gPxeBcProtocolTemplate = {
2171   EFI_PXE_BASE_CODE_PROTOCOL_REVISION,
2172   EfiPxeBcStart,
2173   EfiPxeBcStop,
2174   EfiPxeBcDhcp,
2175   EfiPxeBcDiscover,
2176   EfiPxeBcMtftp,
2177   EfiPxeBcUdpWrite,
2178   EfiPxeBcUdpRead,
2179   EfiPxeBcSetIpFilter,
2180   EfiPxeBcArp,
2181   EfiPxeBcSetParameters,
2182   EfiPxeBcSetStationIP,
2183   EfiPxeBcSetPackets,
2184   NULL
2185 };
2186 
2187 
2188 /**
2189   Callback function that is invoked when the PXE Base Code Protocol is about to transmit, has
2190   received, or is waiting to receive a packet.
2191 
2192   This function is invoked when the PXE Base Code Protocol is about to transmit, has received,
2193   or is waiting to receive a packet. Parameters Function and Received specify the type of event.
2194   Parameters PacketLen and Packet specify the packet that generated the event. If these fields
2195   are zero and NULL respectively, then this is a status update callback. If the operation specified
2196   by Function is to continue, then CALLBACK_STATUS_CONTINUE should be returned. If the operation
2197   specified by Function should be aborted, then CALLBACK_STATUS_ABORT should be returned. Due to
2198   the polling nature of UEFI device drivers, a callback function should not execute for more than 5 ms.
2199   The SetParameters() function must be called after a Callback Protocol is installed to enable the
2200   use of callbacks.
2201 
2202   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL instance.
2203   @param[in]  Function          The PXE Base Code Protocol function that is waiting for an event.
2204   @param[in]  Received          TRUE if the callback is being invoked due to a receive event. FALSE if
2205                                 the callback is being invoked due to a transmit event.
2206   @param[in]  PacketLength      The length, in bytes, of Packet. This field will have a value of zero if
2207                                 this is a wait for receive event.
2208   @param[in]  PacketPtr         If Received is TRUE, a pointer to the packet that was just received;
2209                                 otherwise a pointer to the packet that is about to be transmitted.
2210 
2211   @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE If Function specifies a continue operation.
2212   @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT    If Function specifies an abort operation.
2213 
2214 **/
2215 EFI_PXE_BASE_CODE_CALLBACK_STATUS
2216 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)2217 EfiPxeLoadFileCallback (
2218   IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL  *This,
2219   IN EFI_PXE_BASE_CODE_FUNCTION           Function,
2220   IN BOOLEAN                              Received,
2221   IN UINT32                               PacketLength,
2222   IN EFI_PXE_BASE_CODE_PACKET             *PacketPtr     OPTIONAL
2223   )
2224 {
2225   EFI_INPUT_KEY       Key;
2226   EFI_STATUS          Status;
2227 
2228   //
2229   // Catch Ctrl-C or ESC to abort.
2230   //
2231   Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
2232 
2233   if (!EFI_ERROR (Status)) {
2234 
2235     if (Key.ScanCode == SCAN_ESC || Key.UnicodeChar == (0x1F & 'c')) {
2236 
2237       return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
2238     }
2239   }
2240   //
2241   // No print if receive packet
2242   //
2243   if (Received) {
2244     return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
2245   }
2246   //
2247   // Print only for three functions
2248   //
2249   switch (Function) {
2250 
2251   case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:
2252     //
2253     // Print only for open MTFTP packets, not every MTFTP packets
2254     //
2255     if (PacketLength != 0 && PacketPtr != NULL) {
2256       if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {
2257         return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
2258       }
2259     }
2260     break;
2261 
2262   case EFI_PXE_BASE_CODE_FUNCTION_DHCP:
2263   case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:
2264     break;
2265 
2266   default:
2267     return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
2268   }
2269 
2270   if (PacketLength != 0 && PacketPtr != NULL) {
2271     //
2272     // Print '.' when transmit a packet
2273     //
2274     AsciiPrint (".");
2275   }
2276 
2277   return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
2278 }
2279 
2280 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL gPxeBcCallBackTemplate = {
2281   EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION,
2282   EfiPxeLoadFileCallback
2283 };
2284 
2285 
2286 /**
2287   Causes the driver to load a specified file.
2288 
2289   @param[in]      This                Protocol instance pointer.
2290   @param[in]      FilePath            The device specific path of the file to load.
2291   @param[in]      BootPolicy          If TRUE, indicates that the request originates from the
2292                                       boot manager is attempting to load FilePath as a boot
2293                                       selection. If FALSE, then FilePath must match an exact file
2294                                       to be loaded.
2295   @param[in, out] BufferSize          On input the size of Buffer in bytes. On output with a return
2296                                       code of EFI_SUCCESS, the amount of data transferred to
2297                                       Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
2298                                       the size of Buffer required to retrieve the requested file.
2299   @param[in]      Buffer              The memory buffer to transfer the file to. IF Buffer is NULL,
2300                                       then no the size of the requested file is returned in
2301                                       BufferSize.
2302 
2303   @retval EFI_SUCCESS                 The file was loaded.
2304   @retval EFI_UNSUPPORTED             The device does not support the provided BootPolicy.
2305   @retval EFI_INVALID_PARAMETER       FilePath is not a valid device path, or
2306                                       BufferSize is NULL.
2307   @retval EFI_NO_MEDIA                No medium was present to load the file.
2308   @retval EFI_DEVICE_ERROR            The file was not loaded due to a device error.
2309   @retval EFI_NO_RESPONSE             The remote system did not respond.
2310   @retval EFI_NOT_FOUND               The file was not found.
2311   @retval EFI_ABORTED                 The file load process was manually cancelled.
2312 
2313 **/
2314 EFI_STATUS
2315 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)2316 EfiPxeLoadFile (
2317   IN     EFI_LOAD_FILE_PROTOCOL           *This,
2318   IN     EFI_DEVICE_PATH_PROTOCOL         *FilePath,
2319   IN     BOOLEAN                          BootPolicy,
2320   IN OUT UINTN                            *BufferSize,
2321   IN     VOID                             *Buffer       OPTIONAL
2322   )
2323 {
2324   PXEBC_PRIVATE_DATA          *Private;
2325   PXEBC_VIRTUAL_NIC           *VirtualNic;
2326   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
2327   BOOLEAN                     UsingIpv6;
2328   EFI_STATUS                  Status;
2329   BOOLEAN                     MediaPresent;
2330 
2331   if (FilePath == NULL || !IsDevicePathEnd (FilePath)) {
2332     return EFI_INVALID_PARAMETER;
2333   }
2334 
2335   VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (This);
2336   Private    = VirtualNic->Private;
2337   PxeBc      = &Private->PxeBc;
2338   UsingIpv6  = FALSE;
2339   Status     = EFI_DEVICE_ERROR;
2340 
2341   if (This == NULL || BufferSize == NULL) {
2342     return EFI_INVALID_PARAMETER;
2343   }
2344 
2345   //
2346   // Only support BootPolicy
2347   //
2348   if (!BootPolicy) {
2349     return EFI_UNSUPPORTED;
2350   }
2351 
2352   //
2353   // Check media status before PXE start
2354   //
2355   MediaPresent = TRUE;
2356   NetLibDetectMedia (Private->Controller, &MediaPresent);
2357   if (!MediaPresent) {
2358     return EFI_NO_MEDIA;
2359   }
2360 
2361   //
2362   // Check whether the virtual nic is using IPv6 or not.
2363   //
2364   if (VirtualNic == Private->Ip6Nic) {
2365     UsingIpv6 = TRUE;
2366   }
2367 
2368   //
2369   // Start Pxe Base Code to initialize PXE boot.
2370   //
2371   Status = PxeBc->Start (PxeBc, UsingIpv6);
2372   if (Status == EFI_ALREADY_STARTED && UsingIpv6 != PxeBc->Mode->UsingIpv6) {
2373     //
2374     // PxeBc protocol has already been started but not on the required IP version, restart it.
2375     //
2376     Status = PxeBc->Stop (PxeBc);
2377     if (!EFI_ERROR (Status)) {
2378       Status = PxeBc->Start (PxeBc, UsingIpv6);
2379     }
2380   }
2381   if (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED) {
2382     Status = PxeBcLoadBootFile (Private, BufferSize, Buffer);
2383   }
2384 
2385   if (Status != EFI_SUCCESS &&
2386       Status != EFI_UNSUPPORTED &&
2387       Status != EFI_BUFFER_TOO_SMALL) {
2388     //
2389     // There are three cases, which needn't stop pxebc here.
2390     //   1. success to download file.
2391     //   2. success to get file size.
2392     //   3. unsupported.
2393     //
2394     PxeBc->Stop (PxeBc);
2395   } else {
2396     //
2397     // The DHCP4 can have only one configured child instance so we need to stop
2398     // reset the DHCP4 child before we return. Otherwise these programs which
2399     // also need to use DHCP4 will be impacted.
2400     //
2401     if (!PxeBc->Mode->UsingIpv6) {
2402       Private->Dhcp4->Stop (Private->Dhcp4);
2403       Private->Dhcp4->Configure (Private->Dhcp4, NULL);
2404     }
2405   }
2406 
2407   return Status;
2408 }
2409 
2410 EFI_LOAD_FILE_PROTOCOL  gLoadFileProtocolTemplate = { EfiPxeLoadFile };
2411 
2412