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