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