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