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