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