3 Copyright (c) 2006, 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
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.
17 TFTP and MTFTP (multicast TFTP) implementation.
23 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
26 // The following #define is used to create a version that does not wait to
27 // open after a listen. This is just for a special regression test of MTFTP
28 // server to make sure multiple opens are handled correctly. Normally this
29 // next line should be a comment.
30 // #define SpecialNowaitVersion // comment out for normal operation
33 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
38 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
72 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
76 PXE_BASECODE_DEVICE
*Private
,
81 EFI_IP_ADDRESS
*ServerIpPtr
,
82 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
83 EFI_IP_ADDRESS
*OurIpPtr
,
84 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
89 Read TFTP packet. If TFTP ERROR packet is read, fill in TFTP error
90 information in Mode structure and return TFTP_ERROR status.
110 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
112 EFI_EVENT TimeoutEvent
;
118 Status
= gBS
->CreateEvent (
126 if (EFI_ERROR (Status
)) {
130 Status
= gBS
->SetTimer (
133 Timeout
* 10000000 + 1000000
136 if (EFI_ERROR (Status
)) {
137 gBS
->CloseEvent (TimeoutEvent
);
143 HeaderSize
= Private
->BigBlkNumFlag
? sizeof (struct Tftpv4Ack8
) : sizeof (struct Tftpv4Ack
);
145 #define ERROR_MESSAGE_PTR ((struct Tftpv4Error *) HeaderPtr)
161 if (Status
!= EFI_SUCCESS
|| ERROR_MESSAGE_PTR
->OpCode
!= HTONS (TFTP_ERROR
)) {
162 gBS
->CloseEvent (TimeoutEvent
);
166 // got an error packet
167 // write one byte error code followed by error message
169 PxeBcMode
= Private
->EfiBc
.Mode
;
170 PxeBcMode
->TftpErrorReceived
= TRUE
;
171 PxeBcMode
->TftpError
.ErrorCode
= (UINT8
) NTOHS (ERROR_MESSAGE_PTR
->ErrCode
);
172 HeaderSize
= EFI_MIN (*BufferSizePtr
, sizeof PxeBcMode
->TftpError
.ErrorString
);
173 CopyMem (PxeBcMode
->TftpError
.ErrorString
, BufferPtr
, HeaderSize
);
175 gBS
->CloseEvent (TimeoutEvent
);
176 return EFI_TFTP_ERROR
;
179 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
183 PXE_BASECODE_DEVICE
*Private
,
184 EFI_IP_ADDRESS
*ServerIpPtr
,
185 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
186 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
190 Send TFTP ERROR message to TFTP server
201 struct Tftpv4Error
*ErrStr
;
204 ErrStr
= (VOID
*) Private
->TftpErrorBuffer
;
205 Len
= sizeof *ErrStr
;
207 ErrStr
->OpCode
= HTONS (TFTP_ERROR
);
208 ErrStr
->ErrCode
= HTONS (TFTP_ERR_OPTION
);
209 ErrStr
->ErrMsg
[0] = 0;
213 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
226 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
230 PXE_BASECODE_DEVICE
*Private
,
231 EFI_IP_ADDRESS
*ServerIpPtr
,
232 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
233 EFI_IP_ADDRESS
*ReplyIpPtr
,
234 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
243 Send TFTP ACK packet to server and read next DATA packet.
246 Private := Pointer to PxeBc interface
247 ServerIpPtr := Pointer to TFTP server IP address
248 ServerPortPtr := Pointer to TFTP server UDP port
249 ReplyIpPtr := Pointer to TFTP DATA packet destination IP address
250 OurPortPtr := Pointer to TFTP client UDP port
252 ReplyLenPtr := Pointer to packet length
253 PxeBcMode := Pointer to packet buffer
254 BlockNumPtr := Pointer to block number
255 AckOnly := TRUE == Send last ack - do not wait for reply
260 struct Tftpv4Data DataBuffer
;
261 struct Tftpv4Ack
*Ack2Ptr
;
262 struct Tftpv4Ack8
*Ack8Ptr
;
266 Ack2Ptr
= (VOID
*) Private
->TftpAckBuffer
;
267 Ack8Ptr
= (VOID
*) Private
->TftpAckBuffer
;
269 if (Private
->BigBlkNumFlag
) {
270 Len
= sizeof (struct Tftpv4Ack8
);
272 Ack8Ptr
->OpCode
= HTONS (TFTP_ACK8
);
273 Ack8Ptr
->BlockNum
= Swap64 (*BlockNumPtr
);
277 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
289 if (EFI_ERROR (Status
)) {
293 Len
= sizeof (struct Tftpv4Ack
);
295 Ack2Ptr
->OpCode
= HTONS (TFTP_ACK
);
296 Ack2Ptr
->BlockNum
= HTONS ((UINT16
) *BlockNumPtr
);
300 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
312 if (EFI_ERROR (Status
)) {
319 // ACK of last packet. This is just a courtesy.
320 // Do not wait for response.
327 Status
= TftpUdpRead (
340 if (EFI_ERROR (Status
) && Status
!= EFI_BUFFER_TOO_SMALL
) {
344 // got a good reply (so far)
345 // check for next data packet
347 if (!Private
->BigBlkNumFlag
&& DataBuffer
.Header
.OpCode
== HTONS (TFTP_DATA
)) {
348 if (Status
== EFI_BUFFER_TOO_SMALL
) {
349 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
352 *BlockNumPtr
= NTOHS (DataBuffer
.Header
.BlockNum
);
356 if (Private
->BigBlkNumFlag
&& DataBuffer
.Header
.OpCode
== HTONS (TFTP_DATA8
)) {
357 if (Status
== EFI_BUFFER_TOO_SMALL
) {
358 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
361 *BlockNumPtr
= Swap64 (*(UINT64
*) &DataBuffer
.Header
.BlockNum
);
365 return EFI_PROTOCOL_ERROR
;
368 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
372 PXE_BASECODE_DEVICE
*Private
,
374 UINT64
*BufferSizePtr
,
377 EFI_IP_ADDRESS
*ServerIpPtr
,
378 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
379 EFI_IP_ADDRESS
*ReplyIpPtr
,
380 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
383 IN BOOLEAN DontUseBuffer
387 Read rest of file after successfull M/TFTP request.
390 Private := Pointer to PxeBc interface
391 PacketSize := Pointer to packet size
392 BufferSizePtr := Pointer to buffer (file) size
393 Offset := Offset into buffer of next packet
394 BufferPtr := Pointer to receive buffer
395 ServerIpPtr := Pointer to TFTP server IP address
396 ServerPortPtr := Pointer to TFTP server UDP port
397 ReplyIpPtr := Pointer to TFTP DATA packet destination IP address
398 OurPortPtr := Pointer to TFTP client UDP port
399 LastBlock := Last block number received
401 DontUseBuffer := TRUE == throw away data, just count # of bytes
413 ReplyLen
= PacketSize
;
414 BlockNum
= LastBlock
;
416 DEBUG ((EFI_D_INFO
, "\nLockStepReceive() PacketSize = %d", PacketSize
));
419 BufferSize
= PacketSize
;
421 BufferSize
= *BufferSizePtr
- Offset
;
425 while (ReplyLen
>= 512 && ReplyLen
== PacketSize
) {
426 if (BufferSize
< PacketSize
) {
427 ReplyLen
= (UINTN
) ((BufferSize
> 0) ? BufferSize
: 0);
433 // write an ack packet and get data - retry up to NUM_ACK_RETRIES on timeout
435 Retries
= NUM_ACK_RETRIES
;
440 Status
= SendAckAndGetData (
453 if (!EFI_ERROR (Status
) || Status
== EFI_BUFFER_TOO_SMALL
) {
454 if (BlockNum
== LastBlock
) {
455 DEBUG ((EFI_D_NET
, "\nresend"));
457 // a resend - continue
459 Status
= EFI_TIMEOUT
;
460 } else if (Private
->BigBlkNumFlag
) {
461 if (BlockNum
!= ++LastBlock
) {
462 DEBUG ((EFI_D_NET
, "\nLockStepReceive() Exit #1a"));
464 // not correct blocknum - error
466 return EFI_PROTOCOL_ERROR
;
469 LastBlock
= (LastBlock
+ 1) & 0xFFFF;
470 if (BlockNum
!= LastBlock
) {
471 DEBUG ((EFI_D_NET
, "\nLockStepReceive() Exit #1b"));
472 return EFI_PROTOCOL_ERROR
;
474 // not correct blocknum - error
479 } while (Status
== EFI_TIMEOUT
&& --Retries
);
481 if (EFI_ERROR (Status
)) {
482 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
483 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
490 BufferSize
+= ReplyLen
;
492 BufferPtr
+= ReplyLen
;
493 BufferSize
-= ReplyLen
;
497 // while (ReplyLen == PacketSize);
500 if (BufferSizePtr
!= NULL
) {
501 *BufferSizePtr
= (BufferSize
- PacketSize
);
504 *BufferSizePtr
-= BufferSize
;
507 /* Send ACK of last packet. */
526 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
531 STATIC UINT8 Mode
[] = MODE_BINARY
;
532 STATIC UINT8 BlockSizeOp
[] = OP_BLKSIZE
;
533 STATIC UINT8 TsizeOp
[] = OP_TFRSIZE
;
534 STATIC UINT8 OverwriteOp
[] = OP_OVERWRITE
;
535 STATIC UINT8 BigBlkNumOp
[] = OP_BIGBLKNUM
;
536 STATIC EFI_PXE_BASE_CODE_UDP_PORT TftpRequestPort
= TFTP_OPEN_PORT
;
538 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
549 Check TFTP OACK packet for option.
552 OptionPtr := Pointer to option string to find
553 OpLen := Length of option string
554 OackPtr := Pointer to OACK data
555 OackSize := Length of OACK data
558 Pointer to value field if option found or NULL if not found.
561 if ((OackSize
-= OpLen
) <= 0) {
566 if (!CompareMem (OackPtr
, OptionPtr
, OpLen
)) {
567 return OackPtr
+ OpLen
;
571 } while (--OackSize
);
576 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
577 #define BKSZOP 1 // block size
578 #define TSIZEOP 2 // transfer size
579 #define OVERWRITEOP 4 // overwrite
580 #define BIGBLKNUMOP 8 // big block numbers
586 PXE_BASECODE_DEVICE
*Private
,
587 EFI_IP_ADDRESS
*ServerIpPtr
,
588 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
589 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
591 UINTN
*PacketSizePtr
,
596 Send TFTP RRQ/WRQ packet.
599 Req := Type of request to send
600 Options := One or more of the #define values above
601 Private := Pointer to PxeBc interface
602 ServerIpPtr := Pointer to TFTP server IP address
603 ServerPortPtr := Pointer to TFTP server UDP port
604 OurPortPtr := Pointer to TFTP client UDP port
605 FilenamePtr := Pointer to TFTP file or directory name
606 PacketSizePtr := Pointer to block size
614 struct Tftpv4Req ReqStr
;
622 if (*OurPortPtr
== 0) {
623 OpFlags
= EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
| EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
;
625 OpFlags
= EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
;
628 // build the basic request - opcode, filename, mode
631 u
->ReqStr
.OpCode
= HTONS (Req
);
632 TotalLen
= sizeof (Mode
) + sizeof (u
->ReqStr
.OpCode
) + (Len
= 1 + AsciiStrLen ((CHAR8
*)FilenamePtr
));
634 CopyMem (u
->ReqStr
.FileName
, FilenamePtr
, Len
);
635 Ptr
= (UINT8
*) (u
->ReqStr
.FileName
+ Len
);
637 CopyMem (Ptr
, Mode
, sizeof (Mode
));
638 Ptr
+= sizeof (Mode
);
640 if (Options
& BKSZOP
) {
641 CopyMem (Ptr
, BlockSizeOp
, sizeof (BlockSizeOp
));
642 UtoA10 (*PacketSizePtr
, Ptr
+ sizeof (BlockSizeOp
));
644 TotalLen
+= (Len
= 1 + AsciiStrLen ((CHAR8
*)Ptr
+ sizeof (BlockSizeOp
)) + sizeof (BlockSizeOp
));
649 if (Options
& TSIZEOP
) {
650 CopyMem (Ptr
, TsizeOp
, sizeof (TsizeOp
));
651 CopyMem (Ptr
+ sizeof (TsizeOp
), "0", 2);
652 TotalLen
+= sizeof (TsizeOp
) + 2;
653 Ptr
+= sizeof (TsizeOp
) + 2;
656 if (Options
& OVERWRITEOP
) {
657 CopyMem (Ptr
, OverwriteOp
, sizeof (OverwriteOp
));
658 CopyMem (Ptr
+ sizeof (OverwriteOp
), "1", 2);
659 TotalLen
+= sizeof (OverwriteOp
) + 2;
660 Ptr
+= sizeof (OverwriteOp
) + 2;
663 if (Options
& BIGBLKNUMOP
) {
664 CopyMem (Ptr
, BigBlkNumOp
, sizeof (BigBlkNumOp
));
665 CopyMem (Ptr
+ sizeof (BigBlkNumOp
), "8", 2);
666 TotalLen
+= sizeof (BigBlkNumOp
) + 2;
667 Ptr
+= sizeof (BigBlkNumOp
) + 2;
687 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
693 PXE_BASECODE_DEVICE
*Private
,
695 UINTN
*PacketSizePtr
,
698 EFI_IP_ADDRESS
*ServerIpPtr
,
699 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
700 EFI_PXE_BASE_CODE_UDP_PORT
*ServerReplyPortPtr
,
701 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
707 Start TFTP session. Issue request and wait for response.
708 Retry three times on error. If failed using options,
709 retry three times w/o options on error.
712 Req := TFTP request type
713 Options := TFTP option bits
714 Private := Pointer to PxeBc interface
716 PacketSizePtr := Pointer to block size
719 ServerIpPtr := Pointer to TFTP server IP address
720 ServerPortPtr := Pointer to TFTP server UDP port
721 ServerReplyPortPtr :=
722 OurPortPtr := Pointer to TFTP client UDP Port
723 FilenamePtr := Pointer to file or directory name
734 SaveReplyLen
= *ReplyLenPtr
;
736 Private
->BigBlkNumFlag
= FALSE
;
742 if (*OurPortPtr
!= 0) {
743 if (++ *OurPortPtr
== 0) {
744 *OurPortPtr
= PXE_RND_PORT_LOW
;
748 // send request from our Ip = StationIp
750 if ((Status
= TftpRwReq (
763 "\nTftpRwReqwResp() Exit #1 %xh (%r)",
771 // read reply to our Ip = StationIp
773 *ReplyLenPtr
= SaveReplyLen
;
775 Status
= TftpUdpRead (
777 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
,
787 } while (Status
== EFI_TIMEOUT
&& --Retries
);
789 if (!Options
|| Status
!= EFI_TFTP_ERROR
) {
792 "\nTftpRwReqwResp() Exit #2 %xh (%r)",
799 Status
= TftpRwReqwResp (
815 DEBUG ((EFI_D_WARN
, "\nTftpRwReqwResp() Exit #3 %xh (%r)", Status
, Status
));
820 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
824 // read on mcast ip, cport, from sport, for data packet
825 // returns success if gets multicast last packet or all up to last block
826 // if not missing, then finished
831 PXE_BASECODE_DEVICE
*Private
,
832 UINT64
*BufferSizePtr
,
834 EFI_IP_ADDRESS
*ServerIpPtr
,
835 EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
,
836 UINT64
*StartBlockPtr
,
839 UINT16 ListenTimeout
,
841 IN BOOLEAN DontUseBuffer
845 Listen for MTFTP traffic and save desired packets.
848 Private := Pointer to PxeBc interface
851 ServerIpPtr := Pointer to TFTP server IP address
852 MtftpInfoPtr := Pointer to MTFTP session information
853 StartBlockPtr := IN=first block we are looking for OUT=first block received
854 NumMissedPtr := Number of blocks missed
858 DontUseBuffer := TRUE == throw packets away, just count bytes
864 struct Tftpv4Ack Header
;
875 LastBlockNum
= *StartBlockPtr
;
876 Timeout
= ListenTimeout
;
879 BufferSize
= *BufferSizePtr
;
880 ReplyLen
= MAX_TFTP_PKT_SIZE
;;
886 if ((SaveReplyLen
= ReplyLen
) > BufferSize
) {
887 SaveReplyLen
= (UINTN
) BufferSize
;
890 /* %%TBD - add big block number support */
893 // get data - loop on resends
896 ReplyLen
= SaveReplyLen
;
898 if ((Status
= TftpUdpRead (
905 &MtftpInfoPtr
->SPort
,
906 &MtftpInfoPtr
->MCastIp
,
907 &MtftpInfoPtr
->CPort
,
913 // make sure a data packet
915 if (Header
.OpCode
!= HTONS (TFTP_DATA
)) {
916 return EFI_PROTOCOL_ERROR
;
918 } while ((BlockNum
= NTOHS (Header
.BlockNum
)) == LastBlockNum
);
921 // make sure still going up
923 if (LastBlockNum
> BlockNum
) {
924 return EFI_PROTOCOL_ERROR
;
927 if (BlockNum
- LastBlockNum
> 0xFFFFFFFF) {
928 return EFI_PROTOCOL_ERROR
;
930 NumMissed
= (UINTN
) (BlockNum
- LastBlockNum
- 1);
933 LastBlockNum
= BlockNum
;
936 // if first time through, some reinitialization
939 *StartBlockPtr
= BlockNum
;
940 PacketSize
= ReplyLen
;
941 Timeout
= TransTimeout
;
943 *NumMissedPtr
= (UINT16
) (*NumMissedPtr
+ NumMissed
);
946 // if missed packets, update start block,
947 // etc. and move packet to proper place in buffer
950 *StartBlockPtr
= BlockNum
;
951 if (!DontUseBuffer
) {
952 Offset
= NumMissed
* PacketSize
;
953 CopyMem (BufferPtr
+ Offset
, BufferPtr
, ReplyLen
);
955 BufferSize
-= Offset
;
959 if (!DontUseBuffer
) {
960 BufferPtr
+= ReplyLen
;
961 BufferSize
-= ReplyLen
;
963 } while (ReplyLen
== PacketSize
&& BlockNum
!= FinalBlock
);
965 *BufferSizePtr
= BufferSize
;
970 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
974 PXE_BASECODE_DEVICE
* Private
,
975 UINT64
*BufferSizePtr
,
977 UINTN
*PacketSizePtr
,
978 EFI_IP_ADDRESS
* ServerIpPtr
,
980 EFI_PXE_BASE_CODE_MTFTP_INFO
* MtftpInfoPtr
,
981 UINT8
*CompletionStatusPtr
,
984 IN BOOLEAN DontUseBuffer
991 Private := Pointer to PxeBc interface
992 BufferSizePtr := IN=buffer size OUT=transfer size
998 CompletionStatusPtr :=
1002 // mtftp open session
1003 // return code EFI_SUCCESS
1004 // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
1005 // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
1006 // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
1007 // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
1011 EFI_IP_ADDRESS OurReplyIp
;
1012 struct Tftpv4Ack Header
;
1018 Retries
= NUM_MTFTP_OPEN_RETRIES
;
1019 BufferPtr2
= BufferPtr
;
1020 *PacketSizePtr
= (UINTN
) (EFI_MIN (*BufferSizePtr
, MAX_TFTP_PKT_SIZE
));
1024 // send a read request
1026 *CompletionStatusPtr
= 0;
1028 if ((Status
= TftpRwReq (
1033 &MtftpInfoPtr
->SPort
,
1034 &MtftpInfoPtr
->CPort
,
1038 )) != EFI_SUCCESS
) {
1046 ZeroMem (&OurReplyIp
, Private
->IpLength
);
1047 ReplyLen
= *PacketSizePtr
;
1049 if ((Status
= TftpUdpRead (
1051 EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
,
1053 (UINTN
*) &ReplyLen
,
1056 &MtftpInfoPtr
->SPort
,
1058 &MtftpInfoPtr
->CPort
,
1059 MtftpInfoPtr
->TransmitTimeout
1060 )) == EFI_SUCCESS
) {
1062 // check for first data packet
1064 if (Header
.OpCode
!= HTONS (TFTP_DATA
)) {
1065 return EFI_PROTOCOL_ERROR
;
1070 if (Header
.BlockNum
!= HTONS (1)) {
1073 // if we are not the primary client,
1074 // we probably got first and now second
1075 // multicast but no unicast, so
1076 // *CompletionStatusPtr = GOTMULTI - if this is
1077 // the second, can just go on to listen
1078 // starting with 2 as the last block
1081 if (Header
.BlockNum
!= HTONS (2)) {
1085 *CompletionStatusPtr
= 0;
1094 *PacketSizePtr
= ReplyLen
;
1096 // see if a unicast data packet
1100 &Private
->EfiBc
.Mode
->StationIp
,
1103 *CompletionStatusPtr
|= GOTUNI
;
1106 // if already got multicast packet,
1109 if (*CompletionStatusPtr
& GOTMULTI
) {
1112 } else if (!CompareMem (
1114 &MtftpInfoPtr
->MCastIp
,
1118 // otherwise see if a multicast data packet
1120 *CompletionStatusPtr
|= GOTMULTI
;
1123 // got first - bump pointer so that if
1124 // second multi comes along, we're OK
1126 if (!DontUseBuffer
) {
1127 BufferPtr2
= (UINT8
*) BufferPtr
+ ReplyLen
;
1130 // if already got unicast packet,
1133 if (*CompletionStatusPtr
& GOTUNI
) {
1138 // else protocol error
1140 return EFI_PROTOCOL_ERROR
;
1142 } else if (Status
== EFI_TIMEOUT
) {
1144 // bad return code - if timed out, retry
1149 // else just bad - failed MTFTP open
1154 } while (Status
== EFI_TIMEOUT
&& --Retries
);
1156 if (Status
!= EFI_SUCCESS
) {
1163 // got em both - go into receive mode
1164 // routine to read rest of file after a successful open (TFTP or MTFTP)
1165 // sends ACK and gets next data packet until short packet arrives,
1166 // then sends ACK and (hopefully) times out
1168 return LockStepReceive (
1175 &MtftpInfoPtr
->SPort
,
1176 &MtftpInfoPtr
->MCastIp
,
1177 &MtftpInfoPtr
->CPort
,
1179 MtftpInfoPtr
->TransmitTimeout
,
1184 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1187 PXE_BASECODE_DEVICE
*Private
,
1188 UINT64
*BufferSizePtr
,
1190 EFI_IP_ADDRESS
*ServerIpPtr
,
1192 EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
,
1193 IN BOOLEAN DontUseBuffer
1196 Routine description:
1200 // if did not get any packets, try MTFTP open
1201 // if got all packets, return
1202 // compute listen timeout and loop
1205 Private := Pointer to PxeBc interface
1216 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
1220 UINT64 LastStartBlock
;
1224 UINT16 TransTimeout
;
1225 UINT16 ListenTimeout
;
1226 UINT8
*BufferPtrLocal
;
1228 TransTimeout
= MtftpInfoPtr
->TransmitTimeout
;
1229 ListenTimeout
= MtftpInfoPtr
->ListenTimeout
;
1234 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
;
1236 CopyMem (&Filter
.IpList
[0], &Private
->EfiBc
.Mode
->StationIp
, sizeof (EFI_IP_ADDRESS
));
1237 CopyMem (&Filter
.IpList
[1], &MtftpInfoPtr
->MCastIp
, sizeof (EFI_IP_ADDRESS
));
1239 if ((Status
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
1244 StartBlock
= LastStartBlock
;
1245 BufferSize
= *BufferSizePtr
- Offset
;
1247 if (DontUseBuffer
) {
1249 // overwrie the temp buf
1251 BufferPtrLocal
= BufferPtr
;
1253 BufferPtrLocal
= BufferPtr
+ Offset
;
1257 // special !!! do not leave enabled in saved version on Source Safe
1258 // Following code put in in order to create a special version for regression
1259 // test of MTFTP server to make sure it handles mulitple opens correctly.
1260 // This code should NOT be enabled normally.
1262 #ifdef SpecialNowaitVersion
1263 #pragma message ("This is special version for MTFTP regression test")
1264 if (StartBlock
|| !LastBlock
)
1266 if (((Status
= MtftpListen (
1278 )) != EFI_SUCCESS
) && (Status
!= EFI_TIMEOUT
)) {
1285 // if none were received, start block is not reset
1287 if (StartBlock
== LastStartBlock
) {
1291 // timed out with none received - try MTFTP open
1293 if ((Status
= MtftpOpen (
1303 )) != EFI_SUCCESS
) {
1305 // open failure - try TFTP
1310 // return code EFI_SUCCESS
1311 // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
1312 // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
1313 // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
1314 // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
1316 if (CompStat
== (GOTUNI
| GOTMULTI
)) {
1318 // finished - got it all
1325 // offset is two packet lengths
1329 // last block received
1337 ListenTimeout
= TransTimeout
;
1341 // did we get the last block
1343 if (Status
== EFI_SUCCESS
) {
1345 // yes - set the file size if this was first time
1348 *BufferSizePtr
-= BufferSize
;
1351 // if buffer was too small, finished
1353 if (!DontUseBuffer
) {
1354 return EFI_BUFFER_TOO_SMALL
;
1357 // if we got them all, finished
1359 if (!NumMissed
&& StartBlock
== LastStartBlock
+ 1) {
1363 // did not get them all - set last block
1365 LastBlock
= (UINT16
) (StartBlock
- 1);
1368 // compute listen timeout
1370 ListenTimeout
= (UINT16
) ((NumMissed
> MtftpInfoPtr
->ListenTimeout
) ? 0 : (MtftpInfoPtr
->ListenTimeout
- NumMissed
));
1380 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1384 PXE_BASECODE_DEVICE
*Private
,
1385 UINT64
*BufferSizePtr
,
1386 EFI_IP_ADDRESS
*ServerIpPtr
,
1387 EFI_PXE_BASE_CODE_UDP_PORT SrvPort
,
1389 UINTN
*PacketSizePtr
1392 Routine description:
1393 // TFTP info request routine
1394 // send read request with block size and transfer size options
1396 // send error to terminate session
1397 // if OACK received, set info
1410 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1411 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1419 struct Tftpv4Oack OAck2Ptr
;
1420 struct Tftpv4Ack Ack2Ptr
;
1421 struct Tftpv4Data Datastr
;
1425 ServerReplyPort
= 0;
1426 ReplyLen
= sizeof (u
.Datastr
.Data
);
1429 // send a write request with the blocksize option -
1430 // sets our IP and port - and receive reply - sets his port
1431 // will retry operation up to 3 times if no response,
1432 // and will retry without options on an error reply
1434 if ((Status
= TftpRwReqwResp (
1436 /* BIGBLKNUMOP | */BKSZOP
| TSIZEOP
,
1448 )) != EFI_SUCCESS
) {
1449 DEBUG ((EFI_D_WARN
, "\nTftpInfo() Exit #1"));
1453 // check for good OACK
1455 if (u
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1457 // now parse it for options
1462 sizeof (BigBlkNumOp
),
1463 u
.OAck2Ptr
.OpAck
[0].Option
,
1464 ReplyLen
+ sizeof (u
.Ack2Ptr
.BlockNum
)
1468 if (AtoU (Ptr
) == 8) {
1469 Private
->BigBlkNumFlag
= TRUE
;
1471 return EFI_PROTOCOL_ERROR
;
1479 sizeof (BlockSizeOp
),
1480 u
.OAck2Ptr
.OpAck
[0].Option
,
1481 ReplyLen
+= sizeof (u
.Ack2Ptr
.BlockNum
)
1484 *PacketSizePtr
= (Ptr
) ? AtoU (Ptr
) : 512;
1492 u
.OAck2Ptr
.OpAck
[0].Option
,
1497 *BufferSizePtr
= AtoU64 (Ptr
);
1500 // teminate session with error
1502 SendError (Private
, ServerIpPtr
, &ServerReplyPort
, &OurPort
);
1511 // if MTFTP get filesize, return unsupported
1513 if (SrvPort
!= TftpRequestPort
) {
1514 SendError (Private
, ServerIpPtr
, &ServerReplyPort
, &OurPort
);
1515 DEBUG ((EFI_D_WARN
, "\nTftpInfo() Exit #3"));
1516 return EFI_UNSUPPORTED
;
1521 // last block received
1526 // does not support the option - do a download with no buffer
1530 Status
= LockStepReceive (
1538 &Private
->EfiBc
.Mode
->StationIp
,
1545 if (Status
!= EFI_SUCCESS
) {
1546 DEBUG ((EFI_D_WARN
, "\nTftpInfo() LockStepReceive() == %Xh", Status
));
1549 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1556 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1560 PXE_BASECODE_DEVICE
*Private
,
1561 UINT64
*BufferSizePtr
,
1563 EFI_IP_ADDRESS
*ServerIpPtr
,
1565 UINTN
*PacketSizePtr
,
1566 EFI_PXE_BASE_CODE_UDP_PORT SrvPort
,
1568 IN BOOLEAN DontUseBuffer
1571 Routine description:
1572 // tftp read session
1573 // send read request
1579 // while data size is max
1595 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1596 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1604 struct Tftpv4Ack Ack2Ptr
;
1605 struct Tftpv4Oack OAck2Ptr
;
1606 struct Tftpv4Data Data
;
1607 struct Tftpv4Ack8 Ack8Ptr
;
1608 struct Tftpv4Data8 Data8
;
1612 ServerReplyPort
= 0;
1613 ReplyLen
= (UINTN
) ((*BufferSizePtr
> 0xFFFF) ? 0xFFFF : *BufferSizePtr
);
1616 // send a read request with the blocksize option - sets our IP and port
1617 // - and receive reply - sets his port will retry operation up to 3
1618 // times if no response, and will retry without options on an error
1621 if ((Status
= TftpRwReqwResp (
1623 /* BIGBLKNUMOP | */BKSZOP
,
1635 )) != EFI_SUCCESS
) {
1636 DEBUG ((EFI_D_WARN
, "\nTftpDownload() Exit #1 %xh (%r)", Status
, Status
));
1642 if (U
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1646 CopyMem (U
.Data
.Data
, BufferPtr
, ReplyLen
);
1650 sizeof (BigBlkNumOp
),
1651 U
.OAck2Ptr
.OpAck
[0].Option
,
1652 ReplyLen
+ sizeof (U
.Ack2Ptr
.BlockNum
)
1656 if (AtoU (Ptr
) == 8) {
1657 Private
->BigBlkNumFlag
= TRUE
;
1659 return EFI_PROTOCOL_ERROR
;
1663 // now parse it for blocksize option
1667 sizeof (BlockSizeOp
),
1668 U
.OAck2Ptr
.OpAck
[0].Option
,
1669 ReplyLen
+= sizeof (U
.Ack2Ptr
.BlockNum
)
1672 ReplyLen
= (Ptr
!= NULL
) ? AtoU (Ptr
) : 512;
1676 // last block received
1679 } else if (U
.Ack2Ptr
.OpCode
!= HTONS (TFTP_DATA
) || U
.Ack2Ptr
.BlockNum
!= HTONS (1)) {
1683 DEBUG ((EFI_D_WARN
, "\nTftpDownload() Exit #2 %xh (%r)", Status
, Status
));
1685 return EFI_PROTOCOL_ERROR
;
1688 // got good data packet
1692 // last block received
1697 if (PacketSizePtr
!= NULL
) {
1698 *PacketSizePtr
= ReplyLen
;
1701 // routine to read rest of file after a successful open (TFTP or MTFTP)
1702 // sends ACK and gets next data packet until short packet arrives, then sends
1703 // ACK and (hopefully) times out
1704 // if first packet has been read, BufferPtr and BufferSize must reflect fact
1706 Status
= LockStepReceive (
1714 &Private
->EfiBc
.Mode
->StationIp
,
1721 if (Status
!= EFI_SUCCESS
) {
1722 DEBUG ((EFI_D_WARN
, "\nTftpDownload() Exit #3 %xh (%r)", Status
, Status
));
1724 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1734 if (!EFI_ERROR (Status
)) {
1735 Status
= EFI_BUFFER_TOO_SMALL
;
1743 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1747 PXE_BASECODE_DEVICE
*Private
,
1748 UINT64
*BufferSizePtr
,
1750 EFI_IP_ADDRESS
*ServerIpPtr
,
1752 UINTN
*PacketSizePtr
,
1756 Routine description:
1757 // tftp write session
1758 // send write request
1761 // send min (rest of data, max data packet)
1763 // while data size is max
1777 struct Tftpv4Ack Header
;
1778 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1779 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1782 UINT64 TransferSize
;
1789 struct Tftpv4Oack OAck2Ptr
;
1790 struct Tftpv4Ack Ack2Ptr
;
1791 struct Tftpv4Data Datastr
;
1795 ServerReplyPort
= 0;
1796 TransferSize
= *BufferSizePtr
;
1797 ReplyLen
= sizeof (u
.Datastr
.Data
);
1798 Options
= (UINT16
) ((Overwrite
) ? OVERWRITEOP
| BKSZOP
: BKSZOP
);
1801 // send a write request with the blocksize option - sets our IP and port -
1802 // and receive reply - sets his port
1803 // will retry operation up to 3 times if no response, and will retry without
1804 // options on an error reply
1806 if ((Status
= TftpRwReqwResp (
1820 )) != EFI_SUCCESS
) {
1826 if (u
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1828 // parse it for blocksize option
1832 sizeof (BlockSizeOp
),
1833 u
.OAck2Ptr
.OpAck
[0].Option
,
1834 ReplyLen
+= sizeof (u
.Ack2Ptr
.BlockNum
)
1836 *PacketSizePtr
= (Ptr
) ? AtoU (Ptr
) : 512;
1841 else if (u
.Ack2Ptr
.OpCode
== HTONS (TFTP_ACK
)) {
1843 // option was not supported
1845 *PacketSizePtr
= 512;
1847 return EFI_PROTOCOL_ERROR
;
1852 Header
.OpCode
= HTONS (TFTP_DATA
);
1854 Header
.BlockNum
= HTONS (1);
1860 Retries
= NUM_ACK_RETRIES
;
1861 HeaderSize
= sizeof (Header
);
1862 TransferLen
= (UINTN
) (EFI_MIN (*PacketSizePtr
, TransferSize
));
1865 // write a data packet and get an ack
1871 if ((Status
= UdpWrite (
1873 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
1883 )) != EFI_SUCCESS
) {
1889 ReplyLen
= sizeof (u
.Datastr
.Data
);
1891 if ((Status
= TftpUdpRead (
1902 )) == EFI_SUCCESS
) {
1904 // check for ACK for this data packet
1906 if (u
.Ack2Ptr
.OpCode
!= HTONS (TFTP_ACK
)) {
1907 return EFI_PROTOCOL_ERROR
;
1910 if (u
.Ack2Ptr
.BlockNum
!= Header
.BlockNum
) {
1912 // not for this packet - continue
1914 Status
= EFI_TIMEOUT
;
1917 } while (Status
== EFI_TIMEOUT
&& --Retries
);
1919 if (Status
!= EFI_SUCCESS
) {
1923 BufferPtr
= (VOID
*) ((UINT8
*) (BufferPtr
) + TransferLen
);
1924 TransferSize
-= TransferLen
;
1926 Header
.BlockNum
= HTONS ((UINT16
) BlockNum
);
1927 } while (TransferLen
== *PacketSizePtr
);
1932 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1935 PXE_BASECODE_DEVICE
*Private
,
1936 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation
,
1937 UINT64
*BufferSizePtr
,
1939 EFI_IP_ADDRESS
*ServerIpPtr
,
1941 UINTN
*PacketSizePtr
,
1942 IN EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
, OPTIONAL
1943 IN BOOLEAN Overwrite
,
1944 IN BOOLEAN DontUseBuffer
1947 Routine description:
1948 MTFTP API entry point
1963 * EFI_INVALID_PARAMETER
1964 * EFI_OUT_OF_RESOURCES
1965 * EFI_BAD_BUFFER_SIZE
1966 * Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(),
1967 * TftpDownload() and TftpUpload().
1970 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
1971 EFI_STATUS StatCode
;
1973 UINT64 BufferSizeLocal
;
1975 UINT8
*BufferPtrLocal
;
1977 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
;
1979 Filter
.reserved
= 0;
1981 /* No error has occurred, yet. */
1982 Private
->EfiBc
.Mode
->TftpErrorReceived
= FALSE
;
1984 /* We must at least have an MTFTP server IP address and
1985 * a pointer to the buffer size.
1987 if (!ServerIpPtr
|| !BufferSizePtr
) {
1988 DEBUG ((EFI_D_WARN
, "\nPxeBcMtftp() Exit #1"));
1990 return EFI_INVALID_PARAMETER
;
1993 Private
->Function
= EFI_PXE_BASE_CODE_FUNCTION_MTFTP
;
1996 // make sure filter set to unicast at start
1998 if ((StatCode
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
2001 "\nPxeBcMtftp() Exit IpFilter() == %Xh",
2008 // set unset parms to default values
2010 if (!PacketSizePtr
) {
2011 *(PacketSizePtr
= &PacketSize
) = MAX_TFTP_PKT_SIZE
;
2014 if (*PacketSizePtr
> *BufferSizePtr
) {
2015 *PacketSizePtr
= (UINTN
) *BufferSizePtr
;
2018 if (*PacketSizePtr
< MIN_TFTP_PKT_SIZE
) {
2019 *PacketSizePtr
= MIN_TFTP_PKT_SIZE
;
2022 if (*PacketSizePtr
> BUFFER_ALLOCATE_SIZE
) {
2023 *PacketSizePtr
= BUFFER_ALLOCATE_SIZE
;
2026 if (*PacketSizePtr
> MAX_TFTP_PKT_SIZE
) {
2027 *PacketSizePtr
= MAX_TFTP_PKT_SIZE
;
2030 if (Operation
== EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
) {
2031 StatCode
= TftpInfo (
2040 if (StatCode
!= EFI_SUCCESS
) {
2043 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
2051 if (Operation
== EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE
) {
2052 if (!MtftpInfoPtr
|| !MtftpInfoPtr
->SPort
) {
2053 DEBUG ((EFI_D_WARN
, "\nPxeBcMtftp() Exit #2"));
2054 return EFI_INVALID_PARAMETER
;
2056 StatCode
= TftpInfo (
2060 MtftpInfoPtr
->SPort
,
2067 if (StatCode
!= EFI_SUCCESS
) {
2070 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
2079 if (!BufferPtr
&& !DontUseBuffer
) {
2081 // if dontusebuffer is false and no buffer???
2083 DEBUG ((EFI_D_WARN
, "\nPxeBcMtftp() Exit #3"));
2085 // DontUseBuffer can be true only for read_file operation
2087 return EFI_INVALID_PARAMETER
;
2090 if (DontUseBuffer
) {
2091 Status
= gBS
->AllocatePool (
2092 EfiBootServicesData
,
2093 BUFFER_ALLOCATE_SIZE
,
2094 (VOID
**) &BufferPtrLocal
2097 if (EFI_ERROR (Status
) || BufferPtrLocal
== NULL
) {
2098 DEBUG ((EFI_D_NET
, "\nPxeBcMtftp() Exit #4"));
2099 return EFI_OUT_OF_RESOURCES
;
2102 BufferSizeLocal
= BUFFER_ALLOCATE_SIZE
;
2104 if (!*BufferSizePtr
&& Operation
!= EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
) {
2105 DEBUG ((EFI_D_WARN
, "\nPxeBcMtftp() Exit #5"));
2106 return EFI_BAD_BUFFER_SIZE
;
2109 BufferPtrLocal
= BufferPtr
;
2110 BufferSizeLocal
= *BufferSizePtr
;
2113 switch (Operation
) {
2114 case EFI_PXE_BASE_CODE_MTFTP_READ_FILE
:
2115 if (FilenamePtr
== NULL
||
2116 MtftpInfoPtr
== NULL
||
2117 MtftpInfoPtr
->MCastIp
.Addr
[0] == 0 ||
2118 MtftpInfoPtr
->SPort
== 0 ||
2119 MtftpInfoPtr
->CPort
== 0 ||
2120 MtftpInfoPtr
->ListenTimeout
== 0 ||
2121 MtftpInfoPtr
->TransmitTimeout
== 0
2123 StatCode
= EFI_INVALID_PARAMETER
;
2127 // try MTFTP - if fails, drop into TFTP read
2129 if ((StatCode
= MtftpDownload (
2137 )) == EFI_SUCCESS
|| StatCode
== EFI_BUFFER_TOO_SMALL
) {
2138 if (BufferSizePtr
/* %% !DontUseBuffer */ ) {
2139 *BufferSizePtr
= BufferSizeLocal
;
2145 // go back to unicast
2147 if ((StatCode
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
2152 case EFI_PXE_BASE_CODE_TFTP_READ_FILE
:
2153 if (FilenamePtr
== NULL
) {
2154 StatCode
= EFI_INVALID_PARAMETER
;
2158 StatCode
= TftpDownload (
2170 if (StatCode
== EFI_SUCCESS
|| StatCode
== EFI_BUFFER_TOO_SMALL
) {
2171 if (BufferSizePtr
/* !DontUseBuffer */ ) {
2172 *BufferSizePtr
= BufferSizeLocal
;
2178 case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
:
2179 if (FilenamePtr
== NULL
|| DontUseBuffer
) {
2181 // not a valid option
2183 StatCode
= EFI_INVALID_PARAMETER
;
2187 StatCode
= TftpUpload (
2197 if (StatCode
!= EFI_SUCCESS
) {
2200 "\nPxeBcMtftp() Exit #6 %xh (%r)",
2208 case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY
:
2209 if (FilenamePtr
== NULL
|| DontUseBuffer
) {
2211 // not a valid option
2213 StatCode
= EFI_INVALID_PARAMETER
;
2217 StatCode
= TftpDownload (
2229 if (StatCode
!= EFI_SUCCESS
) {
2232 "\nPxeBcMtftp() Exit #7 %xh (%r)",
2240 case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY
:
2241 if (DontUseBuffer
) {
2242 StatCode
= EFI_INVALID_PARAMETER
;
2246 if (MtftpInfoPtr
== NULL
|| !MtftpInfoPtr
->SPort
) {
2249 "\nPxeBcMtftp() Exit #9 %xh (%r)",
2250 EFI_INVALID_PARAMETER
,
2251 EFI_INVALID_PARAMETER
)
2254 return EFI_INVALID_PARAMETER
;
2257 StatCode
= TftpDownload (
2264 MtftpInfoPtr
->SPort
,
2272 StatCode
= EFI_INVALID_PARAMETER
;
2275 if (DontUseBuffer
) {
2276 gBS
->FreePool (BufferPtrLocal
);
2279 if (StatCode
!= EFI_SUCCESS
) {
2282 "\nPxeBcMtftp() Exit #8 %xh (%r)",
2293 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2297 IN EFI_PXE_BASE_CODE_PROTOCOL
* This
,
2298 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation
,
2299 IN OUT VOID
*BufferPtr
,
2300 IN BOOLEAN Overwrite
,
2301 IN OUT UINT64
*BufferSizePtr
,
2302 IN UINTN
*BlockSizePtr OPTIONAL
,
2303 IN EFI_IP_ADDRESS
* ServerIpPtr
,
2304 IN UINT8
*FilenamePtr
,
2305 IN EFI_PXE_BASE_CODE_MTFTP_INFO
* MtftpInfoPtr OPTIONAL
,
2306 IN BOOLEAN DontUseBuffer
2309 Routine description:
2310 MTFTP API entry point.
2325 * EFI_INVALID_PARAMETER
2326 * Status is also returned from PxeBcMtftp();
2329 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
2330 EFI_STATUS StatCode
;
2331 PXE_BASECODE_DEVICE
*Private
;
2334 // Lock the instance data and make sure started
2336 StatCode
= EFI_SUCCESS
;
2339 DEBUG ((EFI_D_ERROR
, "BC *This pointer == NULL"));
2340 return EFI_INVALID_PARAMETER
;
2343 Private
= CR (This
, PXE_BASECODE_DEVICE
, EfiBc
, PXE_BASECODE_DEVICE_SIGNATURE
);
2345 if (Private
== NULL
) {
2346 DEBUG ((EFI_D_ERROR
, "PXE_BASECODE_DEVICE poiner == NULL"));
2347 return EFI_INVALID_PARAMETER
;
2350 EfiAcquireLock (&Private
->Lock
);
2352 if (This
->Mode
== NULL
|| !This
->Mode
->Started
) {
2353 DEBUG ((EFI_D_ERROR
, "BC was not started."));
2354 EfiReleaseLock (&Private
->Lock
);
2355 return EFI_NOT_STARTED
;
2360 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
;
2362 Filter
.reserved
= 0;
2364 DEBUG ((EFI_D_WARN
, "\nBcMtftp() Op=%d Buf=%Xh", Operation
, BufferPtr
));
2366 StatCode
= PxeBcMtftp (
2380 // restore to unicast
2382 IpFilter (Private
, &Filter
);
2385 // Unlock the instance data
2387 EfiReleaseLock (&Private
->Lock
);
2391 /* eof - PxeBcMtftp.c */