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