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