enhanced UefiPxeBcDxe to support
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Network / UefiPxeBcDxe / PxeBcImpl.c
1 /** @file\r
2 \r
3 Copyright (c) 2007 - 2008, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   PxeBcImpl.c\r
15 \r
16 Abstract:\r
17 \r
18   Interface routines for PxeBc\r
19 \r
20 \r
21 **/\r
22 \r
23 \r
24 #include "PxeBcImpl.h"\r
25 \r
26 /**\r
27   Get and record the arp cache\r
28 \r
29   @param  This                    Pointer to EFI_PXE_BC_PROTOCOL\r
30 \r
31   @retval EFI_SUCCESS             Arp cache updated successfully\r
32   @retval others                  If error occurs when updating arp cache\r
33 \r
34 **/\r
35 STATIC\r
36 EFI_STATUS\r
37 UpdateArpCache (\r
38   IN EFI_PXE_BASE_CODE_PROTOCOL     * This\r
39   )\r
40 {\r
41   PXEBC_PRIVATE_DATA      *Private;\r
42   EFI_PXE_BASE_CODE_MODE  *Mode;\r
43   EFI_STATUS              Status;\r
44   UINT32                  EntryLength;\r
45   UINT32                  EntryCount;\r
46   EFI_ARP_FIND_DATA       *Entries;\r
47   UINT32                  Index;\r
48 \r
49   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
50   Mode    = Private->PxeBc.Mode;\r
51 \r
52   Status = Private->Arp->Find (Private->Arp, TRUE, NULL, &EntryLength, &EntryCount, &Entries, TRUE);\r
53   if (EFI_ERROR (Status)) {\r
54     return Status;\r
55   }\r
56 \r
57   Mode->ArpCacheEntries = MIN (EntryCount, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES);\r
58   for (Index = 0; Index < Mode->ArpCacheEntries; Index ++) {\r
59     CopyMem (&Mode->ArpCache[Index].IpAddr, Entries + 1, Entries->SwAddressLength);\r
60     CopyMem (&Mode->ArpCache[Index].MacAddr, (UINT8 *)(Entries + 1) + Entries->SwAddressLength, Entries->HwAddressLength);\r
61     //\r
62     // Slip to the next FindData.\r
63     //\r
64     Entries = (EFI_ARP_FIND_DATA *)((UINT8 *)Entries + EntryLength);\r
65   }\r
66 \r
67   return EFI_SUCCESS;\r
68 }\r
69 \r
70 /**\r
71   Timeout routine to catch arp cache.\r
72 \r
73   @param  Event              Pointer to EFI_PXE_BC_PROTOCOL\r
74   @param  Context            Context of the timer event\r
75 \r
76 **/\r
77 STATIC\r
78 VOID\r
79 EFIAPI\r
80 ArpCacheUpdateTimeout (\r
81   IN EFI_EVENT    Event,\r
82   IN VOID         *Context\r
83   )\r
84 {\r
85   UpdateArpCache ((EFI_PXE_BASE_CODE_PROTOCOL *) Context);\r
86 }\r
87 \r
88 /**\r
89   Timeout routine to catch arp cache.\r
90 \r
91   @param  Event                    Pointer to EFI_PXE_BC_PROTOCOL\r
92   @param  Context\r
93 \r
94 **/\r
95 STATIC\r
96 BOOLEAN\r
97 FindInArpCache (\r
98   EFI_PXE_BASE_CODE_MODE    *PxeBcMode,\r
99   EFI_IPv4_ADDRESS          *Ip4Addr,\r
100   EFI_MAC_ADDRESS           *MacAddress\r
101   )\r
102 {\r
103   UINT32                  Index;\r
104 \r
105   for (Index = 0; Index < PxeBcMode->ArpCacheEntries; Index ++) {\r
106     if (EFI_IP4_EQUAL (&PxeBcMode->ArpCache[Index].IpAddr.v4, Ip4Addr)) {\r
107       CopyMem (MacAddress, &PxeBcMode->ArpCache[Index].MacAddr, sizeof (EFI_MAC_ADDRESS));\r
108       return TRUE;\r
109     }\r
110   }\r
111 \r
112   return FALSE;\r
113 }\r
114 \r
115 /**\r
116   Notify function for the ICMP receive token, used to process\r
117   the received ICMP packets.\r
118 \r
119   @param  Context               The context passed in by the event notifier.\r
120 \r
121   @return None.\r
122 \r
123 **/\r
124 STATIC\r
125 VOID\r
126 EFIAPI\r
127 IcmpErrorListenHandlerDpc (\r
128   IN VOID      *Context\r
129   )\r
130 {\r
131   EFI_STATUS              Status;\r
132   EFI_IP4_RECEIVE_DATA    *RxData;\r
133   EFI_IP4_PROTOCOL        *Ip4;\r
134   PXEBC_PRIVATE_DATA      *Private;\r
135   EFI_PXE_BASE_CODE_MODE  *Mode;\r
136   UINTN                   Index;\r
137   UINT32                  CopiedLen;\r
138   UINT8                   *CopiedPointer;\r
139 \r
140   Private = (PXEBC_PRIVATE_DATA *) Context;\r
141   Mode    = &Private->Mode;\r
142   Status  = Private->IcmpErrorRcvToken.Status;\r
143   RxData  = Private->IcmpErrorRcvToken.Packet.RxData;\r
144   Ip4     = Private->Ip4;\r
145 \r
146   if (EFI_ABORTED == Status) {\r
147     //\r
148     // The reception is actively aborted by the consumer, directly return.\r
149     //\r
150     return;\r
151   }\r
152 \r
153   if ((EFI_SUCCESS != Status) || (NULL == RxData)) {\r
154     //\r
155     // Only process the normal packets and the icmp error packets, if RxData is NULL\r
156     // with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although\r
157     // this should be a bug of the low layer (IP).\r
158     //\r
159     goto Resume;\r
160   }\r
161 \r
162   if ((EFI_IP4 (RxData->Header->SourceAddress) != 0) &&\r
163     !Ip4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {\r
164     //\r
165     // The source address is not zero and it's not a unicast IP address, discard it.\r
166     //\r
167     goto CleanUp;\r
168   }\r
169 \r
170   if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {\r
171     //\r
172     // The dest address is not equal to Station Ip address, discard it.\r
173     //\r
174     goto CleanUp;\r
175   }\r
176 \r
177   //\r
178   // Constructor ICMP error packet\r
179   //\r
180   CopiedLen = 0;\r
181   CopiedPointer = (UINT8 *) &Mode->IcmpError;\r
182 \r
183   for (Index = 0; Index < RxData->FragmentCount; Index ++) {\r
184     CopiedLen += RxData->FragmentTable[Index].FragmentLength;\r
185     if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {\r
186       CopyMem (CopiedPointer, RxData->FragmentTable[Index].FragmentBuffer, RxData->FragmentTable[Index].FragmentLength);\r
187     } else {\r
188       CopyMem (CopiedPointer, RxData->FragmentTable[Index].FragmentBuffer, CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR));\r
189     }\r
190     CopiedPointer += CopiedLen;\r
191   }\r
192 \r
193   goto Resume;\r
194 \r
195 CleanUp:\r
196   gBS->SignalEvent (RxData->RecycleSignal);\r
197 \r
198 Resume:\r
199   Ip4->Receive (Ip4, &(Private->IcmpErrorRcvToken));\r
200 }\r
201 \r
202 /**\r
203   Request IcmpErrorListenHandlerDpc as a DPC at TPL_CALLBACK\r
204 \r
205   @param  Event                 The event signaled.\r
206   @param  Context               The context passed in by the event notifier.\r
207 \r
208   @return None.\r
209 \r
210 **/\r
211 STATIC\r
212 VOID\r
213 EFIAPI\r
214 IcmpErrorListenHandler (\r
215   IN EFI_EVENT Event,\r
216   IN VOID      *Context\r
217   )\r
218 {\r
219   //\r
220   // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK\r
221   //\r
222   NetLibQueueDpc (TPL_CALLBACK, IcmpErrorListenHandlerDpc, Context);\r
223 }\r
224 \r
225 /**\r
226   GC_NOTO: Add function description\r
227 \r
228   @param  This                                        GC_NOTO: add argument\r
229                                                       description\r
230   @param  UseIpv6                                     GC_NOTO: add argument\r
231                                                       description\r
232 \r
233   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
234                                                       return value\r
235   @retval EFI_ALREADY_STARTED                         GC_NOTO: Add description for\r
236                                                       return value\r
237   @retval EFI_UNSUPPORTED                             GC_NOTO: Add description for\r
238                                                       return value\r
239   @retval EFI_SUCCESS                                 GC_NOTO: Add description for\r
240                                                       return value\r
241 \r
242 **/\r
243 EFI_STATUS\r
244 EFIAPI\r
245 EfiPxeBcStart (\r
246   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,\r
247   IN BOOLEAN                          UseIpv6\r
248   )\r
249 {\r
250   PXEBC_PRIVATE_DATA      *Private;\r
251   EFI_PXE_BASE_CODE_MODE  *Mode;\r
252   EFI_STATUS              Status;\r
253 \r
254   CpuDeadLoop ();\r
255   if (This == NULL) {\r
256     return EFI_INVALID_PARAMETER;\r
257   }\r
258 \r
259   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
260   Mode    = Private->PxeBc.Mode;\r
261 \r
262   if (Mode->Started) {\r
263     return EFI_ALREADY_STARTED;\r
264   }\r
265 \r
266   if (UseIpv6) {\r
267     //\r
268     // IPv6 is not supported now.\r
269     //\r
270     return EFI_UNSUPPORTED;\r
271   }\r
272 \r
273   //\r
274   // Configure the udp4 instance to let it receive data\r
275   //\r
276   Status = Private->Udp4->Configure (Private->Udp4, &Private->Udp4CfgData);\r
277   if (EFI_ERROR (Status)) {\r
278     return Status;\r
279   }\r
280 \r
281   Private->AddressIsOk = FALSE;\r
282 \r
283   ZeroMem (Mode, sizeof (EFI_PXE_BASE_CODE_MODE));\r
284 \r
285   Mode->Started = TRUE;\r
286   Mode->TTL     = DEFAULT_TTL;\r
287   Mode->ToS     = DEFAULT_ToS;\r
288   Mode->AutoArp = TRUE;\r
289 \r
290   //\r
291   // Create the event for Arp Cache checking.\r
292   //\r
293   Status = gBS->CreateEvent (\r
294                   EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
295                   TPL_CALLBACK,\r
296                   ArpCacheUpdateTimeout,\r
297                   This,\r
298                   &Private->GetArpCacheEvent\r
299                   );\r
300   if (EFI_ERROR (Status)) {\r
301     goto ON_EXIT;\r
302   }\r
303 \r
304   //\r
305   // Start the timeout timer event.\r
306   //\r
307   Status = gBS->SetTimer (\r
308                   Private->GetArpCacheEvent,\r
309                   TimerPeriodic,\r
310                   TICKS_PER_SECOND\r
311                   );\r
312 \r
313   if (EFI_ERROR (Status)) {\r
314     goto ON_EXIT;\r
315   }\r
316 \r
317   //\r
318   // Create ICMP error receiving event\r
319   //\r
320   Status = gBS->CreateEvent (\r
321                   EVT_NOTIFY_SIGNAL,\r
322                   TPL_NOTIFY,\r
323                   IcmpErrorListenHandler,\r
324                   Private,\r
325                   &(Private->IcmpErrorRcvToken.Event)\r
326                   );\r
327   if (EFI_ERROR (Status)) {\r
328     goto ON_EXIT;\r
329   }\r
330 \r
331   Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4ConfigData);\r
332   if (EFI_ERROR (Status)) {\r
333     goto ON_EXIT;\r
334   }\r
335 \r
336   //\r
337   // start to listen incoming packet\r
338   //\r
339   Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpErrorRcvToken);\r
340   if (!EFI_ERROR (Status)) {\r
341     return Status;\r
342   }\r
343 \r
344 ON_EXIT:\r
345   Private->Ip4->Configure (Private->Ip4, NULL);\r
346 \r
347   if (Private->IcmpErrorRcvToken.Event != NULL) {\r
348     gBS->CloseEvent (Private->IcmpErrorRcvToken.Event);\r
349   }\r
350 \r
351   if (Private->GetArpCacheEvent != NULL) {\r
352     gBS->SetTimer (Private->GetArpCacheEvent, TimerCancel, 0);\r
353     gBS->CloseEvent (Private->GetArpCacheEvent);\r
354   }\r
355 \r
356   Mode->Started = FALSE;\r
357   Mode->TTL     = 0;\r
358   Mode->ToS     = 0;\r
359   Mode->AutoArp = FALSE;\r
360 \r
361   return Status;\r
362 }\r
363 \r
364 \r
365 /**\r
366   GC_NOTO: Add function description\r
367 \r
368   @param  This                                        GC_NOTO: add argument\r
369                                                       description\r
370 \r
371   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
372                                                       return value\r
373   @retval EFI_NOT_STARTED                             GC_NOTO: Add description for\r
374                                                       return value\r
375   @retval EFI_SUCCESS                                 GC_NOTO: Add description for\r
376                                                       return value\r
377 \r
378 **/\r
379 EFI_STATUS\r
380 EFIAPI\r
381 EfiPxeBcStop (\r
382   IN EFI_PXE_BASE_CODE_PROTOCOL       *This\r
383   )\r
384 {\r
385   PXEBC_PRIVATE_DATA      *Private;\r
386   EFI_PXE_BASE_CODE_MODE  *Mode;\r
387 \r
388   if (This == NULL) {\r
389     return EFI_INVALID_PARAMETER;\r
390   }\r
391 \r
392   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
393   Mode    = Private->PxeBc.Mode;\r
394 \r
395   if (!Mode->Started) {\r
396     return EFI_NOT_STARTED;\r
397   }\r
398 \r
399   Private->Ip4->Cancel (Private->Ip4, NULL);\r
400   //\r
401   // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's\r
402   // events.\r
403   //\r
404   NetLibDispatchDpc ();\r
405 \r
406   Private->Ip4->Configure (Private->Ip4, NULL);\r
407 \r
408   //\r
409   // Close the ICMP error receiving event.\r
410   //\r
411   gBS->CloseEvent (Private->IcmpErrorRcvToken.Event);\r
412 \r
413   //\r
414   // Cancel the TimeoutEvent timer.\r
415   //\r
416   gBS->SetTimer (Private->GetArpCacheEvent, TimerCancel, 0);\r
417 \r
418   //\r
419   // Close the TimeoutEvent event.\r
420   //\r
421   gBS->CloseEvent (Private->GetArpCacheEvent);\r
422 \r
423   Mode->Started = FALSE;\r
424 \r
425 \r
426   //\r
427   // Reset and leave joined groups\r
428   //\r
429   Private->Udp4->Groups (Private->Udp4, FALSE, NULL);\r
430 \r
431   Private->Udp4->Configure (Private->Udp4, NULL);\r
432 \r
433   Private->Dhcp4->Stop (Private->Dhcp4);\r
434   Private->Dhcp4->Configure (Private->Dhcp4, NULL);\r
435 \r
436   Private->FileSize = 0;\r
437 \r
438   return EFI_SUCCESS;\r
439 }\r
440 \r
441 \r
442 /**\r
443   GC_NOTO: Add function description\r
444 \r
445   @param  This                                        GC_NOTO: add argument\r
446                                                       description\r
447   @param  SortOffers                                  GC_NOTO: add argument\r
448                                                       description\r
449 \r
450   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
451                                                       return value\r
452   @retval EFI_NOT_STARTED                             GC_NOTO: Add description for\r
453                                                       return value\r
454 \r
455 **/\r
456 EFI_STATUS\r
457 EFIAPI\r
458 EfiPxeBcDhcp (\r
459   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,\r
460   IN BOOLEAN                          SortOffers\r
461   )\r
462 {\r
463   PXEBC_PRIVATE_DATA      *Private;\r
464   EFI_PXE_BASE_CODE_MODE  *Mode;\r
465   EFI_DHCP4_PROTOCOL      *Dhcp4;\r
466   EFI_DHCP4_CONFIG_DATA   Dhcp4CfgData;\r
467   EFI_DHCP4_MODE_DATA     Dhcp4Mode;\r
468   EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];\r
469   UINT32                  OptCount;\r
470   UINT32                  DiscoverTimeout;\r
471   UINTN                   Index;\r
472   EFI_STATUS              Status;\r
473   EFI_ARP_CONFIG_DATA     ArpConfigData;\r
474 \r
475   if (This == NULL) {\r
476     return EFI_INVALID_PARAMETER;\r
477   }\r
478 \r
479   Status              = EFI_SUCCESS;\r
480   Private             = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
481   Mode                = Private->PxeBc.Mode;\r
482   Dhcp4               = Private->Dhcp4;\r
483   Private->Function   = EFI_PXE_BASE_CODE_FUNCTION_DHCP;\r
484   Private->SortOffers = SortOffers;\r
485 \r
486   if (!Mode->Started) {\r
487     return EFI_NOT_STARTED;\r
488   }\r
489 \r
490   Mode->IcmpErrorReceived = FALSE;\r
491 \r
492   //\r
493   // Initialize the DHCP options and build the option list\r
494   //\r
495   OptCount = PxeBcBuildDhcpOptions (Private, OptList, TRUE);\r
496 \r
497   //\r
498   // Set the DHCP4 config data.\r
499   //\r
500   ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));\r
501   Dhcp4CfgData.OptionCount      = OptCount;\r
502   Dhcp4CfgData.OptionList       = OptList;\r
503   Dhcp4CfgData.Dhcp4Callback    = PxeBcDhcpCallBack;\r
504   Dhcp4CfgData.CallbackContext  = Private;\r
505   Dhcp4CfgData.DiscoverTryCount = 1;\r
506   Dhcp4CfgData.DiscoverTimeout  = &DiscoverTimeout;\r
507 \r
508   for (Index = 0; Index < PXEBC_DHCP4_DISCOVER_RETRIES; Index++) {\r
509     //\r
510     // The four discovery timeouts are 4, 8, 16, 32 seconds respectively.\r
511     //\r
512     DiscoverTimeout = (PXEBC_DHCP4_DISCOVER_INIT_TIMEOUT << Index);\r
513 \r
514     Status          = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);\r
515     if (EFI_ERROR (Status)) {\r
516       break;\r
517     }\r
518     //\r
519     // Zero those arrays to record the varies numbers of DHCP OFFERS.\r
520     //\r
521     Private->NumOffers   = 0;\r
522     Private->BootpIndex  = 0;\r
523     ZeroMem (Private->ServerCount, sizeof (Private->ServerCount));\r
524     ZeroMem (Private->ProxyIndex, sizeof (Private->ProxyIndex));\r
525 \r
526     Status = Dhcp4->Start (Dhcp4, NULL);\r
527     if (EFI_ERROR (Status)) {\r
528       if (Status == EFI_TIMEOUT) {\r
529         //\r
530         // If no response is received or all received offers don't match\r
531         // the PXE boot requirements, EFI_TIMEOUT will be returned.\r
532         //\r
533         continue;\r
534       }\r
535       if (Status == EFI_ICMP_ERROR) {\r
536         Mode->IcmpErrorReceived = TRUE;\r
537       }\r
538       //\r
539       // Other error status means the DHCP really fails.\r
540       //\r
541       break;\r
542     }\r
543 \r
544     Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);\r
545     if (EFI_ERROR (Status)) {\r
546       break;\r
547     }\r
548 \r
549     ASSERT (Dhcp4Mode.State == Dhcp4Bound);\r
550 \r
551     CopyMem (&Private->StationIp, &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
552     CopyMem (&Private->SubnetMask, &Dhcp4Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
553     CopyMem (&Private->GatewayIp, &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
554 \r
555     //\r
556     // Check the selected offer to see whether BINL is required, if no or BINL is\r
557     // finished, set the various Mode members.\r
558     //\r
559     Status = PxeBcCheckSelectedOffer (Private);\r
560     if (!EFI_ERROR (Status)) {\r
561       break;\r
562     }\r
563   }\r
564 \r
565   if (EFI_ERROR (Status)) {\r
566     Dhcp4->Stop (Dhcp4);\r
567     Dhcp4->Configure (Dhcp4, NULL);\r
568   } else {\r
569     //\r
570     // Remove the previously configured option list and callback function\r
571     //\r
572     ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));\r
573     Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);\r
574 \r
575     Private->AddressIsOk = TRUE;\r
576 \r
577     if (!Mode->UsingIpv6) {\r
578       //\r
579       // If in IPv4 mode, configure the corresponding ARP with this new\r
580       // station IP address.\r
581       //\r
582       ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));\r
583 \r
584       ArpConfigData.SwAddressType   = 0x0800;\r
585       ArpConfigData.SwAddressLength = sizeof (EFI_IPv4_ADDRESS);\r
586       ArpConfigData.StationAddress  = &Private->StationIp.v4;\r
587 \r
588       Private->Arp->Configure (Private->Arp, NULL);\r
589       Private->Arp->Configure (Private->Arp, &ArpConfigData);\r
590 \r
591       //\r
592       // Updated the route table. Fill the first entry.\r
593       //\r
594       Mode->RouteTableEntries                = 1;\r
595       Mode->RouteTable[0].IpAddr.Addr[0]     = Private->StationIp.Addr[0] & Private->SubnetMask.Addr[0];\r
596       Mode->RouteTable[0].SubnetMask.Addr[0] = Private->SubnetMask.Addr[0];\r
597       Mode->RouteTable[0].GwAddr.Addr[0]     = 0;\r
598 \r
599       //\r
600       // Create the default route entry if there is a default router.\r
601       //\r
602       if (Private->GatewayIp.Addr[0] != 0) {\r
603         Mode->RouteTableEntries                = 2;\r
604         Mode->RouteTable[1].IpAddr.Addr[0]     = 0;\r
605         Mode->RouteTable[1].SubnetMask.Addr[0] = 0;\r
606         Mode->RouteTable[1].GwAddr.Addr[0]     = Private->GatewayIp.Addr[0];\r
607       }\r
608     }\r
609   }\r
610 \r
611   return Status;\r
612 }\r
613 \r
614 \r
615 /**\r
616   GC_NOTO: Add function description\r
617 \r
618   @param  This                                        GC_NOTO: add argument\r
619                                                       description\r
620   @param  Type                                        GC_NOTO: add argument\r
621                                                       description\r
622   @param  Layer                                       GC_NOTO: add argument\r
623                                                       description\r
624   @param  UseBis                                      GC_NOTO: add argument\r
625                                                       description\r
626   @param  Info                                        GC_NOTO: add argument\r
627                                                       description\r
628 \r
629   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
630                                                       return value\r
631   @retval EFI_NOT_STARTED                             GC_NOTO: Add description for\r
632                                                       return value\r
633   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
634                                                       return value\r
635   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
636                                                       return value\r
637   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
638                                                       return value\r
639   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
640                                                       return value\r
641 \r
642 **/\r
643 EFI_STATUS\r
644 EFIAPI\r
645 EfiPxeBcDiscover (\r
646   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,\r
647   IN UINT16                           Type,\r
648   IN UINT16                           *Layer,\r
649   IN BOOLEAN                          UseBis,\r
650   IN EFI_PXE_BASE_CODE_DISCOVER_INFO  *Info   OPTIONAL\r
651   )\r
652 {\r
653   PXEBC_PRIVATE_DATA              *Private;\r
654   EFI_PXE_BASE_CODE_MODE          *Mode;\r
655   EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;\r
656   EFI_PXE_BASE_CODE_SRVLIST       *SrvList;\r
657   EFI_PXE_BASE_CODE_SRVLIST       DefaultSrvList;\r
658   PXEBC_CACHED_DHCP4_PACKET       *Packet;\r
659   PXEBC_VENDOR_OPTION            *VendorOpt;\r
660   UINT16                          Index;\r
661   EFI_STATUS                      Status;\r
662   PXEBC_BOOT_SVR_ENTRY            *BootSvrEntry;\r
663 \r
664   if (This == NULL) {\r
665     return EFI_INVALID_PARAMETER;\r
666   }\r
667 \r
668   Private           = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
669   Mode              = Private->PxeBc.Mode;\r
670   BootSvrEntry      = NULL;\r
671   SrvList           = NULL;\r
672   Status            = EFI_DEVICE_ERROR;\r
673   Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;\r
674 \r
675   if (!Private->AddressIsOk) {\r
676     return EFI_INVALID_PARAMETER;\r
677   }\r
678 \r
679   if (!Mode->Started) {\r
680     return EFI_NOT_STARTED;\r
681   }\r
682 \r
683   Mode->IcmpErrorReceived = FALSE;\r
684 \r
685   //\r
686   // If layer isn't EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL,\r
687   //   use the previous setting;\r
688   // If info isn't offered,\r
689   //   use the cached DhcpAck and ProxyOffer packets.\r
690   //\r
691   if (*Layer != EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) {\r
692 \r
693     if (!Mode->PxeDiscoverValid || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {\r
694 \r
695       return EFI_INVALID_PARAMETER;\r
696     }\r
697 \r
698     DefaultInfo.IpCnt                 = 1;\r
699     DefaultInfo.UseUCast              = TRUE;\r
700 \r
701     DefaultSrvList.Type               = Type;\r
702     DefaultSrvList.AcceptAnyResponse  = FALSE;\r
703     DefaultSrvList.IpAddr.Addr[0]     = Private->ServerIp.Addr[0];\r
704 \r
705     SrvList = &DefaultSrvList;\r
706     Info = &DefaultInfo;\r
707   } else if (Info == NULL) {\r
708     //\r
709     // Create info by the cached packet before\r
710     //\r
711     Packet    = (Mode->ProxyOfferReceived) ? &Private->ProxyOffer : &Private->Dhcp4Ack;\r
712     VendorOpt = &Packet->PxeVendorOption;\r
713 \r
714     if (!Mode->DhcpAckReceived || !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt->BitMap)) {\r
715       //\r
716       // Address is not acquired or no discovery options.\r
717       //\r
718       return EFI_INVALID_PARAMETER;\r
719     }\r
720 \r
721     DefaultInfo.UseMCast    = (BOOLEAN)!IS_DISABLE_MCAST_DISCOVER (VendorOpt->DiscoverCtrl);\r
722     DefaultInfo.UseBCast    = (BOOLEAN)!IS_DISABLE_BCAST_DISCOVER (VendorOpt->DiscoverCtrl);\r
723     DefaultInfo.MustUseList = (BOOLEAN) IS_ENABLE_USE_SERVER_LIST (VendorOpt->DiscoverCtrl);\r
724     DefaultInfo.UseUCast    = DefaultInfo.MustUseList;\r
725 \r
726     if (DefaultInfo.UseMCast) {\r
727       //\r
728       // Get the multicast discover ip address from vendor option.\r
729       //\r
730       CopyMem (&DefaultInfo.ServerMCastIp.Addr, &VendorOpt->DiscoverMcastIp, sizeof (EFI_IPv4_ADDRESS));\r
731     }\r
732 \r
733     DefaultInfo.IpCnt = 0;\r
734 \r
735     if (DefaultInfo.MustUseList) {\r
736       BootSvrEntry  = VendorOpt->BootSvr;\r
737       Status        = EFI_INVALID_PARAMETER;\r
738 \r
739       while (((UINT8) (BootSvrEntry - VendorOpt->BootSvr)) < VendorOpt->BootSvrLen) {\r
740 \r
741         if (BootSvrEntry->Type == HTONS (Type)) {\r
742           Status = EFI_SUCCESS;\r
743           break;\r
744         }\r
745 \r
746         BootSvrEntry = GET_NEXT_BOOT_SVR_ENTRY (BootSvrEntry);\r
747       }\r
748 \r
749       if (EFI_ERROR (Status)) {\r
750         return Status;\r
751       }\r
752 \r
753       DefaultInfo.IpCnt = BootSvrEntry->IpCnt;\r
754     }\r
755 \r
756     Info = &DefaultInfo;\r
757   } else {\r
758 \r
759     SrvList = Info->SrvList;\r
760 \r
761     if (!SrvList[0].AcceptAnyResponse) {\r
762 \r
763       for (Index = 1; Index < Info->IpCnt; Index++) {\r
764         if (SrvList[Index].AcceptAnyResponse) {\r
765           break;\r
766         }\r
767       }\r
768 \r
769       if (Index != Info->IpCnt) {\r
770         return EFI_INVALID_PARAMETER;\r
771       }\r
772     }\r
773   }\r
774 \r
775   if ((!Info->UseUCast && !Info->UseBCast && !Info->UseMCast) || (Info->MustUseList && Info->IpCnt == 0)) {\r
776 \r
777     return EFI_INVALID_PARAMETER;\r
778   }\r
779   //\r
780   // Execute discover by UniCast/BroadCast/MultiCast\r
781   //\r
782   if (Info->UseUCast) {\r
783 \r
784     for (Index = 0; Index < Info->IpCnt; Index++) {\r
785 \r
786       if (BootSvrEntry == NULL) {\r
787         Private->ServerIp.Addr[0] = SrvList[Index].IpAddr.Addr[0];\r
788       } else {\r
789         CopyMem (&Private->ServerIp, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));\r
790       }\r
791 \r
792       Status = PxeBcDiscvBootService (\r
793                 Private,\r
794                 Type,\r
795                 Layer,\r
796                 UseBis,\r
797                 &SrvList[Index].IpAddr,\r
798                 0,\r
799                 NULL,\r
800                 TRUE,\r
801                 &Private->PxeReply.Packet.Ack\r
802                 );\r
803     }\r
804 \r
805   } else if (Info->UseMCast) {\r
806 \r
807     Status = PxeBcDiscvBootService (\r
808               Private,\r
809               Type,\r
810               Layer,\r
811               UseBis,\r
812               &Info->ServerMCastIp,\r
813               0,\r
814               NULL,\r
815               TRUE,\r
816               &Private->PxeReply.Packet.Ack\r
817               );\r
818 \r
819   } else if (Info->UseBCast) {\r
820 \r
821     Status = PxeBcDiscvBootService (\r
822               Private,\r
823               Type,\r
824               Layer,\r
825               UseBis,\r
826               NULL,\r
827               Info->IpCnt,\r
828               SrvList,\r
829               TRUE,\r
830               &Private->PxeReply.Packet.Ack\r
831               );\r
832   }\r
833 \r
834   if (EFI_ERROR (Status) || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {\r
835     if (Status == EFI_ICMP_ERROR) {\r
836       Mode->IcmpErrorReceived = TRUE;\r
837     } else {\r
838       Status = EFI_DEVICE_ERROR;\r
839     }\r
840   } else {\r
841     PxeBcParseCachedDhcpPacket (&Private->PxeReply);\r
842   }\r
843 \r
844   if (Mode->PxeBisReplyReceived) {\r
845     CopyMem (&Private->ServerIp, &Mode->PxeReply.Dhcpv4.BootpSiAddr, sizeof (EFI_IPv4_ADDRESS));\r
846   }\r
847 \r
848   return Status;\r
849 }\r
850 \r
851 \r
852 /**\r
853   GC_NOTO: Add function description\r
854 \r
855   @param  This                                        GC_NOTO: add argument\r
856                                                       description\r
857   @param  Operation                                   GC_NOTO: add argument\r
858                                                       description\r
859   @param  BufferPtr                                   GC_NOTO: add argument\r
860                                                       description\r
861   @param  Overwrite                                   GC_NOTO: add argument\r
862                                                       description\r
863   @param  BufferSize                                  GC_NOTO: add argument\r
864                                                       description\r
865   @param  BlockSize                                   GC_NOTO: add argument\r
866                                                       description\r
867   @param  ServerIp                                    GC_NOTO: add argument\r
868                                                       description\r
869   @param  Filename                                    GC_NOTO: add argument\r
870                                                       description\r
871   @param  Info                                        GC_NOTO: add argument\r
872                                                       description\r
873   @param  DontUseBuffer                               GC_NOTO: add argument\r
874                                                       description\r
875 \r
876   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
877                                                       return value\r
878 \r
879 **/\r
880 EFI_STATUS\r
881 EFIAPI\r
882 EfiPxeBcMtftp (\r
883   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,\r
884   IN EFI_PXE_BASE_CODE_TFTP_OPCODE    Operation,\r
885   IN OUT VOID                         *BufferPtr,\r
886   IN BOOLEAN                          Overwrite,\r
887   IN OUT UINT64                       *BufferSize,\r
888   IN UINTN                            *BlockSize    OPTIONAL,\r
889   IN EFI_IP_ADDRESS                   *ServerIp,\r
890   IN UINT8                            *Filename,\r
891   IN EFI_PXE_BASE_CODE_MTFTP_INFO     *Info         OPTIONAL,\r
892   IN BOOLEAN                          DontUseBuffer\r
893   )\r
894 {\r
895   PXEBC_PRIVATE_DATA      *Private;\r
896   EFI_MTFTP4_CONFIG_DATA  Mtftp4Config;\r
897   EFI_STATUS              Status;\r
898   EFI_PXE_BASE_CODE_MODE  *Mode;\r
899   EFI_MAC_ADDRESS         TempMacAddr;\r
900 \r
901   if ((This == NULL) ||\r
902       (Filename == NULL) ||\r
903       (BufferSize == NULL) ||\r
904       ((ServerIp == NULL) || !Ip4IsUnicast (NTOHL (ServerIp->Addr[0]), 0)) ||\r
905       ((BufferPtr == NULL) && DontUseBuffer) ||\r
906       ((BlockSize != NULL) && (*BlockSize < 512))) {\r
907 \r
908     return EFI_INVALID_PARAMETER;\r
909   }\r
910 \r
911   Status  = EFI_DEVICE_ERROR;\r
912   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
913   Mode    = &Private->Mode;\r
914 \r
915   if (!Mode->AutoArp) {\r
916     //\r
917     // If AutoArp is set false, check arp cache\r
918     //\r
919     UpdateArpCache (This);\r
920     if (!FindInArpCache (Mode, &ServerIp->v4, &TempMacAddr)) {\r
921       return EFI_DEVICE_ERROR;\r
922     }\r
923   }\r
924 \r
925   Mode->TftpErrorReceived = FALSE;\r
926   Mode->IcmpErrorReceived = FALSE;\r
927 \r
928   Mtftp4Config.UseDefaultSetting = FALSE;\r
929   Mtftp4Config.TimeoutValue      = PXEBC_MTFTP_TIMEOUT;\r
930   Mtftp4Config.TryCount          = PXEBC_MTFTP_RETRIES;\r
931 \r
932   CopyMem (&Mtftp4Config.StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));\r
933   CopyMem (&Mtftp4Config.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
934   CopyMem (&Mtftp4Config.GatewayIp, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));\r
935   CopyMem (&Mtftp4Config.ServerIp, ServerIp, sizeof (EFI_IPv4_ADDRESS));\r
936 \r
937   switch (Operation) {\r
938 \r
939   case EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE:\r
940 \r
941     Status = PxeBcTftpGetFileSize (\r
942               Private,\r
943               &Mtftp4Config,\r
944               Filename,\r
945               BlockSize,\r
946               BufferSize\r
947               );\r
948 \r
949     if (!EFI_ERROR (Status)) {\r
950       Status = EFI_BUFFER_TOO_SMALL;\r
951     }\r
952 \r
953     break;\r
954 \r
955   case EFI_PXE_BASE_CODE_TFTP_READ_FILE:\r
956 \r
957     Status = PxeBcTftpReadFile (\r
958               Private,\r
959               &Mtftp4Config,\r
960               Filename,\r
961               BlockSize,\r
962               BufferPtr,\r
963               BufferSize,\r
964               DontUseBuffer\r
965               );\r
966 \r
967     break;\r
968 \r
969   case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:\r
970 \r
971     Status = PxeBcTftpWriteFile (\r
972               Private,\r
973               &Mtftp4Config,\r
974               Filename,\r
975               Overwrite,\r
976               BlockSize,\r
977               BufferPtr,\r
978               BufferSize\r
979               );\r
980 \r
981     break;\r
982 \r
983   case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:\r
984 \r
985     Status = PxeBcTftpReadDirectory (\r
986               Private,\r
987               &Mtftp4Config,\r
988               Filename,\r
989               BlockSize,\r
990               BufferPtr,\r
991               BufferSize,\r
992               DontUseBuffer\r
993               );\r
994 \r
995     break;\r
996 \r
997   case EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE:\r
998   case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:\r
999   case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:\r
1000     Status = EFI_UNSUPPORTED;\r
1001     break;\r
1002 \r
1003   default:\r
1004 \r
1005     Status = EFI_INVALID_PARAMETER;\r
1006     break;\r
1007   }\r
1008 \r
1009   if (Status == EFI_ICMP_ERROR) {\r
1010     Mode->IcmpErrorReceived = TRUE;\r
1011   }\r
1012 \r
1013   return Status;\r
1014 }\r
1015 \r
1016 \r
1017 /**\r
1018   GC_NOTO: Add function description\r
1019 \r
1020   @param  This                                        GC_NOTO: add argument\r
1021                                                       description\r
1022   @param  OpFlags                                     GC_NOTO: add argument\r
1023                                                       description\r
1024   @param  DestIp                                      GC_NOTO: add argument\r
1025                                                       description\r
1026   @param  DestPort                                    GC_NOTO: add argument\r
1027                                                       description\r
1028   @param  GatewayIp                                   GC_NOTO: add argument\r
1029                                                       description\r
1030   @param  SrcIp                                       GC_NOTO: add argument\r
1031                                                       description\r
1032   @param  SrcPort                                     GC_NOTO: add argument\r
1033                                                       description\r
1034   @param  HeaderSize                                  GC_NOTO: add argument\r
1035                                                       description\r
1036   @param  HeaderPtr                                   GC_NOTO: add argument\r
1037                                                       description\r
1038   @param  BufferSize                                  GC_NOTO: add argument\r
1039                                                       description\r
1040   @param  BufferPtr                                   GC_NOTO: add argument\r
1041                                                       description\r
1042 \r
1043   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1044                                                       return value\r
1045   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1046                                                       return value\r
1047   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1048                                                       return value\r
1049   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1050                                                       return value\r
1051   @retval EFI_OUT_OF_RESOURCES                        GC_NOTO: Add description for\r
1052                                                       return value\r
1053 \r
1054 **/\r
1055 EFI_STATUS\r
1056 EFIAPI\r
1057 EfiPxeBcUdpWrite (\r
1058   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,\r
1059   IN UINT16                           OpFlags,\r
1060   IN EFI_IP_ADDRESS                   *DestIp,\r
1061   IN EFI_PXE_BASE_CODE_UDP_PORT       *DestPort,\r
1062   IN EFI_IP_ADDRESS                   *GatewayIp  OPTIONAL,\r
1063   IN EFI_IP_ADDRESS                   *SrcIp      OPTIONAL,\r
1064   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *SrcPort    OPTIONAL,\r
1065   IN UINTN                            *HeaderSize OPTIONAL,\r
1066   IN VOID                             *HeaderPtr  OPTIONAL,\r
1067   IN UINTN                            *BufferSize,\r
1068   IN VOID                             *BufferPtr\r
1069   )\r
1070 {\r
1071   PXEBC_PRIVATE_DATA        *Private;\r
1072   EFI_UDP4_PROTOCOL         *Udp4;\r
1073   EFI_UDP4_COMPLETION_TOKEN Token;\r
1074   EFI_UDP4_TRANSMIT_DATA    *Udp4TxData;\r
1075   UINT32                    FragCount;\r
1076   UINT32                    DataLength;\r
1077   EFI_UDP4_SESSION_DATA     Udp4Session;\r
1078   EFI_STATUS                Status;\r
1079   BOOLEAN                   IsDone;\r
1080   UINT16                    RandomSrcPort;\r
1081   EFI_PXE_BASE_CODE_MODE    *Mode;\r
1082   EFI_MAC_ADDRESS           TempMacAddr;\r
1083 \r
1084   IsDone = FALSE;\r
1085 \r
1086   if ((This == NULL) || (DestIp == NULL) || (DestPort == NULL)) {\r
1087     return EFI_INVALID_PARAMETER;\r
1088   }\r
1089 \r
1090   if ((GatewayIp != NULL) && !Ip4IsUnicast (NTOHL (GatewayIp->Addr[0]), 0)) {\r
1091     //\r
1092     // Gateway is provided but it's not a unicast IP address.\r
1093     //\r
1094     return EFI_INVALID_PARAMETER;\r
1095   }\r
1096 \r
1097   if ((HeaderSize != NULL) && ((*HeaderSize == 0) || (HeaderPtr == NULL))) {\r
1098     //\r
1099     // The HeaderSize ptr isn't NULL and: 1. the value is zero; or 2. the HeaderPtr\r
1100     // is NULL.\r
1101     //\r
1102     return EFI_INVALID_PARAMETER;\r
1103   }\r
1104 \r
1105   if ((BufferSize == NULL) || ((*BufferSize != 0) && (BufferPtr == NULL))) {\r
1106     return EFI_INVALID_PARAMETER;\r
1107   }\r
1108 \r
1109   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
1110   Udp4    = Private->Udp4;\r
1111   Mode    = &Private->Mode;\r
1112 \r
1113   if (!Private->AddressIsOk && (SrcIp == NULL)) {\r
1114     return EFI_INVALID_PARAMETER;\r
1115   }\r
1116 \r
1117   if (!Mode->AutoArp) {\r
1118     //\r
1119     // If AutoArp is set false, check arp cache\r
1120     //\r
1121     UpdateArpCache (This);\r
1122     if (!FindInArpCache (Mode, &DestIp->v4, &TempMacAddr)) {\r
1123       return EFI_DEVICE_ERROR;\r
1124     }\r
1125   }\r
1126 \r
1127   Mode->IcmpErrorReceived = FALSE;\r
1128 \r
1129   if (SrcIp == NULL) {\r
1130     SrcIp = &Private->StationIp;\r
1131 \r
1132     if (GatewayIp == NULL) {\r
1133       GatewayIp = &Private->GatewayIp;\r
1134     }\r
1135   }\r
1136 \r
1137   if ((SrcPort == NULL) || (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT)) {\r
1138     RandomSrcPort = (UINT16) (NET_RANDOM (NetRandomInitSeed ()) % 10000 + 1024);\r
1139 \r
1140     if (SrcPort == NULL) {\r
1141 \r
1142       SrcPort  = &RandomSrcPort;\r
1143     } else {\r
1144 \r
1145       *SrcPort = RandomSrcPort;\r
1146     }\r
1147   }\r
1148 \r
1149   ZeroMem (&Token, sizeof (EFI_UDP4_COMPLETION_TOKEN));\r
1150   ZeroMem (&Udp4Session, sizeof (EFI_UDP4_SESSION_DATA));\r
1151 \r
1152   CopyMem (&Udp4Session.DestinationAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));\r
1153   Udp4Session.DestinationPort = *DestPort;\r
1154   CopyMem (&Udp4Session.SourceAddress, SrcIp, sizeof (EFI_IPv4_ADDRESS));\r
1155   Udp4Session.SourcePort = *SrcPort;\r
1156 \r
1157   FragCount = (HeaderSize != NULL) ? 2 : 1;\r
1158   Udp4TxData = (EFI_UDP4_TRANSMIT_DATA *) AllocatePool (sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA));\r
1159   if (Udp4TxData == NULL) {\r
1160     return EFI_OUT_OF_RESOURCES;\r
1161   }\r
1162 \r
1163   Udp4TxData->FragmentCount = FragCount;\r
1164   Udp4TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;\r
1165   Udp4TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;\r
1166   DataLength = (UINT32) *BufferSize;\r
1167 \r
1168   if (FragCount == 2) {\r
1169 \r
1170     Udp4TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;\r
1171     Udp4TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;\r
1172     DataLength += (UINT32) *HeaderSize;\r
1173   }\r
1174 \r
1175   Udp4TxData->GatewayAddress  = (EFI_IPv4_ADDRESS *) GatewayIp;\r
1176   Udp4TxData->UdpSessionData  = &Udp4Session;\r
1177   Udp4TxData->DataLength      = DataLength;\r
1178   Token.Packet.TxData         = Udp4TxData;\r
1179 \r
1180   Status = gBS->CreateEvent (\r
1181                   EVT_NOTIFY_SIGNAL,\r
1182                   TPL_NOTIFY,\r
1183                   PxeBcCommonNotify,\r
1184                   &IsDone,\r
1185                   &Token.Event\r
1186                   );\r
1187   if (EFI_ERROR (Status)) {\r
1188     goto ON_EXIT;\r
1189   }\r
1190 \r
1191   Status = Udp4->Transmit (Udp4, &Token);\r
1192   if (EFI_ERROR (Status)) {\r
1193     if (Status == EFI_ICMP_ERROR) {\r
1194       Mode->IcmpErrorReceived = TRUE;\r
1195     }\r
1196     goto ON_EXIT;\r
1197   }\r
1198 \r
1199   while (!IsDone) {\r
1200 \r
1201     Udp4->Poll (Udp4);\r
1202   }\r
1203 \r
1204   Status = Token.Status;\r
1205 \r
1206 ON_EXIT:\r
1207 \r
1208   if (Token.Event != NULL) {\r
1209     gBS->CloseEvent (Token.Event);\r
1210   }\r
1211 \r
1212   gBS->FreePool (Udp4TxData);\r
1213 \r
1214   return Status;\r
1215 }\r
1216 \r
1217 /**\r
1218   Validate IP packages by IP filter settings\r
1219 \r
1220   @param  PxeBcMode          Pointer to EFI_PXEBC_MODE\r
1221 \r
1222   @param  Session            Received UDP session\r
1223 \r
1224   @retval TRUE               The UDP package matches IP filters\r
1225 \r
1226   @retval FLASE              The UDP package doesn't matches IP filters\r
1227 \r
1228 **/\r
1229 STATIC\r
1230 BOOLEAN\r
1231 CheckIpByFilter (\r
1232   EFI_PXE_BASE_CODE_MODE    *PxeBcMode,\r
1233   EFI_UDP4_SESSION_DATA     *Session\r
1234   )\r
1235 {\r
1236   UINTN                   Index;\r
1237   EFI_IPv4_ADDRESS        Ip4Address;\r
1238   EFI_IPv4_ADDRESS        DestIp4Address;\r
1239 \r
1240   if (PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) {\r
1241     return TRUE;\r
1242   }\r
1243 \r
1244   CopyMem (&DestIp4Address, &Session->DestinationAddress, sizeof (DestIp4Address));\r
1245   if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) &&\r
1246       IP4_IS_MULTICAST (EFI_NTOHL (DestIp4Address))\r
1247       ) {\r
1248     return TRUE;\r
1249   }\r
1250 \r
1251   if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) &&\r
1252       IP4_IS_LOCAL_BROADCAST (EFI_NTOHL (DestIp4Address))\r
1253       ) {\r
1254     return TRUE;\r
1255   }\r
1256 \r
1257   CopyMem (&Ip4Address, &PxeBcMode->StationIp.v4, sizeof (Ip4Address));\r
1258   if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) &&\r
1259       EFI_IP4_EQUAL (&Ip4Address, &DestIp4Address)\r
1260       ) {\r
1261     return TRUE;\r
1262   }\r
1263 \r
1264   for (Index = 0; Index < PxeBcMode->IpFilter.IpCnt; ++Index) {\r
1265     CopyMem (&Ip4Address, &PxeBcMode->IpFilter.IpList[Index].v4, sizeof (Ip4Address));\r
1266     if (EFI_IP4_EQUAL (&Ip4Address, &DestIp4Address)) {\r
1267       return TRUE;\r
1268     }\r
1269   }\r
1270 \r
1271   return FALSE;\r
1272 }\r
1273 \r
1274 /**\r
1275   GC_NOTO: Add function description\r
1276 \r
1277   @param  This                                        GC_NOTO: add argument\r
1278                                                       description\r
1279   @param  OpFlags                                     GC_NOTO: add argument\r
1280                                                       description\r
1281   @param  DestIp                                      GC_NOTO: add argument\r
1282                                                       description\r
1283   @param  DestPort                                    GC_NOTO: add argument\r
1284                                                       description\r
1285   @param  SrcIp                                       GC_NOTO: add argument\r
1286                                                       description\r
1287   @param  SrcPort                                     GC_NOTO: add argument\r
1288                                                       description\r
1289   @param  HeaderSize                                  GC_NOTO: add argument\r
1290                                                       description\r
1291   @param  HeaderPtr                                   GC_NOTO: add argument\r
1292                                                       description\r
1293   @param  BufferSize                                  GC_NOTO: add argument\r
1294                                                       description\r
1295   @param  BufferPtr                                   GC_NOTO: add argument\r
1296                                                       description\r
1297 \r
1298   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1299                                                       return value\r
1300   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1301                                                       return value\r
1302   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1303                                                       return value\r
1304   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1305                                                       return value\r
1306   @retval EFI_NOT_STARTED                             GC_NOTO: Add description for\r
1307                                                       return value\r
1308   @retval EFI_OUT_OF_RESOURCES                        GC_NOTO: Add description for\r
1309                                                       return value\r
1310 \r
1311 **/\r
1312 EFI_STATUS\r
1313 EFIAPI\r
1314 EfiPxeBcUdpRead (\r
1315   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,\r
1316   IN UINT16                           OpFlags,\r
1317   IN OUT EFI_IP_ADDRESS               *DestIp, OPTIONAL\r
1318   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *DestPort, OPTIONAL\r
1319   IN OUT EFI_IP_ADDRESS               *SrcIp, OPTIONAL\r
1320   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *SrcPort, OPTIONAL\r
1321   IN UINTN                            *HeaderSize, OPTIONAL\r
1322   IN VOID                             *HeaderPtr, OPTIONAL\r
1323   IN OUT UINTN                        *BufferSize,\r
1324   IN VOID                             *BufferPtr\r
1325   )\r
1326 {\r
1327   PXEBC_PRIVATE_DATA        *Private;\r
1328   EFI_PXE_BASE_CODE_MODE    *Mode;\r
1329   EFI_UDP4_PROTOCOL         *Udp4;\r
1330   EFI_UDP4_COMPLETION_TOKEN Token;\r
1331   EFI_UDP4_RECEIVE_DATA     *RxData;\r
1332   EFI_UDP4_SESSION_DATA     *Session;\r
1333   EFI_STATUS                Status;\r
1334   BOOLEAN                   IsDone;\r
1335   BOOLEAN                   Matched;\r
1336   UINTN                     CopyLen;\r
1337 \r
1338   if (This == NULL || DestIp == NULL || DestPort == NULL) {\r
1339     return EFI_INVALID_PARAMETER;\r
1340   }\r
1341 \r
1342   if ((!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && (DestPort == NULL)) ||\r
1343       (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && (SrcIp == NULL)) ||\r
1344       (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && (SrcPort == NULL))) {\r
1345     return EFI_INVALID_PARAMETER;\r
1346   }\r
1347 \r
1348   if (((HeaderSize != NULL) && (*HeaderSize == 0)) || ((HeaderPtr == NULL) && (*HeaderSize != 0))) {\r
1349     return EFI_INVALID_PARAMETER;\r
1350   }\r
1351 \r
1352   if ((BufferSize == NULL) || ((BufferPtr == NULL) && (*BufferSize != 0))) {\r
1353     return EFI_INVALID_PARAMETER;\r
1354   }\r
1355 \r
1356   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
1357   Mode    = Private->PxeBc.Mode;\r
1358   Udp4    = Private->Udp4;\r
1359 \r
1360   if (!Mode->Started) {\r
1361     return EFI_NOT_STARTED;\r
1362   }\r
1363 \r
1364   Mode->IcmpErrorReceived = FALSE;\r
1365 \r
1366   Status = gBS->CreateEvent (\r
1367                   EVT_NOTIFY_SIGNAL,\r
1368                   TPL_NOTIFY,\r
1369                   PxeBcCommonNotify,\r
1370                   &IsDone,\r
1371                   &Token.Event\r
1372                   );\r
1373   if (EFI_ERROR (Status)) {\r
1374     return EFI_OUT_OF_RESOURCES;\r
1375   }\r
1376 \r
1377   IsDone = FALSE;\r
1378   Status = Udp4->Receive (Udp4, &Token);\r
1379   if (EFI_ERROR (Status)) {\r
1380     if (Status == EFI_ICMP_ERROR) {\r
1381       Mode->IcmpErrorReceived = TRUE;\r
1382     }\r
1383     goto ON_EXIT;\r
1384   }\r
1385 \r
1386   Udp4->Poll (Udp4);\r
1387 \r
1388   if (!IsDone) {\r
1389     Status = EFI_TIMEOUT;\r
1390   } else {\r
1391 \r
1392     //\r
1393     // check whether this packet matches the filters\r
1394     //\r
1395     if (EFI_ERROR (Token.Status)){\r
1396       goto ON_EXIT;\r
1397     }\r
1398 \r
1399     RxData  = Token.Packet.RxData;\r
1400     Session = &RxData->UdpSession;\r
1401 \r
1402     Matched = FALSE;\r
1403 \r
1404     if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) {\r
1405       //\r
1406       // Check UDP package by IP filter settings\r
1407       //\r
1408       if (CheckIpByFilter (Mode, Session)) {\r
1409         Matched = TRUE;\r
1410       }\r
1411     }\r
1412 \r
1413     if (Matched) {\r
1414       //\r
1415       // Match the destination ip of the received udp dgram\r
1416       //\r
1417       if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) {\r
1418         Matched = TRUE;\r
1419 \r
1420         if (DestIp != NULL) {\r
1421           CopyMem (DestIp, &Session->DestinationAddress, sizeof (EFI_IPv4_ADDRESS));\r
1422         }\r
1423       } else {\r
1424         if (DestIp != NULL) {\r
1425           if (EFI_IP4_EQUAL (DestIp, &Session->DestinationAddress)) {\r
1426             Matched = TRUE;\r
1427           }\r
1428         } else {\r
1429           if (EFI_IP4_EQUAL (&Private->StationIp, &Session->DestinationAddress)) {\r
1430             Matched = TRUE;\r
1431           }\r
1432         }\r
1433       }\r
1434     }\r
1435 \r
1436     if (Matched) {\r
1437       //\r
1438       // Match the destination port of the received udp dgram\r
1439       //\r
1440       if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) {\r
1441 \r
1442         if (DestPort != NULL) {\r
1443           *DestPort = Session->DestinationPort;\r
1444         }\r
1445       } else {\r
1446 \r
1447         if (*DestPort != Session->DestinationPort) {\r
1448           Matched = FALSE;\r
1449         }\r
1450       }\r
1451     }\r
1452 \r
1453     if (Matched) {\r
1454       //\r
1455       // Match the source ip of the received udp dgram\r
1456       //\r
1457       if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) {\r
1458 \r
1459         if (SrcIp != NULL) {\r
1460           CopyMem (SrcIp, &Session->SourceAddress, sizeof (EFI_IPv4_ADDRESS));\r
1461         }\r
1462       } else {\r
1463 \r
1464         if (!EFI_IP4_EQUAL (SrcIp, &Session->SourceAddress)) {\r
1465           Matched = FALSE;\r
1466         }\r
1467       }\r
1468     }\r
1469 \r
1470     if (Matched) {\r
1471       //\r
1472       // Match the source port of the received udp dgram\r
1473       //\r
1474       if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) {\r
1475 \r
1476         if (SrcPort != NULL) {\r
1477           *SrcPort = Session->SourcePort;\r
1478         }\r
1479       } else {\r
1480 \r
1481         if (*SrcPort != Session->SourcePort) {\r
1482           Matched = FALSE;\r
1483         }\r
1484       }\r
1485     }\r
1486 \r
1487     if (Matched) {\r
1488 \r
1489       CopyLen = 0;\r
1490 \r
1491       if (HeaderSize != NULL) {\r
1492         CopyLen = MIN (*HeaderSize, RxData->DataLength);\r
1493         CopyMem (HeaderPtr, RxData->FragmentTable[0].FragmentBuffer, CopyLen);\r
1494         *HeaderSize = CopyLen;\r
1495       }\r
1496 \r
1497       if (RxData->DataLength - CopyLen > *BufferSize) {\r
1498 \r
1499         Status = EFI_BUFFER_TOO_SMALL;\r
1500       } else {\r
1501 \r
1502         *BufferSize = RxData->DataLength - CopyLen;\r
1503         CopyMem (BufferPtr, (UINT8 *) RxData->FragmentTable[0].FragmentBuffer + CopyLen, *BufferSize);\r
1504       }\r
1505     } else {\r
1506 \r
1507       Status = EFI_TIMEOUT;\r
1508     }\r
1509 \r
1510     //\r
1511     // Recycle the RxData\r
1512     //\r
1513     gBS->SignalEvent (RxData->RecycleSignal);\r
1514   }\r
1515 \r
1516 ON_EXIT:\r
1517 \r
1518   Udp4->Cancel (Udp4, &Token);\r
1519 \r
1520   gBS->CloseEvent (Token.Event);\r
1521 \r
1522   return Status;\r
1523 }\r
1524 \r
1525 \r
1526 /**\r
1527   GC_NOTO: Add function description\r
1528 \r
1529   @param  This                                        GC_NOTO: add argument\r
1530                                                       description\r
1531   @param  NewFilter                                   GC_NOTO: add argument\r
1532                                                       description\r
1533 \r
1534   @retval EFI_UNSUPPORTED                             GC_NOTO: Add description for\r
1535                                                       return value\r
1536 \r
1537 **/\r
1538 EFI_STATUS\r
1539 EFIAPI\r
1540 EfiPxeBcSetIpFilter (\r
1541   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,\r
1542   IN EFI_PXE_BASE_CODE_IP_FILTER      *NewFilter\r
1543   )\r
1544 {\r
1545   EFI_STATUS                Status;\r
1546   PXEBC_PRIVATE_DATA        *Private;\r
1547   EFI_PXE_BASE_CODE_MODE    *Mode;\r
1548   UINTN                     Index;\r
1549   BOOLEAN                   PromiscuousNeed;\r
1550 \r
1551   if (This == NULL) {\r
1552     DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL.\n"));\r
1553     return EFI_INVALID_PARAMETER;\r
1554   }\r
1555 \r
1556   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
1557   Mode = Private->PxeBc.Mode;\r
1558 \r
1559   if (Private == NULL) {\r
1560     DEBUG ((EFI_D_ERROR, "PXEBC_PRIVATE_DATA poiner == NULL.\n"));\r
1561     return EFI_INVALID_PARAMETER;\r
1562   }\r
1563 \r
1564   if (NewFilter == NULL) {\r
1565     DEBUG ((EFI_D_ERROR, "IP Filter *NewFilter == NULL.\n"));\r
1566     return EFI_INVALID_PARAMETER;\r
1567   }\r
1568 \r
1569   if (!Mode->Started) {\r
1570     DEBUG ((EFI_D_ERROR, "BC was not started.\n"));\r
1571     return EFI_NOT_STARTED;\r
1572   }\r
1573 \r
1574   PromiscuousNeed = FALSE;\r
1575   for (Index = 0; Index < NewFilter->IpCnt; ++Index) {\r
1576     if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (NewFilter->IpList[Index].v4))) {\r
1577       //\r
1578       // The IP is a broadcast address.\r
1579       //\r
1580       DEBUG ((EFI_D_ERROR, "There is broadcast address in NewFilter.\n"));\r
1581       return EFI_INVALID_PARAMETER;\r
1582     }\r
1583     if (Ip4IsUnicast (EFI_IP4 (NewFilter->IpList[Index].v4), 0) &&\r
1584         (NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP)\r
1585        ) {\r
1586       //\r
1587       // If EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP is set and IP4 address is in IpList,\r
1588       // promiscuous mode is needed.\r
1589       //\r
1590       PromiscuousNeed = TRUE;\r
1591     }\r
1592   }\r
1593 \r
1594   //\r
1595   // Clear the UDP instance configuration, all joined groups will be left\r
1596   // during the operation.\r
1597   //\r
1598   Private->Udp4->Configure (Private->Udp4, NULL);\r
1599   Private->Udp4CfgData.AcceptPromiscuous  = FALSE;\r
1600   Private->Udp4CfgData.AcceptBroadcast    = FALSE;\r
1601 \r
1602   if (PromiscuousNeed ||\r
1603       NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS ||\r
1604       NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST\r
1605      ) {\r
1606     //\r
1607     // Configure the udp4 filter to receive all packages\r
1608     //\r
1609     Private->Udp4CfgData.AcceptPromiscuous  = TRUE;\r
1610 \r
1611     //\r
1612     // Configure the UDP instance with the new configuration.\r
1613     //\r
1614     Status = Private->Udp4->Configure (Private->Udp4, &Private->Udp4CfgData);\r
1615     if (EFI_ERROR (Status)) {\r
1616       return Status;\r
1617     }\r
1618 \r
1619   } else {\r
1620 \r
1621     if (NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) {\r
1622       //\r
1623       // Configure the udp4 filter to receive all broadcast packages\r
1624       //\r
1625       Private->Udp4CfgData.AcceptBroadcast    = TRUE;\r
1626     }\r
1627 \r
1628     //\r
1629     // Configure the UDP instance with the new configuration.\r
1630     //\r
1631     Status = Private->Udp4->Configure (Private->Udp4, &Private->Udp4CfgData);\r
1632     if (EFI_ERROR (Status)) {\r
1633       return Status;\r
1634     }\r
1635 \r
1636     if (NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) {\r
1637 \r
1638       for (Index = 0; Index < NewFilter->IpCnt; ++Index) {\r
1639         if (IP4_IS_MULTICAST (EFI_NTOHL (NewFilter->IpList[Index].v4))) {\r
1640           //\r
1641           // Join the mutilcast group\r
1642           //\r
1643           Status = Private->Udp4->Groups (Private->Udp4, TRUE, &NewFilter->IpList[Index].v4);\r
1644           if (EFI_ERROR (Status)) {\r
1645             return Status;\r
1646           }\r
1647         }\r
1648       }\r
1649     }\r
1650   }\r
1651 \r
1652 \r
1653   //\r
1654   // Save the new filter.\r
1655   //\r
1656   CopyMem (&Mode->IpFilter, NewFilter, sizeof (Mode->IpFilter));\r
1657 \r
1658   return EFI_SUCCESS;\r
1659 }\r
1660 \r
1661 \r
1662 /**\r
1663   GC_NOTO: Add function description\r
1664 \r
1665   @param  This                                        GC_NOTO: add argument\r
1666                                                       description\r
1667   @param  IpAddr                                      GC_NOTO: add argument\r
1668                                                       description\r
1669   @param  MacAddr                                     GC_NOTO: add argument\r
1670                                                       description\r
1671 \r
1672   @retval EFI_UNSUPPORTED                             GC_NOTO: Add description for\r
1673                                                       return value\r
1674 \r
1675 **/\r
1676 EFI_STATUS\r
1677 EFIAPI\r
1678 EfiPxeBcArp (\r
1679   IN EFI_PXE_BASE_CODE_PROTOCOL       * This,\r
1680   IN EFI_IP_ADDRESS                   * IpAddr,\r
1681   IN EFI_MAC_ADDRESS                  * MacAddr OPTIONAL\r
1682   )\r
1683 {\r
1684   PXEBC_PRIVATE_DATA      *Private;\r
1685   EFI_PXE_BASE_CODE_MODE  *Mode;\r
1686   EFI_STATUS              Status;\r
1687   EFI_MAC_ADDRESS         TempMacAddr;\r
1688 \r
1689   if (This == NULL || IpAddr == NULL) {\r
1690     return EFI_INVALID_PARAMETER;\r
1691   }\r
1692 \r
1693   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
1694   Mode    = Private->PxeBc.Mode;\r
1695 \r
1696   if (!Mode->Started) {\r
1697     return EFI_NOT_STARTED;\r
1698   }\r
1699 \r
1700   if (!Private->AddressIsOk || Mode->UsingIpv6) {\r
1701     //\r
1702     // We can't resolve the IP address if we don't have a local address now.\r
1703     // Don't have ARP for IPv6.\r
1704     //\r
1705     return EFI_INVALID_PARAMETER;\r
1706   }\r
1707 \r
1708   Mode->IcmpErrorReceived = FALSE;\r
1709 \r
1710   if (!Mode->AutoArp) {\r
1711     //\r
1712     // If AutoArp is set false, check arp cache\r
1713     //\r
1714     UpdateArpCache (This);\r
1715     if (!FindInArpCache (Mode, &IpAddr->v4, &TempMacAddr)) {\r
1716       return EFI_DEVICE_ERROR;\r
1717     }\r
1718   } else {\r
1719     Status = Private->Arp->Request (Private->Arp, &IpAddr->v4, NULL, &TempMacAddr);\r
1720     if (EFI_ERROR (Status)) {\r
1721       if (Status == EFI_ICMP_ERROR) {\r
1722         Mode->IcmpErrorReceived = TRUE;\r
1723       }\r
1724       return Status;\r
1725     }\r
1726   }\r
1727 \r
1728   if (MacAddr != NULL) {\r
1729     CopyMem (MacAddr, &TempMacAddr, sizeof (EFI_MAC_ADDRESS));\r
1730   }\r
1731 \r
1732   return EFI_SUCCESS;\r
1733 }\r
1734 \r
1735 \r
1736 \r
1737 /**\r
1738   GC_NOTO: Add function description\r
1739 \r
1740   @param  This                                        GC_NOTO: add argument\r
1741                                                       description\r
1742   @param  NewAutoArp                                  GC_NOTO: add argument\r
1743                                                       description\r
1744   @param  NewSendGUID                                 GC_NOTO: add argument\r
1745                                                       description\r
1746   @param  NewTTL                                      GC_NOTO: add argument\r
1747                                                       description\r
1748   @param  NewToS                                      GC_NOTO: add argument\r
1749                                                       description\r
1750   @param  NewMakeCallback                             GC_NOTO: add argument\r
1751                                                       description\r
1752 \r
1753   @return GC_NOTO: add return values\r
1754 \r
1755 **/\r
1756 EFI_STATUS\r
1757 EFIAPI\r
1758 EfiPxeBcSetParameters (\r
1759   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,\r
1760   IN BOOLEAN                          *NewAutoArp, OPTIONAL\r
1761   IN BOOLEAN                          *NewSendGUID, OPTIONAL\r
1762   IN UINT8                            *NewTTL, OPTIONAL\r
1763   IN UINT8                            *NewToS, OPTIONAL\r
1764   IN BOOLEAN                          *NewMakeCallback  // OPTIONAL\r
1765   )\r
1766 {\r
1767   PXEBC_PRIVATE_DATA      *Private;\r
1768   EFI_PXE_BASE_CODE_MODE  *Mode;\r
1769   EFI_STATUS              Status;\r
1770 \r
1771   Status = EFI_SUCCESS;\r
1772 \r
1773   if (This == NULL) {\r
1774     Status = EFI_INVALID_PARAMETER;\r
1775     goto ON_EXIT;\r
1776   }\r
1777 \r
1778   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
1779   Mode    = Private->PxeBc.Mode;\r
1780 \r
1781   if (NewSendGUID != NULL && *NewSendGUID == TRUE) {\r
1782     //\r
1783     // FixMe, cann't locate SendGuid\r
1784     //\r
1785   }\r
1786 \r
1787   if (NewMakeCallback != NULL && *NewMakeCallback == TRUE) {\r
1788 \r
1789     Status = gBS->HandleProtocol (\r
1790                     Private->Controller,\r
1791                     &gEfiPxeBaseCodeCallbackProtocolGuid,\r
1792                     (VOID **) &Private->PxeBcCallback\r
1793                     );\r
1794     if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {\r
1795 \r
1796       Status = EFI_INVALID_PARAMETER;\r
1797       goto ON_EXIT;\r
1798     }\r
1799   }\r
1800 \r
1801   if (!Mode->Started) {\r
1802     Status = EFI_NOT_STARTED;\r
1803     goto ON_EXIT;\r
1804   }\r
1805 \r
1806   if (NewMakeCallback != NULL) {\r
1807 \r
1808     if (*NewMakeCallback) {\r
1809       //\r
1810       // Update the Callback protocol.\r
1811       //\r
1812       Status = gBS->HandleProtocol (\r
1813                       Private->Controller,\r
1814                       &gEfiPxeBaseCodeCallbackProtocolGuid,\r
1815                       (VOID **) &Private->PxeBcCallback\r
1816                       );\r
1817 \r
1818       if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {\r
1819         Status = EFI_INVALID_PARAMETER;\r
1820         goto ON_EXIT;\r
1821       }\r
1822     } else {\r
1823       Private->PxeBcCallback = NULL;\r
1824     }\r
1825 \r
1826     Mode->MakeCallbacks = *NewMakeCallback;\r
1827   }\r
1828 \r
1829   if (NewAutoArp != NULL) {\r
1830     Mode->AutoArp = *NewAutoArp;\r
1831   }\r
1832 \r
1833   if (NewSendGUID != NULL) {\r
1834     Mode->SendGUID = *NewSendGUID;\r
1835   }\r
1836 \r
1837   if (NewTTL != NULL) {\r
1838     Mode->TTL = *NewTTL;\r
1839   }\r
1840 \r
1841   if (NewToS != NULL) {\r
1842     Mode->ToS = *NewToS;\r
1843   }\r
1844 \r
1845 ON_EXIT:\r
1846   return Status;\r
1847 }\r
1848 \r
1849 \r
1850 /**\r
1851   GC_NOTO: Add function description\r
1852 \r
1853   @param  This                                        GC_NOTO: add argument\r
1854                                                       description\r
1855   @param  NewStationIp                                GC_NOTO: add argument\r
1856                                                       description\r
1857   @param  NewSubnetMask                               GC_NOTO: add argument\r
1858                                                       description\r
1859 \r
1860   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1861                                                       return value\r
1862   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1863                                                       return value\r
1864   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1865                                                       return value\r
1866   @retval EFI_NOT_STARTED                             GC_NOTO: Add description for\r
1867                                                       return value\r
1868   @retval EFI_SUCCESS                                 GC_NOTO: Add description for\r
1869                                                       return value\r
1870 \r
1871 **/\r
1872 EFI_STATUS\r
1873 EFIAPI\r
1874 EfiPxeBcSetStationIP (\r
1875   IN EFI_PXE_BASE_CODE_PROTOCOL       * This,\r
1876   IN EFI_IP_ADDRESS                   * NewStationIp, OPTIONAL\r
1877   IN EFI_IP_ADDRESS                   * NewSubnetMask OPTIONAL\r
1878   )\r
1879 {\r
1880   PXEBC_PRIVATE_DATA      *Private;\r
1881   EFI_PXE_BASE_CODE_MODE  *Mode;\r
1882   EFI_ARP_CONFIG_DATA     ArpConfigData;\r
1883 \r
1884   if (This == NULL) {\r
1885     return EFI_INVALID_PARAMETER;\r
1886   }\r
1887 \r
1888   if (NewStationIp != NULL && !Ip4IsUnicast (NTOHL (NewStationIp->Addr[0]), 0)) {\r
1889     return EFI_INVALID_PARAMETER;\r
1890   }\r
1891 \r
1892   if (NewSubnetMask != NULL && !IP4_IS_VALID_NETMASK (NTOHL (NewSubnetMask->Addr[0]))) {\r
1893     return EFI_INVALID_PARAMETER;\r
1894   }\r
1895 \r
1896   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
1897   Mode    = Private->PxeBc.Mode;\r
1898 \r
1899   if (!Mode->Started) {\r
1900     return EFI_NOT_STARTED;\r
1901   }\r
1902 \r
1903   if (NewStationIp != NULL) {\r
1904     Mode->StationIp    = *NewStationIp;\r
1905     Private->StationIp = *NewStationIp;\r
1906   }\r
1907 \r
1908   if (NewSubnetMask != NULL) {\r
1909     Mode->SubnetMask    = *NewSubnetMask;\r
1910     Private->SubnetMask = *NewSubnetMask;\r
1911   }\r
1912 \r
1913   Private->AddressIsOk = TRUE;\r
1914 \r
1915   if (!Mode->UsingIpv6) {\r
1916     //\r
1917     // If in IPv4 mode, configure the corresponding ARP with this new\r
1918     // station IP address.\r
1919     //\r
1920     ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));\r
1921 \r
1922     ArpConfigData.SwAddressType   = 0x0800;\r
1923     ArpConfigData.SwAddressLength = sizeof (EFI_IPv4_ADDRESS);\r
1924     ArpConfigData.StationAddress  = &Private->StationIp.v4;\r
1925 \r
1926     Private->Arp->Configure (Private->Arp, NULL);\r
1927     Private->Arp->Configure (Private->Arp, &ArpConfigData);\r
1928 \r
1929     //\r
1930     // Update the route table.\r
1931     //\r
1932     Mode->RouteTableEntries                = 1;\r
1933     Mode->RouteTable[0].IpAddr.Addr[0]     = Private->StationIp.Addr[0] & Private->SubnetMask.Addr[0];\r
1934     Mode->RouteTable[0].SubnetMask.Addr[0] = Private->SubnetMask.Addr[0];\r
1935     Mode->RouteTable[0].GwAddr.Addr[0]     = 0;\r
1936   }\r
1937 \r
1938   return EFI_SUCCESS;\r
1939 }\r
1940 \r
1941 \r
1942 /**\r
1943   GC_NOTO: Add function description\r
1944 \r
1945   @param  This                                        GC_NOTO: add argument\r
1946                                                       description\r
1947   @param  NewDhcpDiscoverValid                        GC_NOTO: add argument\r
1948                                                       description\r
1949   @param  NewDhcpAckReceived                          GC_NOTO: add argument\r
1950                                                       description\r
1951   @param  NewProxyOfferReceived                       GC_NOTO: add argument\r
1952                                                       description\r
1953   @param  NewPxeDiscoverValid                         GC_NOTO: add argument\r
1954                                                       description\r
1955   @param  NewPxeReplyReceived                         GC_NOTO: add argument\r
1956                                                       description\r
1957   @param  NewPxeBisReplyReceived                      GC_NOTO: add argument\r
1958                                                       description\r
1959   @param  NewDhcpDiscover                             GC_NOTO: add argument\r
1960                                                       description\r
1961   @param  NewDhcpAck                                  GC_NOTO: add argument\r
1962                                                       description\r
1963   @param  NewProxyOffer                               GC_NOTO: add argument\r
1964                                                       description\r
1965   @param  NewPxeDiscover                              GC_NOTO: add argument\r
1966                                                       description\r
1967   @param  NewPxeReply                                 GC_NOTO: add argument\r
1968                                                       description\r
1969   @param  NewPxeBisReply                              GC_NOTO: add argument\r
1970                                                       description\r
1971 \r
1972   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
1973                                                       return value\r
1974   @retval EFI_NOT_STARTED                             GC_NOTO: Add description for\r
1975                                                       return value\r
1976   @retval EFI_SUCCESS                                 GC_NOTO: Add description for\r
1977                                                       return value\r
1978 \r
1979 **/\r
1980 EFI_STATUS\r
1981 EFIAPI\r
1982 EfiPxeBcSetPackets (\r
1983   IN EFI_PXE_BASE_CODE_PROTOCOL       * This,\r
1984   IN BOOLEAN                          * NewDhcpDiscoverValid, OPTIONAL\r
1985   IN BOOLEAN                          * NewDhcpAckReceived, OPTIONAL\r
1986   IN BOOLEAN                          * NewProxyOfferReceived, OPTIONAL\r
1987   IN BOOLEAN                          * NewPxeDiscoverValid, OPTIONAL\r
1988   IN BOOLEAN                          * NewPxeReplyReceived, OPTIONAL\r
1989   IN BOOLEAN                          * NewPxeBisReplyReceived, OPTIONAL\r
1990   IN EFI_PXE_BASE_CODE_PACKET         * NewDhcpDiscover, OPTIONAL\r
1991   IN EFI_PXE_BASE_CODE_PACKET         * NewDhcpAck, OPTIONAL\r
1992   IN EFI_PXE_BASE_CODE_PACKET         * NewProxyOffer, OPTIONAL\r
1993   IN EFI_PXE_BASE_CODE_PACKET         * NewPxeDiscover, OPTIONAL\r
1994   IN EFI_PXE_BASE_CODE_PACKET         * NewPxeReply, OPTIONAL\r
1995   IN EFI_PXE_BASE_CODE_PACKET         * NewPxeBisReply OPTIONAL\r
1996   )\r
1997 {\r
1998   PXEBC_PRIVATE_DATA      *Private;\r
1999   EFI_PXE_BASE_CODE_MODE  *Mode;\r
2000 \r
2001   if (This == NULL) {\r
2002     return EFI_INVALID_PARAMETER;\r
2003   }\r
2004 \r
2005   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
2006   Mode    = Private->PxeBc.Mode;\r
2007 \r
2008   if (!Mode->Started) {\r
2009     return EFI_NOT_STARTED;\r
2010   }\r
2011 \r
2012   Private->FileSize = 0;\r
2013 \r
2014   if (NewDhcpDiscoverValid != NULL) {\r
2015     Mode->DhcpDiscoverValid = *NewDhcpDiscoverValid;\r
2016   }\r
2017 \r
2018   if (NewDhcpAckReceived != NULL) {\r
2019     Mode->DhcpAckReceived = *NewDhcpAckReceived;\r
2020   }\r
2021 \r
2022   if (NewProxyOfferReceived != NULL) {\r
2023     Mode->ProxyOfferReceived = *NewProxyOfferReceived;\r
2024   }\r
2025 \r
2026   if (NewPxeDiscoverValid != NULL) {\r
2027     Mode->PxeDiscoverValid = *NewPxeDiscoverValid;\r
2028   }\r
2029 \r
2030   if (NewPxeReplyReceived != NULL) {\r
2031     Mode->PxeReplyReceived = *NewPxeReplyReceived;\r
2032   }\r
2033 \r
2034   if (NewPxeBisReplyReceived != NULL) {\r
2035     Mode->PxeBisReplyReceived = *NewPxeBisReplyReceived;\r
2036   }\r
2037 \r
2038   if (NewDhcpDiscover != NULL) {\r
2039     CopyMem (&Mode->DhcpDiscover, NewDhcpDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));\r
2040   }\r
2041 \r
2042   if (NewDhcpAck != NULL) {\r
2043     CopyMem (&Mode->DhcpAck, NewDhcpAck, sizeof (EFI_PXE_BASE_CODE_PACKET));\r
2044   }\r
2045 \r
2046   if (NewProxyOffer != NULL) {\r
2047     CopyMem (&Mode->ProxyOffer, NewProxyOffer, sizeof (EFI_PXE_BASE_CODE_PACKET));\r
2048   }\r
2049 \r
2050   if (NewPxeDiscover != NULL) {\r
2051     CopyMem (&Mode->PxeDiscover, NewPxeDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));\r
2052   }\r
2053 \r
2054   if (NewPxeReply != NULL) {\r
2055     CopyMem (&Mode->PxeReply, NewPxeReply, sizeof (EFI_PXE_BASE_CODE_PACKET));\r
2056   }\r
2057 \r
2058   if (NewPxeBisReply != NULL) {\r
2059     CopyMem (&Mode->PxeBisReply, NewPxeBisReply, sizeof (EFI_PXE_BASE_CODE_PACKET));\r
2060   }\r
2061 \r
2062   return EFI_SUCCESS;\r
2063 }\r
2064 \r
2065 EFI_PXE_BASE_CODE_PROTOCOL  mPxeBcProtocolTemplate = {\r
2066   EFI_PXE_BASE_CODE_PROTOCOL_REVISION,\r
2067   EfiPxeBcStart,\r
2068   EfiPxeBcStop,\r
2069   EfiPxeBcDhcp,\r
2070   EfiPxeBcDiscover,\r
2071   EfiPxeBcMtftp,\r
2072   EfiPxeBcUdpWrite,\r
2073   EfiPxeBcUdpRead,\r
2074   EfiPxeBcSetIpFilter,\r
2075   EfiPxeBcArp,\r
2076   EfiPxeBcSetParameters,\r
2077   EfiPxeBcSetStationIP,\r
2078   EfiPxeBcSetPackets,\r
2079   NULL\r
2080 };\r
2081 \r
2082 \r
2083 /**\r
2084   GC_NOTO: Add function description\r
2085 \r
2086   @param  This                                        GC_NOTO: add argument\r
2087                                                       description\r
2088   @param  Function                                    GC_NOTO: add argument\r
2089                                                       description\r
2090   @param  Received                                    GC_NOTO: add argument\r
2091                                                       description\r
2092   @param  PacketLength                                GC_NOTO: add argument\r
2093                                                       description\r
2094   @param  PacketPtr                                   GC_NOTO: add argument\r
2095                                                       description\r
2096 \r
2097   @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT     GC_NOTO: Add description for\r
2098                                                       return value\r
2099   @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE  GC_NOTO: Add description for\r
2100                                                       return value\r
2101   @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE  GC_NOTO: Add description for\r
2102                                                       return value\r
2103   @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE  GC_NOTO: Add description for\r
2104                                                       return value\r
2105   @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE  GC_NOTO: Add description for\r
2106                                                       return value\r
2107 \r
2108 **/\r
2109 EFI_PXE_BASE_CODE_CALLBACK_STATUS\r
2110 EFIAPI\r
2111 EfiPxeLoadFileCallback (\r
2112   IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL  * This,\r
2113   IN EFI_PXE_BASE_CODE_FUNCTION           Function,\r
2114   IN BOOLEAN                              Received,\r
2115   IN UINT32                               PacketLength,\r
2116   IN EFI_PXE_BASE_CODE_PACKET             * PacketPtr OPTIONAL\r
2117   )\r
2118 {\r
2119   EFI_INPUT_KEY Key;\r
2120   EFI_STATUS    Status;\r
2121 \r
2122   //\r
2123   // Catch Ctrl-C or ESC to abort.\r
2124   //\r
2125   Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2126 \r
2127   if (!EFI_ERROR (Status)) {\r
2128 \r
2129     if (Key.ScanCode == SCAN_ESC || Key.UnicodeChar == (0x1F & 'c')) {\r
2130 \r
2131       return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;\r
2132     }\r
2133   }\r
2134   //\r
2135   // No print if receive packet\r
2136   //\r
2137   if (Received) {\r
2138     return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
2139   }\r
2140   //\r
2141   // Print only for three functions\r
2142   //\r
2143   switch (Function) {\r
2144 \r
2145   case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:\r
2146     //\r
2147     // Print only for open MTFTP packets, not every MTFTP packets\r
2148     //\r
2149     if (PacketLength != 0 && PacketPtr != NULL) {\r
2150       if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {\r
2151         return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
2152       }\r
2153     }\r
2154     break;\r
2155 \r
2156   case EFI_PXE_BASE_CODE_FUNCTION_DHCP:\r
2157   case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:\r
2158     break;\r
2159 \r
2160   default:\r
2161     return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
2162   }\r
2163 \r
2164   if (PacketLength != 0 && PacketPtr != NULL) {\r
2165     //\r
2166     // Print '.' when transmit a packet\r
2167     //\r
2168     AsciiPrint (".");\r
2169 \r
2170   }\r
2171 \r
2172   return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
2173 }\r
2174 \r
2175 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL mPxeBcCallBackTemplate = {\r
2176   EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION,\r
2177   EfiPxeLoadFileCallback\r
2178 };\r
2179 \r
2180 \r
2181 /**\r
2182   GC_NOTO: Add function description\r
2183 \r
2184   @param  Private                                     GC_NOTO: add argument\r
2185                                                       description\r
2186   @param  BufferSize                                  GC_NOTO: add argument\r
2187                                                       description\r
2188   @param  Buffer                                      GC_NOTO: add argument\r
2189                                                       description\r
2190 \r
2191   @return GC_NOTO: add return values\r
2192 \r
2193 **/\r
2194 EFI_STATUS\r
2195 DiscoverBootFile (\r
2196   IN     PXEBC_PRIVATE_DATA  *Private,\r
2197   IN OUT UINT64              *BufferSize,\r
2198   IN     VOID                *Buffer\r
2199   )\r
2200 {\r
2201   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;\r
2202   EFI_PXE_BASE_CODE_MODE      *Mode;\r
2203   EFI_STATUS                  Status;\r
2204   UINT16                      Type;\r
2205   UINT16                      Layer;\r
2206   BOOLEAN                     UseBis;\r
2207   UINTN                       BlockSize;\r
2208   PXEBC_CACHED_DHCP4_PACKET   *Packet;\r
2209   UINT16                      Value;\r
2210 \r
2211   PxeBc = &Private->PxeBc;\r
2212   Mode  = PxeBc->Mode;\r
2213   Type  = EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP;\r
2214   Layer = EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL;\r
2215 \r
2216   //\r
2217   // do DHCP.\r
2218   //\r
2219   Status = PxeBc->Dhcp (PxeBc, TRUE);\r
2220   if (EFI_ERROR (Status)) {\r
2221     return Status;\r
2222   }\r
2223 \r
2224   //\r
2225   // Select a boot server\r
2226   //\r
2227   Status = PxeBcSelectBootPrompt (Private);\r
2228 \r
2229   if (Status == EFI_SUCCESS) {\r
2230     Status = PxeBcSelectBootMenu (Private, &Type, TRUE);\r
2231   } else if (Status == EFI_TIMEOUT) {\r
2232     Status = PxeBcSelectBootMenu (Private, &Type, FALSE);\r
2233   }\r
2234 \r
2235   if (!EFI_ERROR (Status)) {\r
2236 \r
2237     if (Type == EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP) {\r
2238       //\r
2239       // Local boot(PXE bootstrap server) need abort\r
2240       //\r
2241       return EFI_ABORTED;\r
2242     }\r
2243 \r
2244     UseBis  = (BOOLEAN) (Mode->BisSupported && Mode->BisDetected);\r
2245     Status  = PxeBc->Discover (PxeBc, Type, &Layer, UseBis, NULL);\r
2246     if (EFI_ERROR (Status)) {\r
2247       return Status;\r
2248     }\r
2249   }\r
2250 \r
2251   *BufferSize = 0;\r
2252   BlockSize   = 0x8000;\r
2253 \r
2254   //\r
2255   // Get bootfile name and (m)tftp server ip addresss\r
2256   //\r
2257   if (Mode->PxeReplyReceived) {\r
2258     Packet = &Private->PxeReply;\r
2259   } else if (Mode->ProxyOfferReceived) {\r
2260     Packet = &Private->ProxyOffer;\r
2261   } else {\r
2262     Packet = &Private->Dhcp4Ack;\r
2263   }\r
2264 \r
2265   CopyMem (&Private->ServerIp, &Packet->Packet.Offer.Dhcp4.Header.ServerAddr, sizeof (EFI_IPv4_ADDRESS));\r
2266   if (Private->ServerIp.Addr[0] == 0) {\r
2267     //\r
2268     // next server ip address is zero, use option 54 instead\r
2269     //\r
2270     CopyMem (\r
2271       &Private->ServerIp,\r
2272       Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,\r
2273       sizeof (EFI_IPv4_ADDRESS)\r
2274       );\r
2275   }\r
2276 \r
2277   ASSERT (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);\r
2278 \r
2279   //\r
2280   // bootlfile name\r
2281   //\r
2282   Private->BootFileName = (CHAR8 *) (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data);\r
2283 \r
2284   if (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {\r
2285     //\r
2286     // Already have the bootfile length option, compute the file size\r
2287     //\r
2288     CopyMem (&Value, Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value));\r
2289     Value       = NTOHS (Value);\r
2290     *BufferSize = 512 * Value;\r
2291     Status      = EFI_BUFFER_TOO_SMALL;\r
2292   } else {\r
2293     //\r
2294     // Get the bootfile size from tftp\r
2295     //\r
2296     Status = PxeBc->Mtftp (\r
2297                       PxeBc,\r
2298                       EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,\r
2299                       Buffer,\r
2300                       FALSE,\r
2301                       BufferSize,\r
2302                       &BlockSize,\r
2303                       &Private->ServerIp,\r
2304                       (UINT8 *) Private->BootFileName,\r
2305                       NULL,\r
2306                       FALSE\r
2307                       );\r
2308   }\r
2309 \r
2310   Private->FileSize = (UINTN) *BufferSize;\r
2311 \r
2312   return Status;\r
2313 }\r
2314 \r
2315 \r
2316 /**\r
2317   GC_NOTO: Add function description\r
2318 \r
2319   @param  This                                        GC_NOTO: add argument\r
2320                                                       description\r
2321   @param  FilePath                                    GC_NOTO: add argument\r
2322                                                       description\r
2323   @param  BootPolicy                                  GC_NOTO: add argument\r
2324                                                       description\r
2325   @param  BufferSize                                  GC_NOTO: add argument\r
2326                                                       description\r
2327   @param  Buffer                                      GC_NOTO: add argument\r
2328                                                       description\r
2329 \r
2330   @retval EFI_INVALID_PARAMETER                       GC_NOTO: Add description for\r
2331                                                       return value\r
2332   @retval EFI_UNSUPPORTED                             GC_NOTO: Add description for\r
2333                                                       return value\r
2334 \r
2335 **/\r
2336 EFI_STATUS\r
2337 EFIAPI\r
2338 EfiPxeLoadFile (\r
2339   IN EFI_LOAD_FILE_PROTOCOL           * This,\r
2340   IN EFI_DEVICE_PATH_PROTOCOL         * FilePath,\r
2341   IN BOOLEAN                          BootPolicy,\r
2342   IN OUT UINTN                        *BufferSize,\r
2343   IN VOID                             *Buffer OPTIONAL\r
2344   )\r
2345 {\r
2346   PXEBC_PRIVATE_DATA          *Private;\r
2347   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;\r
2348   BOOLEAN                     NewMakeCallback;\r
2349   UINTN                       BlockSize;\r
2350   EFI_STATUS                  Status;\r
2351   UINT64                      TmpBufSize;\r
2352 \r
2353   Private         = PXEBC_PRIVATE_DATA_FROM_LOADFILE (This);\r
2354   PxeBc           = &Private->PxeBc;\r
2355   NewMakeCallback = FALSE;\r
2356   BlockSize       = 0x8000;\r
2357   Status          = EFI_DEVICE_ERROR;\r
2358 \r
2359   CpuDeadLoop ();\r
2360   if (This == NULL || BufferSize == NULL) {\r
2361 \r
2362     return EFI_INVALID_PARAMETER;\r
2363   }\r
2364 \r
2365   //\r
2366   // Only support BootPolicy\r
2367   //\r
2368   if (!BootPolicy) {\r
2369     return EFI_UNSUPPORTED;\r
2370   }\r
2371 \r
2372   Status = PxeBc->Start (PxeBc, FALSE);\r
2373   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
2374     return Status;\r
2375   }\r
2376 \r
2377   Status = gBS->HandleProtocol (\r
2378                   Private->Controller,\r
2379                   &gEfiPxeBaseCodeCallbackProtocolGuid,\r
2380                   (VOID **) &Private->PxeBcCallback\r
2381                   );\r
2382   if (Status == EFI_UNSUPPORTED) {\r
2383 \r
2384     CopyMem (&Private->LoadFileCallback, &mPxeBcCallBackTemplate, sizeof (Private->LoadFileCallback));\r
2385 \r
2386     Status = gBS->InstallProtocolInterface (\r
2387                     &Private->Controller,\r
2388                     &gEfiPxeBaseCodeCallbackProtocolGuid,\r
2389                     EFI_NATIVE_INTERFACE,\r
2390                     &Private->LoadFileCallback\r
2391                     );\r
2392 \r
2393     NewMakeCallback = (BOOLEAN) (Status == EFI_SUCCESS);\r
2394 \r
2395     Status          = PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);\r
2396     if (EFI_ERROR (Status)) {\r
2397       PxeBc->Stop (PxeBc);\r
2398       return Status;\r
2399     }\r
2400   }\r
2401 \r
2402   if (Private->FileSize == 0) {\r
2403     TmpBufSize  = 0;\r
2404     Status      = DiscoverBootFile (Private, &TmpBufSize, Buffer);\r
2405 \r
2406     if (sizeof (UINTN) < sizeof (UINT64) && (TmpBufSize > 0xFFFFFFFF)) {\r
2407       Status = EFI_DEVICE_ERROR;\r
2408     } else {\r
2409       *BufferSize = (UINTN) TmpBufSize;\r
2410     }\r
2411   } else if (Buffer == NULL) {\r
2412     *BufferSize = Private->FileSize;\r
2413     Status      = EFI_BUFFER_TOO_SMALL;\r
2414   } else {\r
2415     //\r
2416     // Download the file.\r
2417     //\r
2418     TmpBufSize = (UINT64) (*BufferSize);\r
2419     Status = PxeBc->Mtftp (\r
2420                       PxeBc,\r
2421                       EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
2422                       Buffer,\r
2423                       FALSE,\r
2424                       &TmpBufSize,\r
2425                       &BlockSize,\r
2426                       &Private->ServerIp,\r
2427                       (UINT8 *) Private->BootFileName,\r
2428                       NULL,\r
2429                       FALSE\r
2430                       );\r
2431   }\r
2432   //\r
2433   // If we added a callback protocol, now is the time to remove it.\r
2434   //\r
2435   if (NewMakeCallback) {\r
2436 \r
2437     NewMakeCallback = FALSE;\r
2438 \r
2439     PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);\r
2440 \r
2441     gBS->UninstallProtocolInterface (\r
2442           Private->Controller,\r
2443           &gEfiPxeBaseCodeCallbackProtocolGuid,\r
2444           &Private->LoadFileCallback\r
2445           );\r
2446   }\r
2447   //\r
2448   // Check download status\r
2449   //\r
2450   switch (Status) {\r
2451 \r
2452   case EFI_SUCCESS:\r
2453     break;\r
2454 \r
2455   case EFI_BUFFER_TOO_SMALL:\r
2456     if (Buffer != NULL) {\r
2457       AsciiPrint ("PXE-E05: Download buffer is smaller than requested file.\n");\r
2458     } else {\r
2459       return Status;\r
2460     }\r
2461     break;\r
2462 \r
2463   case EFI_DEVICE_ERROR:\r
2464     AsciiPrint ("PXE-E07: Network device error.\n");\r
2465     break;\r
2466 \r
2467   case EFI_OUT_OF_RESOURCES:\r
2468     AsciiPrint ("PXE-E09: Could not allocate I/O buffers.\n");\r
2469     break;\r
2470 \r
2471   case EFI_NO_MEDIA:\r
2472     AsciiPrint ("PXE-E12: Could not detect network connection.\n");\r
2473     break;\r
2474 \r
2475   case EFI_NO_RESPONSE:\r
2476     AsciiPrint ("PXE-E16: No offer received.\n");\r
2477     break;\r
2478 \r
2479   case EFI_TIMEOUT:\r
2480     AsciiPrint ("PXE-E18: Server response timeout.\n");\r
2481     break;\r
2482 \r
2483   case EFI_ABORTED:\r
2484     AsciiPrint ("PXE-E21: Remote boot cancelled.\n");\r
2485     break;\r
2486 \r
2487   case EFI_ICMP_ERROR:\r
2488     AsciiPrint ("PXE-E22: Client received ICMP error from server.\n");\r
2489     break;\r
2490 \r
2491   case EFI_TFTP_ERROR:\r
2492     AsciiPrint ("PXE-E23: Client received TFTP error from server.\n");\r
2493     break;\r
2494 \r
2495   default:\r
2496     AsciiPrint ("PXE-E99: Unexpected network error.\n");\r
2497     break;\r
2498   }\r
2499 \r
2500   PxeBc->Stop (PxeBc);\r
2501 \r
2502   return Status;\r
2503 }\r
2504 \r
2505 EFI_LOAD_FILE_PROTOCOL  mLoadFileProtocolTemplate = { EfiPxeLoadFile };\r
2506 \r