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