3 Copyright (c) 2004 - 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
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.
24 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
27 // The following #define is used to create a version that does not wait to
28 // open after a listen. This is just for a special regression test of MTFTP
29 // server to make sure multiple opens are handled correctly. Normally this
30 // next line should be a comment.
31 // #define SpecialNowaitVersion // comment out for normal operation
34 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
37 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
71 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
75 @return EFI_SUCCESS :=
76 @return EFI_TFTP_ERROR :=
82 PXE_BASECODE_DEVICE
*Private
,
87 EFI_IP_ADDRESS
*ServerIpPtr
,
88 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
89 EFI_IP_ADDRESS
*OurIpPtr
,
90 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
94 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
96 EFI_EVENT TimeoutEvent
;
102 Status
= gBS
->CreateEvent (
110 if (EFI_ERROR (Status
)) {
114 Status
= gBS
->SetTimer (
117 Timeout
* 10000000 + 1000000
120 if (EFI_ERROR (Status
)) {
121 gBS
->CloseEvent (TimeoutEvent
);
127 HeaderSize
= Private
->BigBlkNumFlag
? sizeof (struct Tftpv4Ack8
) : sizeof (struct Tftpv4Ack
);
129 #define ERROR_MESSAGE_PTR ((struct Tftpv4Error *) HeaderPtr)
145 if (Status
!= EFI_SUCCESS
|| ERROR_MESSAGE_PTR
->OpCode
!= HTONS (TFTP_ERROR
)) {
146 gBS
->CloseEvent (TimeoutEvent
);
150 // got an error packet
151 // write one byte error code followed by error message
153 PxeBcMode
= Private
->EfiBc
.Mode
;
154 PxeBcMode
->TftpErrorReceived
= TRUE
;
155 PxeBcMode
->TftpError
.ErrorCode
= (UINT8
) NTOHS (ERROR_MESSAGE_PTR
->ErrCode
);
156 HeaderSize
= MIN (*BufferSizePtr
, sizeof PxeBcMode
->TftpError
.ErrorString
);
157 CopyMem (PxeBcMode
->TftpError
.ErrorString
, BufferPtr
, HeaderSize
);
159 gBS
->CloseEvent (TimeoutEvent
);
160 return EFI_TFTP_ERROR
;
163 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
171 PXE_BASECODE_DEVICE
*Private
,
172 EFI_IP_ADDRESS
*ServerIpPtr
,
173 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
174 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
177 struct Tftpv4Error
*ErrStr
;
180 ErrStr
= (VOID
*) Private
->TftpErrorBuffer
;
181 Len
= sizeof *ErrStr
;
183 ErrStr
->OpCode
= HTONS (TFTP_ERROR
);
184 ErrStr
->ErrCode
= HTONS (TFTP_ERR_OPTION
);
185 ErrStr
->ErrMsg
[0] = 0;
189 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
202 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
210 PXE_BASECODE_DEVICE
*Private
,
211 EFI_IP_ADDRESS
*ServerIpPtr
,
212 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
213 EFI_IP_ADDRESS
*ReplyIpPtr
,
214 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
222 struct Tftpv4Data DataBuffer
;
223 struct Tftpv4Ack
*Ack2Ptr
;
224 struct Tftpv4Ack8
*Ack8Ptr
;
228 Ack2Ptr
= (VOID
*) Private
->TftpAckBuffer
;
229 Ack8Ptr
= (VOID
*) Private
->TftpAckBuffer
;
231 if (Private
->BigBlkNumFlag
) {
232 Len
= sizeof (struct Tftpv4Ack8
);
234 Ack8Ptr
->OpCode
= HTONS (TFTP_ACK8
);
235 Ack8Ptr
->BlockNum
= Swap64 (*BlockNumPtr
);
239 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
251 if (EFI_ERROR (Status
)) {
255 Len
= sizeof (struct Tftpv4Ack
);
257 Ack2Ptr
->OpCode
= HTONS (TFTP_ACK
);
258 Ack2Ptr
->BlockNum
= HTONS ((UINT16
) *BlockNumPtr
);
262 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
274 if (EFI_ERROR (Status
)) {
281 // ACK of last packet. This is just a courtesy.
282 // Do not wait for response.
289 Status
= TftpUdpRead (
302 if (EFI_ERROR (Status
) && Status
!= EFI_BUFFER_TOO_SMALL
) {
306 // got a good reply (so far)
307 // check for next data packet
309 if (!Private
->BigBlkNumFlag
&& DataBuffer
.Header
.OpCode
== HTONS (TFTP_DATA
)) {
310 if (Status
== EFI_BUFFER_TOO_SMALL
) {
311 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
314 *BlockNumPtr
= NTOHS (DataBuffer
.Header
.BlockNum
);
318 if (Private
->BigBlkNumFlag
&& DataBuffer
.Header
.OpCode
== HTONS (TFTP_DATA8
)) {
319 if (Status
== EFI_BUFFER_TOO_SMALL
) {
320 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
323 *BlockNumPtr
= Swap64 (*(UINT64
*) &DataBuffer
.Header
.BlockNum
);
327 return EFI_PROTOCOL_ERROR
;
330 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
338 PXE_BASECODE_DEVICE
*Private
,
340 UINT64
*BufferSizePtr
,
343 EFI_IP_ADDRESS
*ServerIpPtr
,
344 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
345 EFI_IP_ADDRESS
*ReplyIpPtr
,
346 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
349 IN BOOLEAN DontUseBuffer
359 ReplyLen
= PacketSize
;
360 BlockNum
= LastBlock
;
362 DEBUG ((DEBUG_INFO
, "\nLockStepReceive() PacketSize = %d", PacketSize
));
365 BufferSize
= PacketSize
;
367 BufferSize
= *BufferSizePtr
- Offset
;
371 while (ReplyLen
>= 512 && ReplyLen
== PacketSize
) {
372 if (BufferSize
< PacketSize
) {
373 ReplyLen
= (UINTN
) ((BufferSize
> 0) ? BufferSize
: 0);
379 // write an ack packet and get data - retry up to NUM_ACK_RETRIES on timeout
381 Retries
= NUM_ACK_RETRIES
;
386 Status
= SendAckAndGetData (
399 if (!EFI_ERROR (Status
) || Status
== EFI_BUFFER_TOO_SMALL
) {
400 if (BlockNum
== LastBlock
) {
401 DEBUG ((DEBUG_NET
, "\nresend"));
403 // a resend - continue
405 Status
= EFI_TIMEOUT
;
406 } else if (Private
->BigBlkNumFlag
) {
407 if (BlockNum
!= ++LastBlock
) {
408 DEBUG ((DEBUG_NET
, "\nLockStepReceive() Exit #1a"));
410 // not correct blocknum - error
412 return EFI_PROTOCOL_ERROR
;
415 LastBlock
= (LastBlock
+ 1) & 0xFFFF;
416 if (BlockNum
!= LastBlock
) {
417 DEBUG ((DEBUG_NET
, "\nLockStepReceive() Exit #1b"));
418 return EFI_PROTOCOL_ERROR
;
420 // not correct blocknum - error
425 } while (Status
== EFI_TIMEOUT
&& --Retries
);
427 if (EFI_ERROR (Status
)) {
428 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
429 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
436 BufferSize
+= ReplyLen
;
438 BufferPtr
+= ReplyLen
;
439 BufferSize
-= ReplyLen
;
443 // while (ReplyLen == PacketSize);
446 if (BufferSizePtr
!= NULL
) {
447 *BufferSizePtr
= (BufferSize
- PacketSize
);
450 *BufferSizePtr
-= BufferSize
;
453 /* Send ACK of last packet. */
472 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
477 UINT8 Mode
[] = MODE_BINARY
;
478 UINT8 BlockSizeOp
[] = OP_BLKSIZE
;
479 UINT8 TsizeOp
[] = OP_TFRSIZE
;
480 UINT8 OverwriteOp
[] = OP_OVERWRITE
;
481 UINT8 BigBlkNumOp
[] = OP_BIGBLKNUM
;
482 EFI_PXE_BASE_CODE_UDP_PORT TftpRequestPort
= TFTP_OPEN_PORT
;
484 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
488 @return Pointer to value field if option found or NULL if not found.
499 if ((OackSize
-= OpLen
) <= 0) {
504 if (!CompareMem (OackPtr
, OptionPtr
, OpLen
)) {
505 return OackPtr
+ OpLen
;
509 } while (--OackSize
);
514 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
515 #define BKSZOP 1 // block size
516 #define TSIZEOP 2 // transfer size
517 #define OVERWRITEOP 4 // overwrite
518 #define BIGBLKNUMOP 8 // big block numbers
523 PXE_BASECODE_DEVICE
*Private
,
524 EFI_IP_ADDRESS
*ServerIpPtr
,
525 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
526 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
528 UINTN
*PacketSizePtr
,
534 struct Tftpv4Req ReqStr
;
542 if (*OurPortPtr
== 0) {
543 OpFlags
= EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
| EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
;
545 OpFlags
= EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
;
548 // build the basic request - opcode, filename, mode
551 u
->ReqStr
.OpCode
= HTONS (Req
);
552 TotalLen
= sizeof (Mode
) + sizeof (u
->ReqStr
.OpCode
) + (Len
= 1 + AsciiStrLen ((CHAR8
*) FilenamePtr
));
554 CopyMem (u
->ReqStr
.FileName
, FilenamePtr
, Len
);
555 Ptr
= (UINT8
*) (u
->ReqStr
.FileName
+ Len
);
557 CopyMem (Ptr
, Mode
, sizeof (Mode
));
558 Ptr
+= sizeof (Mode
);
560 if (Options
& BKSZOP
) {
561 CopyMem (Ptr
, BlockSizeOp
, sizeof (BlockSizeOp
));
562 UtoA10 (*PacketSizePtr
, Ptr
+ sizeof (BlockSizeOp
));
564 TotalLen
+= (Len
= 1 + AsciiStrLen ((CHAR8
*) (Ptr
+ sizeof (BlockSizeOp
))) + sizeof (BlockSizeOp
));
569 if (Options
& TSIZEOP
) {
570 CopyMem (Ptr
, TsizeOp
, sizeof (TsizeOp
));
571 CopyMem (Ptr
+ sizeof (TsizeOp
), "0", 2);
572 TotalLen
+= sizeof (TsizeOp
) + 2;
573 Ptr
+= sizeof (TsizeOp
) + 2;
576 if (Options
& OVERWRITEOP
) {
577 CopyMem (Ptr
, OverwriteOp
, sizeof (OverwriteOp
));
578 CopyMem (Ptr
+ sizeof (OverwriteOp
), "1", 2);
579 TotalLen
+= sizeof (OverwriteOp
) + 2;
580 Ptr
+= sizeof (OverwriteOp
) + 2;
583 if (Options
& BIGBLKNUMOP
) {
584 CopyMem (Ptr
, BigBlkNumOp
, sizeof (BigBlkNumOp
));
585 CopyMem (Ptr
+ sizeof (BigBlkNumOp
), "8", 2);
586 TotalLen
+= sizeof (BigBlkNumOp
) + 2;
587 Ptr
+= sizeof (BigBlkNumOp
) + 2;
607 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
617 PXE_BASECODE_DEVICE
*Private
,
619 UINTN
*PacketSizePtr
,
622 EFI_IP_ADDRESS
*ServerIpPtr
,
623 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
624 EFI_PXE_BASE_CODE_UDP_PORT
*ServerReplyPortPtr
,
625 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
635 SaveReplyLen
= *ReplyLenPtr
;
637 Private
->BigBlkNumFlag
= FALSE
;
643 if (*OurPortPtr
!= 0) {
644 if (++ *OurPortPtr
== 0) {
645 *OurPortPtr
= PXE_RND_PORT_LOW
;
649 // send request from our Ip = StationIp
651 if ((Status
= TftpRwReq (
664 "\nTftpRwReqwResp() Exit #1 %xh (%r)",
672 // read reply to our Ip = StationIp
674 *ReplyLenPtr
= SaveReplyLen
;
676 Status
= TftpUdpRead (
678 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
,
688 } while (Status
== EFI_TIMEOUT
&& --Retries
);
690 if (!Options
|| Status
!= EFI_TFTP_ERROR
) {
693 "\nTftpRwReqwResp() Exit #2 %xh (%r)",
700 Status
= TftpRwReqwResp (
716 DEBUG ((DEBUG_WARN
, "\nTftpRwReqwResp() Exit #3 %xh (%r)", Status
, Status
));
721 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
725 // read on mcast ip, cport, from sport, for data packet
726 // returns success if gets multicast last packet or all up to last block
727 // if not missing, then finished
736 PXE_BASECODE_DEVICE
*Private
,
737 UINT64
*BufferSizePtr
,
739 EFI_IP_ADDRESS
*ServerIpPtr
,
740 EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
,
741 UINT64
*StartBlockPtr
,
744 UINT16 ListenTimeout
,
746 IN BOOLEAN DontUseBuffer
750 struct Tftpv4Ack Header
;
761 LastBlockNum
= *StartBlockPtr
;
762 Timeout
= ListenTimeout
;
765 BufferSize
= *BufferSizePtr
;
766 ReplyLen
= MAX_TFTP_PKT_SIZE
;;
772 if ((SaveReplyLen
= ReplyLen
) > BufferSize
) {
776 /* %%TBD - add big block number support */
779 // get data - loop on resends
782 ReplyLen
= SaveReplyLen
;
784 if ((Status
= TftpUdpRead (
791 &MtftpInfoPtr
->SPort
,
792 &MtftpInfoPtr
->MCastIp
,
793 &MtftpInfoPtr
->CPort
,
799 // make sure a data packet
801 if (Header
.OpCode
!= HTONS (TFTP_DATA
)) {
802 return EFI_PROTOCOL_ERROR
;
804 } while ((BlockNum
= NTOHS (Header
.BlockNum
)) == LastBlockNum
);
807 // make sure still going up
809 if (LastBlockNum
> BlockNum
) {
810 return EFI_PROTOCOL_ERROR
;
813 if (BlockNum
- LastBlockNum
> 0xFFFFFFFF) {
814 return EFI_PROTOCOL_ERROR
;
816 NumMissed
= (UINTN
) (BlockNum
- LastBlockNum
- 1);
819 LastBlockNum
= BlockNum
;
822 // if first time through, some reinitialization
825 *StartBlockPtr
= BlockNum
;
826 PacketSize
= ReplyLen
;
827 Timeout
= TransTimeout
;
829 *NumMissedPtr
= (UINT16
) (*NumMissedPtr
+ NumMissed
);
832 // if missed packets, update start block,
833 // etc. and move packet to proper place in buffer
836 *StartBlockPtr
= BlockNum
;
837 if (!DontUseBuffer
) {
838 Offset
= NumMissed
* PacketSize
;
839 CopyMem (BufferPtr
+ Offset
, BufferPtr
, ReplyLen
);
841 BufferSize
-= Offset
;
845 if (!DontUseBuffer
) {
846 BufferPtr
+= ReplyLen
;
847 BufferSize
-= ReplyLen
;
849 } while (ReplyLen
== PacketSize
&& BlockNum
!= FinalBlock
);
851 *BufferSizePtr
= BufferSize
;
856 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
860 @return // mtftp open session
861 @return // return code EFI_SUCCESS
862 @return // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
863 @return // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
864 @return // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
865 @retval GOTUNI returns NO_DATA go will go to TFTP session)
870 PXE_BASECODE_DEVICE
* Private
,
871 UINT64
*BufferSizePtr
,
873 UINTN
*PacketSizePtr
,
874 EFI_IP_ADDRESS
* ServerIpPtr
,
876 EFI_PXE_BASE_CODE_MTFTP_INFO
* MtftpInfoPtr
,
877 UINT8
*CompletionStatusPtr
,
880 IN BOOLEAN DontUseBuffer
884 EFI_IP_ADDRESS OurReplyIp
;
885 struct Tftpv4Ack Header
;
891 Retries
= NUM_MTFTP_OPEN_RETRIES
;
892 BufferPtr2
= BufferPtr
;
893 *PacketSizePtr
= (UINTN
) (MIN (*BufferSizePtr
, MAX_TFTP_PKT_SIZE
));
897 // send a read request
899 *CompletionStatusPtr
= 0;
901 if ((Status
= TftpRwReq (
906 &MtftpInfoPtr
->SPort
,
907 &MtftpInfoPtr
->CPort
,
919 ZeroMem (&OurReplyIp
, Private
->IpLength
);
920 ReplyLen
= *PacketSizePtr
;
922 if ((Status
= TftpUdpRead (
924 EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
,
929 &MtftpInfoPtr
->SPort
,
931 &MtftpInfoPtr
->CPort
,
932 MtftpInfoPtr
->TransmitTimeout
935 // check for first data packet
937 if (Header
.OpCode
!= HTONS (TFTP_DATA
)) {
938 return EFI_PROTOCOL_ERROR
;
943 if (Header
.BlockNum
!= HTONS (1)) {
946 // if we are not the primary client,
947 // we probably got first and now second
948 // multicast but no unicast, so
949 // *CompletionStatusPtr = GOTMULTI - if this is
950 // the second, can just go on to listen
951 // starting with 2 as the last block
954 if (Header
.BlockNum
!= HTONS (2)) {
958 *CompletionStatusPtr
= 0;
967 *PacketSizePtr
= ReplyLen
;
969 // see if a unicast data packet
973 &Private
->EfiBc
.Mode
->StationIp
,
976 *CompletionStatusPtr
|= GOTUNI
;
979 // if already got multicast packet,
982 if (*CompletionStatusPtr
& GOTMULTI
) {
985 } else if (!CompareMem (
987 &MtftpInfoPtr
->MCastIp
,
991 // otherwise see if a multicast data packet
993 *CompletionStatusPtr
|= GOTMULTI
;
996 // got first - bump pointer so that if
997 // second multi comes along, we're OK
999 if (!DontUseBuffer
) {
1000 BufferPtr2
= (UINT8
*) BufferPtr
+ ReplyLen
;
1003 // if already got unicast packet,
1006 if (*CompletionStatusPtr
& GOTUNI
) {
1011 // else protocol error
1013 return EFI_PROTOCOL_ERROR
;
1015 } else if (Status
== EFI_TIMEOUT
) {
1017 // bad return code - if timed out, retry
1022 // else just bad - failed MTFTP open
1027 } while (Status
== EFI_TIMEOUT
&& --Retries
);
1029 if (Status
!= EFI_SUCCESS
) {
1036 // got em both - go into receive mode
1037 // routine to read rest of file after a successful open (TFTP or MTFTP)
1038 // sends ACK and gets next data packet until short packet arrives,
1039 // then sends ACK and (hopefully) times out
1041 return LockStepReceive (
1048 &MtftpInfoPtr
->SPort
,
1049 &MtftpInfoPtr
->MCastIp
,
1050 &MtftpInfoPtr
->CPort
,
1052 MtftpInfoPtr
->TransmitTimeout
,
1057 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1065 PXE_BASECODE_DEVICE
*Private
,
1066 UINT64
*BufferSizePtr
,
1068 EFI_IP_ADDRESS
*ServerIpPtr
,
1070 EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
,
1071 IN BOOLEAN DontUseBuffer
1074 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
1078 UINT64 LastStartBlock
;
1082 UINT16 TransTimeout
;
1083 UINT16 ListenTimeout
;
1084 UINT8
*BufferPtrLocal
;
1086 TransTimeout
= MtftpInfoPtr
->TransmitTimeout
;
1087 ListenTimeout
= MtftpInfoPtr
->ListenTimeout
;
1092 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
;
1094 CopyMem (&Filter
.IpList
[0], &Private
->EfiBc
.Mode
->StationIp
, sizeof (EFI_IP_ADDRESS
));
1095 CopyMem (&Filter
.IpList
[1], &MtftpInfoPtr
->MCastIp
, sizeof (EFI_IP_ADDRESS
));
1097 if ((Status
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
1102 StartBlock
= LastStartBlock
;
1103 BufferSize
= *BufferSizePtr
- Offset
;
1105 if (DontUseBuffer
) {
1107 // overwrie the temp buf
1109 BufferPtrLocal
= BufferPtr
;
1111 BufferPtrLocal
= BufferPtr
+ Offset
;
1115 // special !!! do not leave enabled in saved version on Source Safe
1116 // Following code put in in order to create a special version for regression
1117 // test of MTFTP server to make sure it handles mulitple opens correctly.
1118 // This code should NOT be enabled normally.
1120 if (((Status
= MtftpListen (
1132 )) != EFI_SUCCESS
) && (Status
!= EFI_TIMEOUT
)) {
1139 // if none were received, start block is not reset
1141 if (StartBlock
== LastStartBlock
) {
1145 // timed out with none received - try MTFTP open
1147 if ((Status
= MtftpOpen (
1157 )) != EFI_SUCCESS
) {
1159 // open failure - try TFTP
1164 // return code EFI_SUCCESS
1165 // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
1166 // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
1167 // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
1168 // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
1170 if (CompStat
== (GOTUNI
| GOTMULTI
)) {
1172 // finished - got it all
1179 // offset is two packet lengths
1183 // last block received
1191 ListenTimeout
= TransTimeout
;
1195 // did we get the last block
1197 if (Status
== EFI_SUCCESS
) {
1199 // yes - set the file size if this was first time
1202 *BufferSizePtr
-= BufferSize
;
1205 // if buffer was too small, finished
1207 if (!DontUseBuffer
) {
1208 return EFI_BUFFER_TOO_SMALL
;
1211 // if we got them all, finished
1213 if (!NumMissed
&& StartBlock
== LastStartBlock
+ 1) {
1217 // did not get them all - set last block
1219 LastBlock
= (UINT16
) (StartBlock
- 1);
1222 // compute listen timeout
1224 ListenTimeout
= (UINT16
) ((NumMissed
> MtftpInfoPtr
->ListenTimeout
) ? 0 : (MtftpInfoPtr
->ListenTimeout
- NumMissed
));
1234 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1242 PXE_BASECODE_DEVICE
*Private
,
1243 UINT64
*BufferSizePtr
,
1244 EFI_IP_ADDRESS
*ServerIpPtr
,
1245 EFI_PXE_BASE_CODE_UDP_PORT SrvPort
,
1247 UINTN
*PacketSizePtr
1250 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1251 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1259 struct Tftpv4Oack OAck2Ptr
;
1260 struct Tftpv4Ack Ack2Ptr
;
1261 struct Tftpv4Data Datastr
;
1265 ServerReplyPort
= 0;
1266 ReplyLen
= sizeof (u
.Datastr
.Data
);
1269 // send a write request with the blocksize option -
1270 // sets our IP and port - and receive reply - sets his port
1271 // will retry operation up to 3 times if no response,
1272 // and will retry without options on an error reply
1274 if ((Status
= TftpRwReqwResp (
1276 /* BIGBLKNUMOP | */BKSZOP
| TSIZEOP
,
1288 )) != EFI_SUCCESS
) {
1289 DEBUG ((DEBUG_WARN
, "\nTftpInfo() Exit #1"));
1293 // check for good OACK
1295 if (u
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1297 // now parse it for options
1302 sizeof (BigBlkNumOp
),
1303 u
.OAck2Ptr
.OpAck
[0].Option
,
1304 ReplyLen
+ sizeof (u
.Ack2Ptr
.BlockNum
)
1308 if (AtoU (Ptr
) == 8) {
1309 Private
->BigBlkNumFlag
= TRUE
;
1311 return EFI_PROTOCOL_ERROR
;
1319 sizeof (BlockSizeOp
),
1320 u
.OAck2Ptr
.OpAck
[0].Option
,
1321 ReplyLen
+= sizeof (u
.Ack2Ptr
.BlockNum
)
1324 *PacketSizePtr
= (Ptr
) ? AtoU (Ptr
) : 512;
1332 u
.OAck2Ptr
.OpAck
[0].Option
,
1337 *BufferSizePtr
= AtoU64 (Ptr
);
1340 // teminate session with error
1342 SendError (Private
, ServerIpPtr
, &ServerReplyPort
, &OurPort
);
1351 // if MTFTP get filesize, return unsupported
1353 if (SrvPort
!= TftpRequestPort
) {
1354 SendError (Private
, ServerIpPtr
, &ServerReplyPort
, &OurPort
);
1355 DEBUG ((DEBUG_WARN
, "\nTftpInfo() Exit #3"));
1356 return EFI_UNSUPPORTED
;
1361 // last block received
1366 // does not support the option - do a download with no buffer
1370 Status
= LockStepReceive (
1378 &Private
->EfiBc
.Mode
->StationIp
,
1385 if (Status
!= EFI_SUCCESS
) {
1386 DEBUG ((DEBUG_WARN
, "\nTftpInfo() LockStepReceive() == %Xh", Status
));
1389 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1396 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1404 PXE_BASECODE_DEVICE
*Private
,
1405 UINT64
*BufferSizePtr
,
1407 EFI_IP_ADDRESS
*ServerIpPtr
,
1409 UINTN
*PacketSizePtr
,
1410 EFI_PXE_BASE_CODE_UDP_PORT SrvPort
,
1412 IN BOOLEAN DontUseBuffer
1415 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1416 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1424 struct Tftpv4Ack Ack2Ptr
;
1425 struct Tftpv4Oack OAck2Ptr
;
1426 struct Tftpv4Data Data
;
1427 struct Tftpv4Ack8 Ack8Ptr
;
1428 struct Tftpv4Data8 Data8
;
1432 ServerReplyPort
= 0;
1433 ReplyLen
= (UINTN
) ((*BufferSizePtr
> 0xFFFF) ? 0xFFFF : *BufferSizePtr
);
1436 // send a read request with the blocksize option - sets our IP and port
1437 // - and receive reply - sets his port will retry operation up to 3
1438 // times if no response, and will retry without options on an error
1441 if ((Status
= TftpRwReqwResp (
1443 /* BIGBLKNUMOP | */BKSZOP
,
1455 )) != EFI_SUCCESS
) {
1456 DEBUG ((DEBUG_WARN
, "\nTftpDownload() Exit #1 %xh (%r)", Status
, Status
));
1462 if (U
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1466 CopyMem (U
.Data
.Data
, BufferPtr
, ReplyLen
);
1470 sizeof (BigBlkNumOp
),
1471 U
.OAck2Ptr
.OpAck
[0].Option
,
1472 ReplyLen
+ sizeof (U
.Ack2Ptr
.BlockNum
)
1476 if (AtoU (Ptr
) == 8) {
1477 Private
->BigBlkNumFlag
= TRUE
;
1479 return EFI_PROTOCOL_ERROR
;
1483 // now parse it for blocksize option
1487 sizeof (BlockSizeOp
),
1488 U
.OAck2Ptr
.OpAck
[0].Option
,
1489 ReplyLen
+= sizeof (U
.Ack2Ptr
.BlockNum
)
1492 ReplyLen
= (Ptr
!= NULL
) ? AtoU (Ptr
) : 512;
1496 // last block received
1499 } else if (U
.Ack2Ptr
.OpCode
!= HTONS (TFTP_DATA
) || U
.Ack2Ptr
.BlockNum
!= HTONS (1)) {
1503 DEBUG ((DEBUG_WARN
, "\nTftpDownload() Exit #2 %xh (%r)", Status
, Status
));
1505 return EFI_PROTOCOL_ERROR
;
1508 // got good data packet
1512 // last block received
1517 if (PacketSizePtr
!= NULL
) {
1518 *PacketSizePtr
= ReplyLen
;
1521 // routine to read rest of file after a successful open (TFTP or MTFTP)
1522 // sends ACK and gets next data packet until short packet arrives, then sends
1523 // ACK and (hopefully) times out
1524 // if first packet has been read, BufferPtr and BufferSize must reflect fact
1526 Status
= LockStepReceive (
1534 &Private
->EfiBc
.Mode
->StationIp
,
1541 if (Status
!= EFI_SUCCESS
) {
1542 DEBUG ((DEBUG_WARN
, "\nTftpDownload() Exit #3 %xh (%r)", Status
, Status
));
1544 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1554 if (!EFI_ERROR (Status
)) {
1555 Status
= EFI_BUFFER_TOO_SMALL
;
1563 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1571 PXE_BASECODE_DEVICE
*Private
,
1572 UINT64
*BufferSizePtr
,
1574 EFI_IP_ADDRESS
*ServerIpPtr
,
1576 UINTN
*PacketSizePtr
,
1580 struct Tftpv4Ack Header
;
1581 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1582 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1585 UINT64 TransferSize
;
1592 struct Tftpv4Oack OAck2Ptr
;
1593 struct Tftpv4Ack Ack2Ptr
;
1594 struct Tftpv4Data Datastr
;
1598 ServerReplyPort
= 0;
1599 TransferSize
= *BufferSizePtr
;
1600 ReplyLen
= sizeof (u
.Datastr
.Data
);
1601 Options
= (UINT16
) ((Overwrite
) ? OVERWRITEOP
| BKSZOP
: BKSZOP
);
1604 // send a write request with the blocksize option - sets our IP and port -
1605 // and receive reply - sets his port
1606 // will retry operation up to 3 times if no response, and will retry without
1607 // options on an error reply
1609 if ((Status
= TftpRwReqwResp (
1623 )) != EFI_SUCCESS
) {
1629 if (u
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1631 // parse it for blocksize option
1635 sizeof (BlockSizeOp
),
1636 u
.OAck2Ptr
.OpAck
[0].Option
,
1637 ReplyLen
+= sizeof (u
.Ack2Ptr
.BlockNum
)
1639 *PacketSizePtr
= (Ptr
) ? AtoU (Ptr
) : 512;
1644 else if (u
.Ack2Ptr
.OpCode
== HTONS (TFTP_ACK
)) {
1646 // option was not supported
1648 *PacketSizePtr
= 512;
1650 return EFI_PROTOCOL_ERROR
;
1655 Header
.OpCode
= HTONS (TFTP_DATA
);
1657 Header
.BlockNum
= HTONS (1);
1663 Retries
= NUM_ACK_RETRIES
;
1664 HeaderSize
= sizeof (Header
);
1665 TransferLen
= (UINTN
) (MIN (*PacketSizePtr
, TransferSize
));
1668 // write a data packet and get an ack
1674 if ((Status
= UdpWrite (
1676 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
1686 )) != EFI_SUCCESS
) {
1692 ReplyLen
= sizeof (u
.Datastr
.Data
);
1694 if ((Status
= TftpUdpRead (
1705 )) == EFI_SUCCESS
) {
1707 // check for ACK for this data packet
1709 if (u
.Ack2Ptr
.OpCode
!= HTONS (TFTP_ACK
)) {
1710 return EFI_PROTOCOL_ERROR
;
1713 if (u
.Ack2Ptr
.BlockNum
!= Header
.BlockNum
) {
1715 // not for this packet - continue
1717 Status
= EFI_TIMEOUT
;
1720 } while (Status
== EFI_TIMEOUT
&& --Retries
);
1722 if (Status
!= EFI_SUCCESS
) {
1726 BufferPtr
= (VOID
*) ((UINT8
*) (BufferPtr
) + TransferLen
);
1727 TransferSize
-= TransferLen
;
1729 Header
.BlockNum
= HTONS ((UINT16
) BlockNum
);
1730 } while (TransferLen
== *PacketSizePtr
);
1735 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1739 @return * EFI_INVALID_PARAMETER
1740 @return * EFI_OUT_OF_RESOURCES
1741 @return * EFI_BAD_BUFFER_SIZE
1742 @return * Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(),
1743 @return * TftpDownload() and TftpUpload().
1748 PXE_BASECODE_DEVICE
*Private
,
1749 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation
,
1750 UINT64
*BufferSizePtr
,
1752 EFI_IP_ADDRESS
*ServerIpPtr
,
1754 UINTN
*PacketSizePtr
,
1755 IN EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
, OPTIONAL
1756 IN BOOLEAN Overwrite
,
1757 IN BOOLEAN DontUseBuffer
1760 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
1761 EFI_STATUS StatCode
;
1763 UINT64 BufferSizeLocal
;
1765 UINT8
*BufferPtrLocal
;
1767 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
;
1769 Filter
.reserved
= 0;
1771 /* No error has occurred, yet. */
1772 Private
->EfiBc
.Mode
->TftpErrorReceived
= FALSE
;
1774 /* We must at least have an MTFTP server IP address and
1775 * a pointer to the buffer size.
1777 if (!ServerIpPtr
|| !BufferSizePtr
) {
1778 DEBUG ((DEBUG_WARN
, "\nPxeBcMtftp() Exit #1"));
1780 return EFI_INVALID_PARAMETER
;
1783 Private
->Function
= EFI_PXE_BASE_CODE_FUNCTION_MTFTP
;
1786 // make sure filter set to unicast at start
1788 if ((StatCode
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
1791 "\nPxeBcMtftp() Exit IpFilter() == %Xh",
1798 // set unset parms to default values
1800 if (!PacketSizePtr
) {
1801 *(PacketSizePtr
= &PacketSize
) = MAX_TFTP_PKT_SIZE
;
1804 if ((*PacketSizePtr
> *BufferSizePtr
) &&
1805 (Operation
!= EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
) &&
1806 (Operation
!= EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE
)) {
1807 *PacketSizePtr
= MAX ((UINTN
) *BufferSizePtr
, MIN_TFTP_PKT_SIZE
);
1810 if (*PacketSizePtr
< MIN_TFTP_PKT_SIZE
) {
1811 *PacketSizePtr
= MIN_TFTP_PKT_SIZE
;
1812 return EFI_INVALID_PARAMETER
;
1815 if (*PacketSizePtr
> BUFFER_ALLOCATE_SIZE
) {
1816 *PacketSizePtr
= BUFFER_ALLOCATE_SIZE
;
1819 if (*PacketSizePtr
> MAX_TFTP_PKT_SIZE
) {
1820 *PacketSizePtr
= MAX_TFTP_PKT_SIZE
;
1823 if (Operation
== EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
) {
1824 StatCode
= TftpInfo (
1833 if (StatCode
!= EFI_SUCCESS
) {
1836 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
1844 if (Operation
== EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE
) {
1845 if (!MtftpInfoPtr
|| !MtftpInfoPtr
->SPort
) {
1846 DEBUG ((DEBUG_WARN
, "\nPxeBcMtftp() Exit #2"));
1847 return EFI_INVALID_PARAMETER
;
1849 StatCode
= TftpInfo (
1853 MtftpInfoPtr
->SPort
,
1860 if (StatCode
!= EFI_SUCCESS
) {
1863 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
1872 if (!BufferPtr
&& !DontUseBuffer
) {
1874 // if dontusebuffer is false and no buffer???
1876 DEBUG ((DEBUG_WARN
, "\nPxeBcMtftp() Exit #3"));
1878 // DontUseBuffer can be true only for read_file operation
1880 return EFI_INVALID_PARAMETER
;
1883 if (DontUseBuffer
) {
1884 Status
= gBS
->AllocatePool (
1885 EfiBootServicesData
,
1886 BUFFER_ALLOCATE_SIZE
,
1887 (VOID
**) &BufferPtrLocal
1890 if (EFI_ERROR (Status
) || BufferPtrLocal
== NULL
) {
1891 DEBUG ((DEBUG_NET
, "\nPxeBcMtftp() Exit #4"));
1892 return EFI_OUT_OF_RESOURCES
;
1895 BufferSizeLocal
= BUFFER_ALLOCATE_SIZE
;
1897 if (!*BufferSizePtr
&& Operation
!= EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
) {
1898 DEBUG ((DEBUG_WARN
, "\nPxeBcMtftp() Exit #5"));
1899 return EFI_BAD_BUFFER_SIZE
;
1902 BufferPtrLocal
= BufferPtr
;
1903 BufferSizeLocal
= *BufferSizePtr
;
1906 switch (Operation
) {
1907 case EFI_PXE_BASE_CODE_MTFTP_READ_FILE
:
1908 if (FilenamePtr
== NULL
||
1909 MtftpInfoPtr
== NULL
||
1910 MtftpInfoPtr
->MCastIp
.Addr
[0] == 0 ||
1911 MtftpInfoPtr
->SPort
== 0 ||
1912 MtftpInfoPtr
->CPort
== 0 ||
1913 MtftpInfoPtr
->ListenTimeout
== 0 ||
1914 MtftpInfoPtr
->TransmitTimeout
== 0
1916 StatCode
= EFI_INVALID_PARAMETER
;
1920 // try MTFTP - if fails, drop into TFTP read
1922 if ((StatCode
= MtftpDownload (
1930 )) == EFI_SUCCESS
|| StatCode
== EFI_BUFFER_TOO_SMALL
) {
1931 if (BufferSizePtr
/* %% !DontUseBuffer */ ) {
1932 *BufferSizePtr
= BufferSizeLocal
;
1938 // go back to unicast
1940 if ((StatCode
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
1945 case EFI_PXE_BASE_CODE_TFTP_READ_FILE
:
1946 if (FilenamePtr
== NULL
) {
1947 StatCode
= EFI_INVALID_PARAMETER
;
1951 StatCode
= TftpDownload (
1963 if (StatCode
== EFI_SUCCESS
|| StatCode
== EFI_BUFFER_TOO_SMALL
) {
1964 if (BufferSizePtr
/* !DontUseBuffer */ ) {
1965 *BufferSizePtr
= BufferSizeLocal
;
1971 case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
:
1972 if (FilenamePtr
== NULL
|| DontUseBuffer
) {
1974 // not a valid option
1976 StatCode
= EFI_INVALID_PARAMETER
;
1980 StatCode
= TftpUpload (
1990 if (StatCode
!= EFI_SUCCESS
) {
1993 "\nPxeBcMtftp() Exit #6 %xh (%r)",
2001 case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY
:
2002 if (FilenamePtr
== NULL
|| DontUseBuffer
) {
2004 // not a valid option
2006 StatCode
= EFI_INVALID_PARAMETER
;
2010 StatCode
= TftpDownload (
2022 if (StatCode
!= EFI_SUCCESS
) {
2025 "\nPxeBcMtftp() Exit #7 %xh (%r)",
2033 case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY
:
2034 if (DontUseBuffer
) {
2035 StatCode
= EFI_INVALID_PARAMETER
;
2039 if (MtftpInfoPtr
== NULL
|| !MtftpInfoPtr
->SPort
) {
2042 "\nPxeBcMtftp() Exit #9 %xh (%r)",
2043 EFI_INVALID_PARAMETER
,
2044 EFI_INVALID_PARAMETER
)
2047 return EFI_INVALID_PARAMETER
;
2050 StatCode
= TftpDownload (
2057 MtftpInfoPtr
->SPort
,
2065 StatCode
= EFI_INVALID_PARAMETER
;
2068 if (DontUseBuffer
) {
2069 gBS
->FreePool (BufferPtrLocal
);
2072 if (StatCode
!= EFI_SUCCESS
) {
2075 "\nPxeBcMtftp() Exit #8 %xh (%r)",
2086 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2090 @return * EFI_INVALID_PARAMETER
2091 @return * Status is also returned from PxeBcMtftp();
2097 IN EFI_PXE_BASE_CODE_PROTOCOL
* This
,
2098 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation
,
2099 IN OUT VOID
*BufferPtr
,
2100 IN BOOLEAN Overwrite
,
2101 IN OUT UINT64
*BufferSizePtr
,
2102 IN UINTN
*BlockSizePtr OPTIONAL
,
2103 IN EFI_IP_ADDRESS
* ServerIpPtr
,
2104 IN UINT8
*FilenamePtr
,
2105 IN EFI_PXE_BASE_CODE_MTFTP_INFO
* MtftpInfoPtr OPTIONAL
,
2106 IN BOOLEAN DontUseBuffer
2109 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
2110 EFI_STATUS StatCode
;
2111 PXE_BASECODE_DEVICE
*Private
;
2114 // Lock the instance data and make sure started
2116 StatCode
= EFI_SUCCESS
;
2119 DEBUG ((DEBUG_ERROR
, "BC *This pointer == NULL"));
2120 return EFI_INVALID_PARAMETER
;
2123 Private
= CR (This
, PXE_BASECODE_DEVICE
, EfiBc
, PXE_BASECODE_DEVICE_SIGNATURE
);
2125 if (Private
== NULL
) {
2126 DEBUG ((DEBUG_ERROR
, "PXE_BASECODE_DEVICE poiner == NULL"));
2127 return EFI_INVALID_PARAMETER
;
2130 if (!IS_INADDR_UNICAST (ServerIpPtr
)) {
2132 // The station IP is not a unicast address.
2134 return EFI_INVALID_PARAMETER
;
2137 EfiAcquireLock (&Private
->Lock
);
2139 if (This
->Mode
== NULL
|| !This
->Mode
->Started
) {
2140 DEBUG ((DEBUG_ERROR
, "BC was not started."));
2141 EfiReleaseLock (&Private
->Lock
);
2142 return EFI_NOT_STARTED
;
2147 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
;
2149 Filter
.reserved
= 0;
2151 DEBUG ((DEBUG_WARN
, "\nBcMtftp() Op=%d Buf=%Xh", Operation
, BufferPtr
));
2153 StatCode
= PxeBcMtftp (
2167 // restore to unicast
2169 IpFilter (Private
, &Filter
);
2172 // Unlock the instance data
2174 EfiReleaseLock (&Private
->Lock
);
2178 /* eof - PxeBcMtftp.c */