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