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