1. Import UEFI PxeBc module in MdeModulePkg
[mirror_edk2.git] / MdeModulePkg / Universal / Network / UefiPxeBcDxe / PxeBcImpl.c
1 /** @file
2
3 Copyright (c) 2007, 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 /**
28 GC_NOTO: Add function description
29
30 @param This GC_NOTO: add argument
31 description
32 @param UseIpv6 GC_NOTO: add argument
33 description
34
35 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
36 return value
37 @retval EFI_ALREADY_STARTED GC_NOTO: Add description for
38 return value
39 @retval EFI_UNSUPPORTED GC_NOTO: Add description for
40 return value
41 @retval EFI_SUCCESS GC_NOTO: Add description for
42 return value
43
44 **/
45 EFI_STATUS
46 EFIAPI
47 EfiPxeBcStart (
48 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
49 IN BOOLEAN UseIpv6
50 )
51 {
52 PXEBC_PRIVATE_DATA *Private;
53 EFI_PXE_BASE_CODE_MODE *Mode;
54 EFI_STATUS Status;
55
56 if (This == NULL) {
57 return EFI_INVALID_PARAMETER;
58 }
59
60 Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
61 Mode = Private->PxeBc.Mode;
62
63 if (Mode->Started) {
64 return EFI_ALREADY_STARTED;
65 }
66
67 if (UseIpv6) {
68 //
69 // IPv6 is not supported now.
70 //
71 return EFI_UNSUPPORTED;
72 }
73
74 //
75 // Configure the udp4 instance to let it receive data
76 //
77 Status = Private->Udp4->Configure (Private->Udp4, &Private->Udp4CfgData);
78 if (EFI_ERROR (Status)) {
79 return Status;
80 }
81
82 Private->AddressIsOk = FALSE;
83
84 ZeroMem (Mode, sizeof (EFI_PXE_BASE_CODE_MODE));
85
86 Mode->Started = TRUE;
87 Mode->TTL = DEFAULT_TTL;
88 Mode->ToS = DEFAULT_ToS;
89 Mode->AutoArp = TRUE;
90
91 return EFI_SUCCESS;
92 }
93
94
95 /**
96 GC_NOTO: Add function description
97
98 @param This GC_NOTO: add argument
99 description
100
101 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
102 return value
103 @retval EFI_NOT_STARTED GC_NOTO: Add description for
104 return value
105 @retval EFI_SUCCESS GC_NOTO: Add description for
106 return value
107
108 **/
109 EFI_STATUS
110 EFIAPI
111 EfiPxeBcStop (
112 IN EFI_PXE_BASE_CODE_PROTOCOL *This
113 )
114 {
115 PXEBC_PRIVATE_DATA *Private;
116 EFI_PXE_BASE_CODE_MODE *Mode;
117
118 if (This == NULL) {
119 return EFI_INVALID_PARAMETER;
120 }
121
122 Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
123 Mode = Private->PxeBc.Mode;
124
125 if (!Mode->Started) {
126 return EFI_NOT_STARTED;
127 }
128
129 Mode->Started = FALSE;
130
131 Private->Udp4->Configure (Private->Udp4, NULL);
132
133 Private->Dhcp4->Stop (Private->Dhcp4);
134 Private->Dhcp4->Configure (Private->Dhcp4, NULL);
135
136 Private->FileSize = 0;
137
138 return EFI_SUCCESS;
139 }
140
141
142 /**
143 GC_NOTO: Add function description
144
145 @param This GC_NOTO: add argument
146 description
147 @param SortOffers GC_NOTO: add argument
148 description
149
150 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
151 return value
152 @retval EFI_NOT_STARTED GC_NOTO: Add description for
153 return value
154
155 **/
156 EFI_STATUS
157 EFIAPI
158 EfiPxeBcDhcp (
159 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
160 IN BOOLEAN SortOffers
161 )
162 {
163 PXEBC_PRIVATE_DATA *Private;
164 EFI_PXE_BASE_CODE_MODE *Mode;
165 EFI_DHCP4_PROTOCOL *Dhcp4;
166 EFI_DHCP4_CONFIG_DATA Dhcp4CfgData;
167 EFI_DHCP4_MODE_DATA Dhcp4Mode;
168 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];
169 UINT32 OptCount;
170 UINT32 DiscoverTimeout;
171 UINTN Index;
172 EFI_STATUS Status;
173
174 if (This == NULL) {
175 return EFI_INVALID_PARAMETER;
176 }
177
178 Status = EFI_SUCCESS;
179 Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
180 Mode = Private->PxeBc.Mode;
181 Dhcp4 = Private->Dhcp4;
182 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DHCP;
183 Private->SortOffers = SortOffers;
184
185 if (!Mode->Started) {
186 return EFI_NOT_STARTED;
187 }
188 //
189 // Initialize the DHCP options and build the option list
190 //
191 OptCount = PxeBcBuildDhcpOptions (Private, OptList, TRUE);
192
193 //
194 // Set the DHCP4 config data.
195 //
196 NetZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
197 Dhcp4CfgData.OptionCount = OptCount;
198 Dhcp4CfgData.OptionList = OptList;
199 Dhcp4CfgData.Dhcp4Callback = PxeBcDhcpCallBack;
200 Dhcp4CfgData.CallbackContext = Private;
201 Dhcp4CfgData.DiscoverTryCount = 1;
202 Dhcp4CfgData.DiscoverTimeout = &DiscoverTimeout;
203
204 for (Index = 0; Index < PXEBC_DHCP4_DISCOVER_RETRIES; Index++) {
205 //
206 // The four discovery timeouts are 4, 8, 16, 32 seconds respectively.
207 //
208 DiscoverTimeout = (PXEBC_DHCP4_DISCOVER_INIT_TIMEOUT << Index);
209
210 Status = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
211 if (EFI_ERROR (Status)) {
212 break;
213 }
214 //
215 // Zero those arrays to record the varies numbers of DHCP OFFERS.
216 //
217 Private->NumOffers = 0;
218 Private->BootpIndex = 0;
219 NetZeroMem (Private->ServerCount, sizeof (Private->ServerCount));
220 NetZeroMem (Private->ProxyIndex, sizeof (Private->ProxyIndex));
221
222 Status = Dhcp4->Start (Dhcp4, NULL);
223 if (EFI_ERROR (Status)) {
224 if (Status == EFI_TIMEOUT) {
225 //
226 // If no response is received or all received offers don't match
227 // the PXE boot requirements, EFI_TIMEOUT will be returned.
228 //
229 continue;
230 }
231 //
232 // Other error status means the DHCP really fails.
233 //
234 break;
235 }
236
237 Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
238 if (EFI_ERROR (Status)) {
239 break;
240 }
241
242 ASSERT (Dhcp4Mode.State == Dhcp4Bound);
243
244 NetCopyMem (&Private->StationIp, &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
245 NetCopyMem (&Private->SubnetMask, &Dhcp4Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
246 NetCopyMem (&Private->GatewayIp, &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
247
248 //
249 // Check the selected offer to see whether BINL is required, if no or BINL is
250 // finished, set the various Mode members.
251 //
252 Status = PxeBcCheckSelectedOffer (Private);
253 if (!EFI_ERROR (Status)) {
254 break;
255 }
256 }
257
258 if (EFI_ERROR (Status)) {
259 Dhcp4->Stop (Dhcp4);
260 Dhcp4->Configure (Dhcp4, NULL);
261 } else {
262 //
263 // Remove the previously configured option list and callback function
264 //
265 NetZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
266 Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
267
268 Private->AddressIsOk = TRUE;
269 }
270
271 return Status;
272 }
273
274
275 /**
276 GC_NOTO: Add function description
277
278 @param This GC_NOTO: add argument
279 description
280 @param Type GC_NOTO: add argument
281 description
282 @param Layer GC_NOTO: add argument
283 description
284 @param UseBis GC_NOTO: add argument
285 description
286 @param Info GC_NOTO: add argument
287 description
288
289 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
290 return value
291 @retval EFI_NOT_STARTED GC_NOTO: Add description for
292 return value
293 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
294 return value
295 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
296 return value
297 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
298 return value
299 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
300 return value
301
302 **/
303 EFI_STATUS
304 EFIAPI
305 EfiPxeBcDiscover (
306 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
307 IN UINT16 Type,
308 IN UINT16 *Layer,
309 IN BOOLEAN UseBis,
310 IN EFI_PXE_BASE_CODE_DISCOVER_INFO *Info OPTIONAL
311 )
312 {
313 PXEBC_PRIVATE_DATA *Private;
314 EFI_PXE_BASE_CODE_MODE *Mode;
315 EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;
316 EFI_PXE_BASE_CODE_SRVLIST *SrvList;
317 EFI_PXE_BASE_CODE_SRVLIST DefaultSrvList;
318 PXEBC_CACHED_DHCP4_PACKET *Packet;
319 PXEBC_VENDOR_OPTION *VendorOpt;
320 UINT16 Index;
321 EFI_STATUS Status;
322 PXEBC_BOOT_SVR_ENTRY *BootSvrEntry;
323
324 if (This == NULL) {
325 return EFI_INVALID_PARAMETER;
326 }
327
328 Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
329 Mode = Private->PxeBc.Mode;
330 BootSvrEntry = NULL;
331 SrvList = NULL;
332 Status = EFI_DEVICE_ERROR;
333 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;
334
335 if (!Private->AddressIsOk) {
336 return EFI_INVALID_PARAMETER;
337 }
338
339 if (!Mode->Started) {
340 return EFI_NOT_STARTED;
341 }
342
343 //
344 // If layer isn't EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL,
345 // use the previous setting;
346 // If info isn't offered,
347 // use the cached DhcpAck and ProxyOffer packets.
348 //
349 if (*Layer != EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) {
350
351 if (!Mode->PxeDiscoverValid || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {
352
353 return EFI_INVALID_PARAMETER;
354 }
355
356 DefaultInfo.IpCnt = 1;
357 DefaultInfo.UseUCast = TRUE;
358
359 DefaultSrvList.Type = Type;
360 DefaultSrvList.AcceptAnyResponse = FALSE;
361 DefaultSrvList.IpAddr.Addr[0] = Private->ServerIp.Addr[0];
362
363 SrvList = &DefaultSrvList;
364 Info = &DefaultInfo;
365 } else if (Info == NULL) {
366 //
367 // Create info by the cached packet before
368 //
369 Packet = (Mode->ProxyOfferReceived) ? &Private->ProxyOffer : &Private->Dhcp4Ack;
370 VendorOpt = &Packet->PxeVendorOption;
371
372 if (!Mode->DhcpAckReceived || !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt->BitMap)) {
373 //
374 // Address is not acquired or no discovery options.
375 //
376 return EFI_INVALID_PARAMETER;
377 }
378
379 DefaultInfo.UseMCast = (BOOLEAN)!IS_DISABLE_MCAST_DISCOVER (VendorOpt->DiscoverCtrl);
380 DefaultInfo.UseBCast = (BOOLEAN)!IS_DISABLE_BCAST_DISCOVER (VendorOpt->DiscoverCtrl);
381 DefaultInfo.MustUseList = (BOOLEAN) IS_ENABLE_USE_SERVER_LIST (VendorOpt->DiscoverCtrl);
382 DefaultInfo.UseUCast = DefaultInfo.MustUseList;
383
384 if (DefaultInfo.UseMCast) {
385 //
386 // Get the multicast discover ip address from vendor option.
387 //
388 NetCopyMem (&DefaultInfo.ServerMCastIp.Addr, &VendorOpt->DiscoverMcastIp, sizeof (EFI_IPv4_ADDRESS));
389 }
390
391 DefaultInfo.IpCnt = 0;
392
393 if (DefaultInfo.MustUseList) {
394 BootSvrEntry = VendorOpt->BootSvr;
395 Status = EFI_INVALID_PARAMETER;
396
397 while (((UINT8) (BootSvrEntry - VendorOpt->BootSvr)) < VendorOpt->BootSvrLen) {
398
399 if (BootSvrEntry->Type == HTONS (Type)) {
400 Status = EFI_SUCCESS;
401 break;
402 }
403
404 BootSvrEntry = GET_NEXT_BOOT_SVR_ENTRY (BootSvrEntry);
405 }
406
407 if (EFI_ERROR (Status)) {
408 return Status;
409 }
410
411 DefaultInfo.IpCnt = BootSvrEntry->IpCnt;
412 }
413
414 Info = &DefaultInfo;
415 } else {
416
417 SrvList = Info->SrvList;
418
419 if (!SrvList[0].AcceptAnyResponse) {
420
421 for (Index = 1; Index < Info->IpCnt; Index++) {
422 if (SrvList[Index].AcceptAnyResponse) {
423 break;
424 }
425 }
426
427 if (Index != Info->IpCnt) {
428 return EFI_INVALID_PARAMETER;
429 }
430 }
431 }
432
433 if ((!Info->UseUCast && !Info->UseBCast && !Info->UseMCast) || (Info->MustUseList && Info->IpCnt == 0)) {
434
435 return EFI_INVALID_PARAMETER;
436 }
437 //
438 // Execute discover by UniCast/BroadCast/MultiCast
439 //
440 if (Info->UseUCast) {
441
442 for (Index = 0; Index < Info->IpCnt; Index++) {
443
444 if (BootSvrEntry == NULL) {
445 Private->ServerIp.Addr[0] = SrvList[Index].IpAddr.Addr[0];
446 } else {
447 NetCopyMem (&Private->ServerIp, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));
448 }
449
450 Status = PxeBcDiscvBootService (
451 Private,
452 Type,
453 Layer,
454 UseBis,
455 &SrvList[Index].IpAddr,
456 0,
457 NULL,
458 TRUE,
459 &Private->PxeReply.Packet.Ack
460 );
461 }
462
463 } else if (Info->UseMCast) {
464
465 Status = PxeBcDiscvBootService (
466 Private,
467 Type,
468 Layer,
469 UseBis,
470 &Info->ServerMCastIp,
471 0,
472 NULL,
473 TRUE,
474 &Private->PxeReply.Packet.Ack
475 );
476
477 } else if (Info->UseBCast) {
478
479 Status = PxeBcDiscvBootService (
480 Private,
481 Type,
482 Layer,
483 UseBis,
484 NULL,
485 Info->IpCnt,
486 SrvList,
487 TRUE,
488 &Private->PxeReply.Packet.Ack
489 );
490 }
491
492 if (EFI_ERROR (Status) || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {
493
494 Status = EFI_DEVICE_ERROR;
495 } else {
496 PxeBcParseCachedDhcpPacket (&Private->PxeReply);
497 }
498
499 if (Mode->PxeBisReplyReceived) {
500 NetCopyMem (&Private->ServerIp, &Mode->PxeReply.Dhcpv4.BootpSiAddr, sizeof (EFI_IPv4_ADDRESS));
501 }
502
503 return Status;
504 }
505
506
507 /**
508 GC_NOTO: Add function description
509
510 @param This GC_NOTO: add argument
511 description
512 @param Operation GC_NOTO: add argument
513 description
514 @param BufferPtr GC_NOTO: add argument
515 description
516 @param Overwrite GC_NOTO: add argument
517 description
518 @param BufferSize GC_NOTO: add argument
519 description
520 @param BlockSize GC_NOTO: add argument
521 description
522 @param ServerIp GC_NOTO: add argument
523 description
524 @param Filename GC_NOTO: add argument
525 description
526 @param Info GC_NOTO: add argument
527 description
528 @param DontUseBuffer GC_NOTO: add argument
529 description
530
531 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
532 return value
533
534 **/
535 EFI_STATUS
536 EFIAPI
537 EfiPxeBcMtftp (
538 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
539 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
540 IN OUT VOID *BufferPtr,
541 IN BOOLEAN Overwrite,
542 IN OUT UINT64 *BufferSize,
543 IN UINTN *BlockSize OPTIONAL,
544 IN EFI_IP_ADDRESS *ServerIp,
545 IN UINT8 *Filename,
546 IN EFI_PXE_BASE_CODE_MTFTP_INFO *Info OPTIONAL,
547 IN BOOLEAN DontUseBuffer
548 )
549 {
550 PXEBC_PRIVATE_DATA *Private;
551 EFI_MTFTP4_CONFIG_DATA Mtftp4Config;
552 EFI_STATUS Status;
553
554 if ((This == NULL) ||
555 (Filename == NULL) ||
556 (BufferSize == NULL) ||
557 ((ServerIp == NULL) || !Ip4IsUnicast (NTOHL (ServerIp->Addr[0]), 0)) ||
558 ((BufferPtr == NULL) && DontUseBuffer) ||
559 ((BlockSize != NULL) && (*BlockSize < 512))) {
560
561 return EFI_INVALID_PARAMETER;
562 }
563
564 Status = EFI_DEVICE_ERROR;
565 Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
566
567 Mtftp4Config.UseDefaultSetting = FALSE;
568 Mtftp4Config.TimeoutValue = PXEBC_MTFTP_TIMEOUT;
569 Mtftp4Config.TryCount = PXEBC_MTFTP_RETRIES;
570
571 NetCopyMem (&Mtftp4Config.StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
572 NetCopyMem (&Mtftp4Config.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
573 NetCopyMem (&Mtftp4Config.GatewayIp, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
574 NetCopyMem (&Mtftp4Config.ServerIp, ServerIp, sizeof (EFI_IPv4_ADDRESS));
575
576 switch (Operation) {
577
578 case EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE:
579
580 Status = PxeBcTftpGetFileSize (
581 Private,
582 &Mtftp4Config,
583 Filename,
584 BlockSize,
585 BufferSize
586 );
587
588 if (!EFI_ERROR (Status)) {
589 Status = EFI_BUFFER_TOO_SMALL;
590 }
591
592 break;
593
594 case EFI_PXE_BASE_CODE_TFTP_READ_FILE:
595
596 Status = PxeBcTftpReadFile (
597 Private,
598 &Mtftp4Config,
599 Filename,
600 BlockSize,
601 BufferPtr,
602 BufferSize,
603 DontUseBuffer
604 );
605
606 break;
607
608 case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:
609
610 Status = PxeBcTftpWriteFile (
611 Private,
612 &Mtftp4Config,
613 Filename,
614 Overwrite,
615 BlockSize,
616 BufferPtr,
617 BufferSize
618 );
619
620 break;
621
622 case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:
623
624 Status = PxeBcTftpReadDirectory (
625 Private,
626 &Mtftp4Config,
627 Filename,
628 BlockSize,
629 BufferPtr,
630 BufferSize,
631 DontUseBuffer
632 );
633
634 break;
635
636 case EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE:
637 case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:
638 case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:
639 Status = EFI_UNSUPPORTED;
640 break;
641
642 default:
643
644 Status = EFI_INVALID_PARAMETER;
645 break;
646 }
647
648 return Status;
649 }
650
651
652 /**
653 GC_NOTO: Add function description
654
655 @param This GC_NOTO: add argument
656 description
657 @param OpFlags GC_NOTO: add argument
658 description
659 @param DestIp GC_NOTO: add argument
660 description
661 @param DestPort GC_NOTO: add argument
662 description
663 @param GatewayIp GC_NOTO: add argument
664 description
665 @param SrcIp GC_NOTO: add argument
666 description
667 @param SrcPort GC_NOTO: add argument
668 description
669 @param HeaderSize GC_NOTO: add argument
670 description
671 @param HeaderPtr GC_NOTO: add argument
672 description
673 @param BufferSize GC_NOTO: add argument
674 description
675 @param BufferPtr GC_NOTO: add argument
676 description
677
678 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
679 return value
680 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
681 return value
682 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
683 return value
684 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
685 return value
686 @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for
687 return value
688
689 **/
690 EFI_STATUS
691 EFIAPI
692 EfiPxeBcUdpWrite (
693 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
694 IN UINT16 OpFlags,
695 IN EFI_IP_ADDRESS *DestIp,
696 IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort,
697 IN EFI_IP_ADDRESS *GatewayIp OPTIONAL,
698 IN EFI_IP_ADDRESS *SrcIp OPTIONAL,
699 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL,
700 IN UINTN *HeaderSize OPTIONAL,
701 IN VOID *HeaderPtr OPTIONAL,
702 IN UINTN *BufferSize,
703 IN VOID *BufferPtr
704 )
705 {
706 PXEBC_PRIVATE_DATA *Private;
707 EFI_UDP4_PROTOCOL *Udp4;
708 EFI_UDP4_COMPLETION_TOKEN Token;
709 EFI_UDP4_TRANSMIT_DATA *Udp4TxData;
710 UINT32 FragCount;
711 UINT32 DataLength;
712 EFI_UDP4_SESSION_DATA Udp4Session;
713 EFI_STATUS Status;
714 BOOLEAN IsDone;
715 UINT16 RandomSrcPort;
716
717 IsDone = FALSE;
718
719 if ((This == NULL) || (DestIp == NULL) || (DestPort == NULL)) {
720 return EFI_INVALID_PARAMETER;
721 }
722
723 if ((GatewayIp != NULL) && !Ip4IsUnicast (NTOHL (GatewayIp->Addr[0]), 0)) {
724 //
725 // Gateway is provided but it's not a unicast IP address.
726 //
727 return EFI_INVALID_PARAMETER;
728 }
729
730 if ((HeaderSize != NULL) && ((*HeaderSize == 0) || (HeaderPtr == NULL))) {
731 //
732 // The HeaderSize ptr isn't NULL and: 1. the value is zero; or 2. the HeaderPtr
733 // is NULL.
734 //
735 return EFI_INVALID_PARAMETER;
736 }
737
738 if ((BufferSize == NULL) || ((*BufferSize != 0) && (BufferPtr == NULL))) {
739 return EFI_INVALID_PARAMETER;
740 }
741
742 Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
743 Udp4 = Private->Udp4;
744
745 if (!Private->AddressIsOk && (SrcIp == NULL)) {
746 return EFI_INVALID_PARAMETER;
747 }
748
749 if (SrcIp == NULL) {
750 SrcIp = &Private->StationIp;
751
752 if (GatewayIp == NULL) {
753 GatewayIp = &Private->GatewayIp;
754 }
755 }
756
757 if ((SrcPort == NULL) || (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT)) {
758 RandomSrcPort = (UINT16) (NET_RANDOM (NetRandomInitSeed ()) % 10000 + 1024);
759
760 if (SrcPort == NULL) {
761
762 SrcPort = &RandomSrcPort;
763 } else {
764
765 *SrcPort = RandomSrcPort;
766 }
767 }
768
769 ZeroMem (&Token, sizeof (EFI_UDP4_COMPLETION_TOKEN));
770 ZeroMem (&Udp4Session, sizeof (EFI_UDP4_SESSION_DATA));
771
772 NetCopyMem (&Udp4Session.DestinationAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
773 Udp4Session.DestinationPort = *DestPort;
774 NetCopyMem (&Udp4Session.SourceAddress, SrcIp, sizeof (EFI_IPv4_ADDRESS));
775 Udp4Session.SourcePort = *SrcPort;
776
777 FragCount = (HeaderSize != NULL) ? 2 : 1;
778 Udp4TxData = (EFI_UDP4_TRANSMIT_DATA *) NetAllocatePool (sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA));
779 if (Udp4TxData == NULL) {
780 return EFI_OUT_OF_RESOURCES;
781 }
782
783 Udp4TxData->FragmentCount = FragCount;
784 Udp4TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;
785 Udp4TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
786 DataLength = (UINT32) *BufferSize;
787
788 if (FragCount == 2) {
789
790 Udp4TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;
791 Udp4TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
792 DataLength += (UINT32) *HeaderSize;
793 }
794
795 Udp4TxData->GatewayAddress = (EFI_IPv4_ADDRESS *) GatewayIp;
796 Udp4TxData->UdpSessionData = &Udp4Session;
797 Udp4TxData->DataLength = DataLength;
798 Token.Packet.TxData = Udp4TxData;
799
800 Status = gBS->CreateEvent (
801 EVT_NOTIFY_SIGNAL,
802 NET_TPL_EVENT,
803 PxeBcCommonNotify,
804 &IsDone,
805 &Token.Event
806 );
807 if (EFI_ERROR (Status)) {
808 goto ON_EXIT;
809 }
810
811 Status = Udp4->Transmit (Udp4, &Token);
812 if (EFI_ERROR (Status)) {
813 goto ON_EXIT;
814 }
815
816 while (!IsDone) {
817
818 Udp4->Poll (Udp4);
819 }
820
821 Status = Token.Status;
822
823 ON_EXIT:
824
825 if (Token.Event != NULL) {
826 gBS->CloseEvent (Token.Event);
827 }
828
829 NetFreePool (Udp4TxData);
830
831 return Status;
832 }
833
834
835 /**
836 GC_NOTO: Add function description
837
838 @param This GC_NOTO: add argument
839 description
840 @param OpFlags GC_NOTO: add argument
841 description
842 @param DestIp GC_NOTO: add argument
843 description
844 @param DestPort GC_NOTO: add argument
845 description
846 @param SrcIp GC_NOTO: add argument
847 description
848 @param SrcPort GC_NOTO: add argument
849 description
850 @param HeaderSize GC_NOTO: add argument
851 description
852 @param HeaderPtr GC_NOTO: add argument
853 description
854 @param BufferSize GC_NOTO: add argument
855 description
856 @param BufferPtr GC_NOTO: add argument
857 description
858
859 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
860 return value
861 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
862 return value
863 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
864 return value
865 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
866 return value
867 @retval EFI_NOT_STARTED GC_NOTO: Add description for
868 return value
869 @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for
870 return value
871
872 **/
873 EFI_STATUS
874 EFIAPI
875 EfiPxeBcUdpRead (
876 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
877 IN UINT16 OpFlags,
878 IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL
879 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL
880 IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL
881 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL
882 IN UINTN *HeaderSize, OPTIONAL
883 IN VOID *HeaderPtr, OPTIONAL
884 IN OUT UINTN *BufferSize,
885 IN VOID *BufferPtr
886 )
887 {
888 PXEBC_PRIVATE_DATA *Private;
889 EFI_PXE_BASE_CODE_MODE *Mode;
890 EFI_UDP4_PROTOCOL *Udp4;
891 EFI_UDP4_COMPLETION_TOKEN Token;
892 EFI_UDP4_RECEIVE_DATA *RxData;
893 EFI_UDP4_SESSION_DATA *Session;
894 EFI_STATUS Status;
895 BOOLEAN IsDone;
896 BOOLEAN Matched;
897 UINTN CopyLen;
898
899 if (This == NULL || DestIp == NULL || DestPort == NULL) {
900 return EFI_INVALID_PARAMETER;
901 }
902
903 if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) {
904 return EFI_UNSUPPORTED;
905 }
906
907 if ((!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && (DestPort == NULL)) ||
908 (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && (SrcIp == NULL)) ||
909 (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && (SrcPort == NULL))) {
910 return EFI_INVALID_PARAMETER;
911 }
912
913 if (((HeaderSize != NULL) && (*HeaderSize == 0)) || ((HeaderPtr == NULL) && (*HeaderSize != 0))) {
914 return EFI_INVALID_PARAMETER;
915 }
916
917 if ((BufferSize == NULL) || ((BufferPtr == NULL) && (*BufferSize != 0))) {
918 return EFI_INVALID_PARAMETER;
919 }
920
921 Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
922 Mode = Private->PxeBc.Mode;
923 Udp4 = Private->Udp4;
924
925 if (!Mode->Started) {
926 return EFI_NOT_STARTED;
927 }
928
929 Status = gBS->CreateEvent (
930 EVT_NOTIFY_SIGNAL,
931 NET_TPL_EVENT,
932 PxeBcCommonNotify,
933 &IsDone,
934 &Token.Event
935 );
936 if (EFI_ERROR (Status)) {
937 return EFI_OUT_OF_RESOURCES;
938 }
939
940 IsDone = FALSE;
941 Status = Udp4->Receive (Udp4, &Token);
942 if (EFI_ERROR (Status)) {
943 goto ON_EXIT;
944 }
945
946 Udp4->Poll (Udp4);
947
948 if (!IsDone) {
949 Status = EFI_TIMEOUT;
950 } else {
951
952 //
953 // check whether this packet matches the filters
954 //
955 if (EFI_ERROR (Token.Status)){
956 goto ON_EXIT;
957 }
958
959 RxData = Token.Packet.RxData;
960 Session = &RxData->UdpSession;
961
962 Matched = FALSE;
963
964 //
965 // Match the destination ip of the received udp dgram
966 //
967 if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) {
968 Matched = TRUE;
969
970 if (DestIp != NULL) {
971 NetCopyMem (DestIp, &Session->DestinationAddress, sizeof (EFI_IPv4_ADDRESS));
972 }
973 } else {
974 if (DestIp != NULL) {
975 if (EFI_IP4_EQUAL (DestIp, &Session->DestinationAddress)) {
976 Matched = TRUE;
977 }
978 } else {
979 if (EFI_IP4_EQUAL (&Private->StationIp, &Session->DestinationAddress)) {
980 Matched = TRUE;
981 }
982 }
983 }
984
985 if (Matched) {
986 //
987 // Match the destination port of the received udp dgram
988 //
989 if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) {
990
991 if (DestPort != NULL) {
992 *DestPort = Session->DestinationPort;
993 }
994 } else {
995
996 if (*DestPort != Session->DestinationPort) {
997 Matched = FALSE;
998 }
999 }
1000 }
1001
1002 if (Matched) {
1003 //
1004 // Match the source ip of the received udp dgram
1005 //
1006 if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) {
1007
1008 if (SrcIp != NULL) {
1009 NetCopyMem (SrcIp, &Session->SourceAddress, sizeof (EFI_IPv4_ADDRESS));
1010 }
1011 } else {
1012
1013 if (!EFI_IP4_EQUAL (SrcIp, &Session->SourceAddress)) {
1014 Matched = FALSE;
1015 }
1016 }
1017 }
1018
1019 if (Matched) {
1020 //
1021 // Match the source port of the received udp dgram
1022 //
1023 if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) {
1024
1025 if (SrcPort != NULL) {
1026 *SrcPort = Session->SourcePort;
1027 }
1028 } else {
1029
1030 if (*SrcPort != Session->SourcePort) {
1031 Matched = FALSE;
1032 }
1033 }
1034 }
1035
1036 if (Matched) {
1037
1038 CopyLen = 0;
1039
1040 if (HeaderSize != NULL) {
1041 CopyLen = MIN (*HeaderSize, RxData->DataLength);
1042 NetCopyMem (HeaderPtr, RxData->FragmentTable[0].FragmentBuffer, CopyLen);
1043 *HeaderSize = CopyLen;
1044 }
1045
1046 if (RxData->DataLength - CopyLen > *BufferSize) {
1047
1048 Status = EFI_BUFFER_TOO_SMALL;
1049 } else {
1050
1051 *BufferSize = RxData->DataLength - CopyLen;
1052 NetCopyMem (BufferPtr, (UINT8 *) RxData->FragmentTable[0].FragmentBuffer + CopyLen, *BufferSize);
1053 }
1054 } else {
1055
1056 Status = EFI_TIMEOUT;
1057 }
1058
1059 //
1060 // Recycle the RxData
1061 //
1062 gBS->SignalEvent (RxData->RecycleSignal);
1063 }
1064
1065 ON_EXIT:
1066
1067 Udp4->Cancel (Udp4, &Token);
1068
1069 gBS->CloseEvent (Token.Event);
1070
1071 return Status;
1072 }
1073
1074
1075 /**
1076 GC_NOTO: Add function description
1077
1078 @param This GC_NOTO: add argument
1079 description
1080 @param NewFilter GC_NOTO: add argument
1081 description
1082
1083 @retval EFI_UNSUPPORTED GC_NOTO: Add description for
1084 return value
1085
1086 **/
1087 EFI_STATUS
1088 EFIAPI
1089 EfiPxeBcSetIpFilter (
1090 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
1091 IN EFI_PXE_BASE_CODE_IP_FILTER *NewFilter
1092 )
1093 {
1094 return EFI_UNSUPPORTED;
1095 }
1096
1097
1098 /**
1099 GC_NOTO: Add function description
1100
1101 @param This GC_NOTO: add argument
1102 description
1103 @param IpAddr GC_NOTO: add argument
1104 description
1105 @param MacAddr GC_NOTO: add argument
1106 description
1107
1108 @retval EFI_UNSUPPORTED GC_NOTO: Add description for
1109 return value
1110
1111 **/
1112 EFI_STATUS
1113 EFIAPI
1114 EfiPxeBcArp (
1115 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
1116 IN EFI_IP_ADDRESS * IpAddr,
1117 IN EFI_MAC_ADDRESS * MacAddr OPTIONAL
1118 )
1119 {
1120 return EFI_UNSUPPORTED;
1121 }
1122
1123
1124 /**
1125 GC_NOTO: Add function description
1126
1127 @param This GC_NOTO: add argument
1128 description
1129 @param NewAutoArp GC_NOTO: add argument
1130 description
1131 @param NewSendGUID GC_NOTO: add argument
1132 description
1133 @param NewTTL GC_NOTO: add argument
1134 description
1135 @param NewToS GC_NOTO: add argument
1136 description
1137 @param NewMakeCallback GC_NOTO: add argument
1138 description
1139
1140 @return GC_NOTO: add return values
1141
1142 **/
1143 EFI_STATUS
1144 EFIAPI
1145 EfiPxeBcSetParameters (
1146 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
1147 IN BOOLEAN *NewAutoArp, OPTIONAL
1148 IN BOOLEAN *NewSendGUID, OPTIONAL
1149 IN UINT8 *NewTTL, OPTIONAL
1150 IN UINT8 *NewToS, OPTIONAL
1151 IN BOOLEAN *NewMakeCallback // OPTIONAL
1152 )
1153 {
1154 PXEBC_PRIVATE_DATA *Private;
1155 EFI_PXE_BASE_CODE_MODE *Mode;
1156 EFI_STATUS Status;
1157
1158 Status = EFI_SUCCESS;
1159
1160 if (This == NULL) {
1161 Status = EFI_INVALID_PARAMETER;
1162 goto ON_EXIT;
1163 }
1164
1165 Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1166 Mode = Private->PxeBc.Mode;
1167
1168 if (NewSendGUID != NULL && *NewSendGUID == TRUE) {
1169 //
1170 // FixMe, cann't locate SendGuid
1171 //
1172 }
1173
1174 if (NewMakeCallback != NULL && *NewMakeCallback == TRUE) {
1175
1176 Status = gBS->HandleProtocol (
1177 Private->Controller,
1178 &gEfiPxeBaseCodeCallbackProtocolGuid,
1179 (VOID **) &Private->PxeBcCallback
1180 );
1181 if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {
1182
1183 Status = EFI_INVALID_PARAMETER;
1184 goto ON_EXIT;
1185 }
1186 }
1187
1188 if (!Mode->Started) {
1189 Status = EFI_NOT_STARTED;
1190 goto ON_EXIT;
1191 }
1192
1193 if (NewMakeCallback != NULL) {
1194
1195 if (*NewMakeCallback) {
1196 //
1197 // Update the Callback protocol.
1198 //
1199 Status = gBS->HandleProtocol (
1200 Private->Controller,
1201 &gEfiPxeBaseCodeCallbackProtocolGuid,
1202 (VOID **) &Private->PxeBcCallback
1203 );
1204
1205 if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {
1206 Status = EFI_INVALID_PARAMETER;
1207 goto ON_EXIT;
1208 }
1209 } else {
1210 Private->PxeBcCallback = NULL;
1211 }
1212
1213 Mode->MakeCallbacks = *NewMakeCallback;
1214 }
1215
1216 if (NewAutoArp != NULL) {
1217 Mode->AutoArp = *NewAutoArp;
1218 }
1219
1220 if (NewSendGUID != NULL) {
1221 Mode->SendGUID = *NewSendGUID;
1222 }
1223
1224 if (NewTTL != NULL) {
1225 Mode->TTL = *NewTTL;
1226 }
1227
1228 if (NewToS != NULL) {
1229 Mode->ToS = *NewToS;
1230 }
1231
1232 ON_EXIT:
1233 return Status;
1234 }
1235
1236
1237 /**
1238 GC_NOTO: Add function description
1239
1240 @param This GC_NOTO: add argument
1241 description
1242 @param NewStationIp GC_NOTO: add argument
1243 description
1244 @param NewSubnetMask GC_NOTO: add argument
1245 description
1246
1247 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
1248 return value
1249 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
1250 return value
1251 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
1252 return value
1253 @retval EFI_NOT_STARTED GC_NOTO: Add description for
1254 return value
1255 @retval EFI_SUCCESS GC_NOTO: Add description for
1256 return value
1257
1258 **/
1259 EFI_STATUS
1260 EFIAPI
1261 EfiPxeBcSetStationIP (
1262 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
1263 IN EFI_IP_ADDRESS * NewStationIp, OPTIONAL
1264 IN EFI_IP_ADDRESS * NewSubnetMask OPTIONAL
1265 )
1266 {
1267 PXEBC_PRIVATE_DATA *Private;
1268 EFI_PXE_BASE_CODE_MODE *Mode;
1269
1270 if (This == NULL) {
1271 return EFI_INVALID_PARAMETER;
1272 }
1273
1274 if (NewStationIp != NULL && !Ip4IsUnicast (NTOHL (NewStationIp->Addr[0]), 0)) {
1275 return EFI_INVALID_PARAMETER;
1276 }
1277
1278 if (NewSubnetMask != NULL && !IP4_IS_VALID_NETMASK (NTOHL (NewSubnetMask->Addr[0]))) {
1279 return EFI_INVALID_PARAMETER;
1280 }
1281
1282 Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1283 Mode = Private->PxeBc.Mode;
1284
1285 if (!Mode->Started) {
1286 return EFI_NOT_STARTED;
1287 }
1288
1289 if (NewStationIp != NULL) {
1290 Mode->StationIp = *NewStationIp;
1291 }
1292
1293 if (NewSubnetMask != NULL) {
1294 Mode->SubnetMask = *NewSubnetMask;
1295 }
1296
1297 Private->AddressIsOk = TRUE;
1298
1299 return EFI_SUCCESS;
1300 }
1301
1302
1303 /**
1304 GC_NOTO: Add function description
1305
1306 @param This GC_NOTO: add argument
1307 description
1308 @param NewDhcpDiscoverValid GC_NOTO: add argument
1309 description
1310 @param NewDhcpAckReceived GC_NOTO: add argument
1311 description
1312 @param NewProxyOfferReceived GC_NOTO: add argument
1313 description
1314 @param NewPxeDiscoverValid GC_NOTO: add argument
1315 description
1316 @param NewPxeReplyReceived GC_NOTO: add argument
1317 description
1318 @param NewPxeBisReplyReceived GC_NOTO: add argument
1319 description
1320 @param NewDhcpDiscover GC_NOTO: add argument
1321 description
1322 @param NewDhcpAck GC_NOTO: add argument
1323 description
1324 @param NewProxyOffer GC_NOTO: add argument
1325 description
1326 @param NewPxeDiscover GC_NOTO: add argument
1327 description
1328 @param NewPxeReply GC_NOTO: add argument
1329 description
1330 @param NewPxeBisReply GC_NOTO: add argument
1331 description
1332
1333 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
1334 return value
1335 @retval EFI_NOT_STARTED GC_NOTO: Add description for
1336 return value
1337 @retval EFI_SUCCESS GC_NOTO: Add description for
1338 return value
1339
1340 **/
1341 EFI_STATUS
1342 EFIAPI
1343 EfiPxeBcSetPackets (
1344 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
1345 IN BOOLEAN * NewDhcpDiscoverValid, OPTIONAL
1346 IN BOOLEAN * NewDhcpAckReceived, OPTIONAL
1347 IN BOOLEAN * NewProxyOfferReceived, OPTIONAL
1348 IN BOOLEAN * NewPxeDiscoverValid, OPTIONAL
1349 IN BOOLEAN * NewPxeReplyReceived, OPTIONAL
1350 IN BOOLEAN * NewPxeBisReplyReceived, OPTIONAL
1351 IN EFI_PXE_BASE_CODE_PACKET * NewDhcpDiscover, OPTIONAL
1352 IN EFI_PXE_BASE_CODE_PACKET * NewDhcpAck, OPTIONAL
1353 IN EFI_PXE_BASE_CODE_PACKET * NewProxyOffer, OPTIONAL
1354 IN EFI_PXE_BASE_CODE_PACKET * NewPxeDiscover, OPTIONAL
1355 IN EFI_PXE_BASE_CODE_PACKET * NewPxeReply, OPTIONAL
1356 IN EFI_PXE_BASE_CODE_PACKET * NewPxeBisReply OPTIONAL
1357 )
1358 {
1359 PXEBC_PRIVATE_DATA *Private;
1360 EFI_PXE_BASE_CODE_MODE *Mode;
1361
1362 if (This == NULL) {
1363 return EFI_INVALID_PARAMETER;
1364 }
1365
1366 Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
1367 Mode = Private->PxeBc.Mode;
1368
1369 if (!Mode->Started) {
1370 return EFI_NOT_STARTED;
1371 }
1372
1373 Private->FileSize = 0;
1374
1375 if (NewDhcpDiscoverValid != NULL) {
1376 Mode->DhcpDiscoverValid = *NewDhcpDiscoverValid;
1377 }
1378
1379 if (NewDhcpAckReceived != NULL) {
1380 Mode->DhcpAckReceived = *NewDhcpAckReceived;
1381 }
1382
1383 if (NewProxyOfferReceived != NULL) {
1384 Mode->ProxyOfferReceived = *NewProxyOfferReceived;
1385 }
1386
1387 if (NewPxeDiscoverValid != NULL) {
1388 Mode->PxeDiscoverValid = *NewPxeDiscoverValid;
1389 }
1390
1391 if (NewPxeReplyReceived != NULL) {
1392 Mode->PxeReplyReceived = *NewPxeReplyReceived;
1393 }
1394
1395 if (NewPxeBisReplyReceived != NULL) {
1396 Mode->PxeBisReplyReceived = *NewPxeBisReplyReceived;
1397 }
1398
1399 if (NewDhcpDiscover != NULL) {
1400 NetCopyMem (&Mode->DhcpDiscover, NewDhcpDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
1401 }
1402
1403 if (NewDhcpAck != NULL) {
1404 NetCopyMem (&Mode->DhcpAck, NewDhcpAck, sizeof (EFI_PXE_BASE_CODE_PACKET));
1405 }
1406
1407 if (NewProxyOffer != NULL) {
1408 NetCopyMem (&Mode->ProxyOffer, NewProxyOffer, sizeof (EFI_PXE_BASE_CODE_PACKET));
1409 }
1410
1411 if (NewPxeDiscover != NULL) {
1412 NetCopyMem (&Mode->PxeDiscover, NewPxeDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
1413 }
1414
1415 if (NewPxeReply != NULL) {
1416 NetCopyMem (&Mode->PxeReply, NewPxeReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
1417 }
1418
1419 if (NewPxeBisReply != NULL) {
1420 NetCopyMem (&Mode->PxeBisReply, NewPxeBisReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
1421 }
1422
1423 return EFI_SUCCESS;
1424 }
1425
1426 EFI_PXE_BASE_CODE_PROTOCOL mPxeBcProtocolTemplate = {
1427 EFI_PXE_BASE_CODE_PROTOCOL_REVISION,
1428 EfiPxeBcStart,
1429 EfiPxeBcStop,
1430 EfiPxeBcDhcp,
1431 EfiPxeBcDiscover,
1432 EfiPxeBcMtftp,
1433 EfiPxeBcUdpWrite,
1434 EfiPxeBcUdpRead,
1435 EfiPxeBcSetIpFilter,
1436 EfiPxeBcArp,
1437 EfiPxeBcSetParameters,
1438 EfiPxeBcSetStationIP,
1439 EfiPxeBcSetPackets,
1440 NULL
1441 };
1442
1443
1444 /**
1445 GC_NOTO: Add function description
1446
1447 @param This GC_NOTO: add argument
1448 description
1449 @param Function GC_NOTO: add argument
1450 description
1451 @param Received GC_NOTO: add argument
1452 description
1453 @param PacketLength GC_NOTO: add argument
1454 description
1455 @param PacketPtr GC_NOTO: add argument
1456 description
1457
1458 @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT GC_NOTO: Add description for
1459 return value
1460 @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE GC_NOTO: Add description for
1461 return value
1462 @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE GC_NOTO: Add description for
1463 return value
1464 @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE GC_NOTO: Add description for
1465 return value
1466 @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE GC_NOTO: Add description for
1467 return value
1468
1469 **/
1470 EFI_PXE_BASE_CODE_CALLBACK_STATUS
1471 EFIAPI
1472 EfiPxeLoadFileCallback (
1473 IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL * This,
1474 IN EFI_PXE_BASE_CODE_FUNCTION Function,
1475 IN BOOLEAN Received,
1476 IN UINT32 PacketLength,
1477 IN EFI_PXE_BASE_CODE_PACKET * PacketPtr OPTIONAL
1478 )
1479 {
1480 EFI_INPUT_KEY Key;
1481 EFI_STATUS Status;
1482
1483 //
1484 // Catch Ctrl-C or ESC to abort.
1485 //
1486 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
1487
1488 if (!EFI_ERROR (Status)) {
1489
1490 if (Key.ScanCode == SCAN_ESC || Key.UnicodeChar == (0x1F & 'c')) {
1491
1492 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
1493 }
1494 }
1495 //
1496 // No print if receive packet
1497 //
1498 if (Received) {
1499 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
1500 }
1501 //
1502 // Print only for three functions
1503 //
1504 switch (Function) {
1505
1506 case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:
1507 //
1508 // Print only for open MTFTP packets, not every MTFTP packets
1509 //
1510 if (PacketLength != 0 && PacketPtr != NULL) {
1511 if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {
1512 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
1513 }
1514 }
1515 break;
1516
1517 case EFI_PXE_BASE_CODE_FUNCTION_DHCP:
1518 case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:
1519 break;
1520
1521 default:
1522 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
1523 }
1524
1525 if (PacketLength != 0 && PacketPtr != NULL) {
1526 //
1527 // Print '.' when transmit a packet
1528 //
1529 AsciiPrint (".");
1530
1531 }
1532
1533 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
1534 }
1535
1536 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL mPxeBcCallBackTemplate = {
1537 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION,
1538 EfiPxeLoadFileCallback
1539 };
1540
1541
1542 /**
1543 GC_NOTO: Add function description
1544
1545 @param Private GC_NOTO: add argument
1546 description
1547 @param BufferSize GC_NOTO: add argument
1548 description
1549 @param Buffer GC_NOTO: add argument
1550 description
1551
1552 @return GC_NOTO: add return values
1553
1554 **/
1555 EFI_STATUS
1556 DiscoverBootFile (
1557 IN PXEBC_PRIVATE_DATA *Private,
1558 IN OUT UINT64 *BufferSize,
1559 IN VOID *Buffer
1560 )
1561 {
1562 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
1563 EFI_PXE_BASE_CODE_MODE *Mode;
1564 EFI_STATUS Status;
1565 UINT16 Type;
1566 UINT16 Layer;
1567 BOOLEAN UseBis;
1568 UINTN BlockSize;
1569 PXEBC_CACHED_DHCP4_PACKET *Packet;
1570 UINT16 Value;
1571
1572 PxeBc = &Private->PxeBc;
1573 Mode = PxeBc->Mode;
1574 Type = EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP;
1575 Layer = EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL;
1576
1577 //
1578 // do DHCP.
1579 //
1580 Status = PxeBc->Dhcp (PxeBc, TRUE);
1581 if (EFI_ERROR (Status)) {
1582 return Status;
1583 }
1584
1585 //
1586 // Select a boot server
1587 //
1588 Status = PxeBcSelectBootPrompt (Private);
1589
1590 if (Status == EFI_SUCCESS) {
1591 Status = PxeBcSelectBootMenu (Private, &Type, TRUE);
1592 } else if (Status == EFI_TIMEOUT) {
1593 Status = PxeBcSelectBootMenu (Private, &Type, FALSE);
1594 }
1595
1596 if (!EFI_ERROR (Status)) {
1597
1598 if (Type == EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP) {
1599 //
1600 // Local boot(PXE bootstrap server) need abort
1601 //
1602 return EFI_ABORTED;
1603 }
1604
1605 UseBis = (BOOLEAN) (Mode->BisSupported && Mode->BisDetected);
1606 Status = PxeBc->Discover (PxeBc, Type, &Layer, UseBis, NULL);
1607 if (EFI_ERROR (Status)) {
1608 return Status;
1609 }
1610 }
1611
1612 *BufferSize = 0;
1613 BlockSize = 0x8000;
1614
1615 //
1616 // Get bootfile name and (m)tftp server ip addresss
1617 //
1618 if (Mode->PxeReplyReceived) {
1619 Packet = &Private->PxeReply;
1620 } else if (Mode->ProxyOfferReceived) {
1621 Packet = &Private->ProxyOffer;
1622 } else {
1623 Packet = &Private->Dhcp4Ack;
1624 }
1625
1626 NetCopyMem (&Private->ServerIp, &Packet->Packet.Offer.Dhcp4.Header.ServerAddr, sizeof (EFI_IPv4_ADDRESS));
1627 if (Private->ServerIp.Addr[0] == 0) {
1628 //
1629 // next server ip address is zero, use option 54 instead
1630 //
1631 NetCopyMem (
1632 &Private->ServerIp,
1633 Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
1634 sizeof (EFI_IPv4_ADDRESS)
1635 );
1636 }
1637
1638 ASSERT (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);
1639
1640 //
1641 // bootlfile name
1642 //
1643 Private->BootFileName = (CHAR8 *) (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data);
1644
1645 if (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {
1646 //
1647 // Already have the bootfile length option, compute the file size
1648 //
1649 NetCopyMem (&Value, Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value));
1650 Value = NTOHS (Value);
1651 *BufferSize = 512 * Value;
1652 Status = EFI_BUFFER_TOO_SMALL;
1653 } else {
1654 //
1655 // Get the bootfile size from tftp
1656 //
1657 Status = PxeBc->Mtftp (
1658 PxeBc,
1659 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
1660 Buffer,
1661 FALSE,
1662 BufferSize,
1663 &BlockSize,
1664 &Private->ServerIp,
1665 (UINT8 *) Private->BootFileName,
1666 NULL,
1667 FALSE
1668 );
1669 }
1670
1671 Private->FileSize = (UINTN) *BufferSize;
1672
1673 return Status;
1674 }
1675
1676
1677 /**
1678 GC_NOTO: Add function description
1679
1680 @param This GC_NOTO: add argument
1681 description
1682 @param FilePath GC_NOTO: add argument
1683 description
1684 @param BootPolicy GC_NOTO: add argument
1685 description
1686 @param BufferSize GC_NOTO: add argument
1687 description
1688 @param Buffer GC_NOTO: add argument
1689 description
1690
1691 @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
1692 return value
1693 @retval EFI_UNSUPPORTED GC_NOTO: Add description for
1694 return value
1695
1696 **/
1697 EFI_STATUS
1698 EFIAPI
1699 EfiPxeLoadFile (
1700 IN EFI_LOAD_FILE_PROTOCOL * This,
1701 IN EFI_DEVICE_PATH_PROTOCOL * FilePath,
1702 IN BOOLEAN BootPolicy,
1703 IN OUT UINTN *BufferSize,
1704 IN VOID *Buffer OPTIONAL
1705 )
1706 {
1707 PXEBC_PRIVATE_DATA *Private;
1708 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
1709 BOOLEAN NewMakeCallback;
1710 UINTN BlockSize;
1711 EFI_STATUS Status;
1712 UINT64 TmpBufSize;
1713
1714 Private = PXEBC_PRIVATE_DATA_FROM_LOADFILE (This);
1715 PxeBc = &Private->PxeBc;
1716 NewMakeCallback = FALSE;
1717 BlockSize = 0x8000;
1718 Status = EFI_DEVICE_ERROR;
1719
1720 if (This == NULL || BufferSize == NULL) {
1721
1722 return EFI_INVALID_PARAMETER;
1723 }
1724
1725 //
1726 // Only support BootPolicy
1727 //
1728 if (!BootPolicy) {
1729 return EFI_UNSUPPORTED;
1730 }
1731
1732 Status = PxeBc->Start (PxeBc, FALSE);
1733 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
1734 return Status;
1735 }
1736
1737 Status = gBS->HandleProtocol (
1738 Private->Controller,
1739 &gEfiPxeBaseCodeCallbackProtocolGuid,
1740 (VOID **) &Private->PxeBcCallback
1741 );
1742 if (Status == EFI_UNSUPPORTED) {
1743
1744 CopyMem (&Private->LoadFileCallback, &mPxeBcCallBackTemplate, sizeof (Private->LoadFileCallback));
1745
1746 Status = gBS->InstallProtocolInterface (
1747 &Private->Controller,
1748 &gEfiPxeBaseCodeCallbackProtocolGuid,
1749 EFI_NATIVE_INTERFACE,
1750 &Private->LoadFileCallback
1751 );
1752
1753 NewMakeCallback = (BOOLEAN) (Status == EFI_SUCCESS);
1754
1755 Status = PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);
1756 if (EFI_ERROR (Status)) {
1757 PxeBc->Stop (PxeBc);
1758 return Status;
1759 }
1760 }
1761
1762 if (Private->FileSize == 0) {
1763 TmpBufSize = 0;
1764 Status = DiscoverBootFile (Private, &TmpBufSize, Buffer);
1765
1766 if (sizeof (UINTN) < sizeof (UINT64) && (TmpBufSize > 0xFFFFFFFF)) {
1767 Status = EFI_DEVICE_ERROR;
1768 } else {
1769 *BufferSize = (UINTN) TmpBufSize;
1770 }
1771 } else if (Buffer == NULL) {
1772 *BufferSize = Private->FileSize;
1773 Status = EFI_BUFFER_TOO_SMALL;
1774 } else {
1775 //
1776 // Download the file.
1777 //
1778 TmpBufSize = (UINT64) (*BufferSize);
1779 Status = PxeBc->Mtftp (
1780 PxeBc,
1781 EFI_PXE_BASE_CODE_TFTP_READ_FILE,
1782 Buffer,
1783 FALSE,
1784 &TmpBufSize,
1785 &BlockSize,
1786 &Private->ServerIp,
1787 (UINT8 *) Private->BootFileName,
1788 NULL,
1789 FALSE
1790 );
1791 }
1792 //
1793 // If we added a callback protocol, now is the time to remove it.
1794 //
1795 if (NewMakeCallback) {
1796
1797 NewMakeCallback = FALSE;
1798
1799 PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);
1800
1801 gBS->UninstallProtocolInterface (
1802 Private->Controller,
1803 &gEfiPxeBaseCodeCallbackProtocolGuid,
1804 &Private->LoadFileCallback
1805 );
1806 }
1807 //
1808 // Check download status
1809 //
1810 switch (Status) {
1811
1812 case EFI_SUCCESS:
1813 break;
1814
1815 case EFI_BUFFER_TOO_SMALL:
1816 if (Buffer != NULL) {
1817 AsciiPrint ("PXE-E05: Download buffer is smaller than requested file.\n");
1818 } else {
1819 return Status;
1820 }
1821 break;
1822
1823 case EFI_DEVICE_ERROR:
1824 AsciiPrint ("PXE-E07: Network device error.\n");
1825 break;
1826
1827 case EFI_OUT_OF_RESOURCES:
1828 AsciiPrint ("PXE-E09: Could not allocate I/O buffers.\n");
1829 break;
1830
1831 case EFI_NO_MEDIA:
1832 AsciiPrint ("PXE-E12: Could not detect network connection.\n");
1833 break;
1834
1835 case EFI_NO_RESPONSE:
1836 AsciiPrint ("PXE-E16: No offer received.\n");
1837 break;
1838
1839 case EFI_TIMEOUT:
1840 AsciiPrint ("PXE-E18: Server response timeout.\n");
1841 break;
1842
1843 case EFI_ABORTED:
1844 AsciiPrint ("PXE-E21: Remote boot cancelled.\n");
1845 break;
1846
1847 case EFI_ICMP_ERROR:
1848 AsciiPrint ("PXE-E22: Client received ICMP error from server.\n");
1849 break;
1850
1851 case EFI_TFTP_ERROR:
1852 AsciiPrint ("PXE-E23: Client received TFTP error from server.\n");
1853 break;
1854
1855 default:
1856 AsciiPrint ("PXE-E99: Unexpected network error.\n");
1857 break;
1858 }
1859
1860 PxeBc->Stop (PxeBc);
1861
1862 return Status;
1863 }
1864
1865 EFI_LOAD_FILE_PROTOCOL mLoadFileProtocolTemplate = { EfiPxeLoadFile };
1866