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