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 :=
83 PXE_BASECODE_DEVICE
*Private
,
88 EFI_IP_ADDRESS
*ServerIpPtr
,
89 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
90 EFI_IP_ADDRESS
*OurIpPtr
,
91 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
95 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
97 EFI_EVENT TimeoutEvent
;
103 Status
= gBS
->CreateEvent (
111 if (EFI_ERROR (Status
)) {
115 Status
= gBS
->SetTimer (
118 Timeout
* 10000000 + 1000000
121 if (EFI_ERROR (Status
)) {
122 gBS
->CloseEvent (TimeoutEvent
);
128 HeaderSize
= Private
->BigBlkNumFlag
? sizeof (struct Tftpv4Ack8
) : sizeof (struct Tftpv4Ack
);
130 #define ERROR_MESSAGE_PTR ((struct Tftpv4Error *) HeaderPtr)
146 if (Status
!= EFI_SUCCESS
|| ERROR_MESSAGE_PTR
->OpCode
!= HTONS (TFTP_ERROR
)) {
147 gBS
->CloseEvent (TimeoutEvent
);
151 // got an error packet
152 // write one byte error code followed by error message
154 PxeBcMode
= Private
->EfiBc
.Mode
;
155 PxeBcMode
->TftpErrorReceived
= TRUE
;
156 PxeBcMode
->TftpError
.ErrorCode
= (UINT8
) NTOHS (ERROR_MESSAGE_PTR
->ErrCode
);
157 HeaderSize
= MIN (*BufferSizePtr
, sizeof PxeBcMode
->TftpError
.ErrorString
);
158 CopyMem (PxeBcMode
->TftpError
.ErrorString
, BufferPtr
, HeaderSize
);
160 gBS
->CloseEvent (TimeoutEvent
);
161 return EFI_TFTP_ERROR
;
164 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
173 PXE_BASECODE_DEVICE
*Private
,
174 EFI_IP_ADDRESS
*ServerIpPtr
,
175 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
176 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
179 struct Tftpv4Error
*ErrStr
;
182 ErrStr
= (VOID
*) Private
->TftpErrorBuffer
;
183 Len
= sizeof *ErrStr
;
185 ErrStr
->OpCode
= HTONS (TFTP_ERROR
);
186 ErrStr
->ErrCode
= HTONS (TFTP_ERR_OPTION
);
187 ErrStr
->ErrMsg
[0] = 0;
191 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
204 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
213 PXE_BASECODE_DEVICE
*Private
,
214 EFI_IP_ADDRESS
*ServerIpPtr
,
215 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
216 EFI_IP_ADDRESS
*ReplyIpPtr
,
217 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
225 struct Tftpv4Data DataBuffer
;
226 struct Tftpv4Ack
*Ack2Ptr
;
227 struct Tftpv4Ack8
*Ack8Ptr
;
231 Ack2Ptr
= (VOID
*) Private
->TftpAckBuffer
;
232 Ack8Ptr
= (VOID
*) Private
->TftpAckBuffer
;
234 if (Private
->BigBlkNumFlag
) {
235 Len
= sizeof (struct Tftpv4Ack8
);
237 Ack8Ptr
->OpCode
= HTONS (TFTP_ACK8
);
238 Ack8Ptr
->BlockNum
= Swap64 (*BlockNumPtr
);
242 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
254 if (EFI_ERROR (Status
)) {
258 Len
= sizeof (struct Tftpv4Ack
);
260 Ack2Ptr
->OpCode
= HTONS (TFTP_ACK
);
261 Ack2Ptr
->BlockNum
= HTONS ((UINT16
) *BlockNumPtr
);
265 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
277 if (EFI_ERROR (Status
)) {
284 // ACK of last packet. This is just a courtesy.
285 // Do not wait for response.
292 Status
= TftpUdpRead (
305 if (EFI_ERROR (Status
) && Status
!= EFI_BUFFER_TOO_SMALL
) {
309 // got a good reply (so far)
310 // check for next data packet
312 if (!Private
->BigBlkNumFlag
&& DataBuffer
.Header
.OpCode
== HTONS (TFTP_DATA
)) {
313 if (Status
== EFI_BUFFER_TOO_SMALL
) {
314 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
317 *BlockNumPtr
= NTOHS (DataBuffer
.Header
.BlockNum
);
321 if (Private
->BigBlkNumFlag
&& DataBuffer
.Header
.OpCode
== HTONS (TFTP_DATA8
)) {
322 if (Status
== EFI_BUFFER_TOO_SMALL
) {
323 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
326 *BlockNumPtr
= Swap64 (*(UINT64
*) &DataBuffer
.Header
.BlockNum
);
330 return EFI_PROTOCOL_ERROR
;
333 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
342 PXE_BASECODE_DEVICE
*Private
,
344 UINT64
*BufferSizePtr
,
347 EFI_IP_ADDRESS
*ServerIpPtr
,
348 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
349 EFI_IP_ADDRESS
*ReplyIpPtr
,
350 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
353 IN BOOLEAN DontUseBuffer
363 ReplyLen
= PacketSize
;
364 BlockNum
= LastBlock
;
366 DEBUG ((DEBUG_INFO
, "\nLockStepReceive() PacketSize = %d", PacketSize
));
369 BufferSize
= PacketSize
;
371 BufferSize
= *BufferSizePtr
- Offset
;
375 while (ReplyLen
>= 512 && ReplyLen
== PacketSize
) {
376 if (BufferSize
< PacketSize
) {
377 ReplyLen
= (UINTN
) ((BufferSize
> 0) ? BufferSize
: 0);
383 // write an ack packet and get data - retry up to NUM_ACK_RETRIES on timeout
385 Retries
= NUM_ACK_RETRIES
;
390 Status
= SendAckAndGetData (
403 if (!EFI_ERROR (Status
) || Status
== EFI_BUFFER_TOO_SMALL
) {
404 if (BlockNum
== LastBlock
) {
405 DEBUG ((DEBUG_NET
, "\nresend"));
407 // a resend - continue
409 Status
= EFI_TIMEOUT
;
410 } else if (Private
->BigBlkNumFlag
) {
411 if (BlockNum
!= ++LastBlock
) {
412 DEBUG ((DEBUG_NET
, "\nLockStepReceive() Exit #1a"));
414 // not correct blocknum - error
416 return EFI_PROTOCOL_ERROR
;
419 LastBlock
= (LastBlock
+ 1) & 0xFFFF;
420 if (BlockNum
!= LastBlock
) {
421 DEBUG ((DEBUG_NET
, "\nLockStepReceive() Exit #1b"));
422 return EFI_PROTOCOL_ERROR
;
424 // not correct blocknum - error
429 } while (Status
== EFI_TIMEOUT
&& --Retries
);
431 if (EFI_ERROR (Status
)) {
432 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
433 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
440 BufferSize
+= ReplyLen
;
442 BufferPtr
+= ReplyLen
;
443 BufferSize
-= ReplyLen
;
447 // while (ReplyLen == PacketSize);
450 if (BufferSizePtr
!= NULL
) {
451 *BufferSizePtr
= (BufferSize
- PacketSize
);
454 *BufferSizePtr
-= BufferSize
;
457 /* Send ACK of last packet. */
476 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
481 STATIC UINT8 Mode
[] = MODE_BINARY
;
482 STATIC UINT8 BlockSizeOp
[] = OP_BLKSIZE
;
483 STATIC UINT8 TsizeOp
[] = OP_TFRSIZE
;
484 STATIC UINT8 OverwriteOp
[] = OP_OVERWRITE
;
485 STATIC UINT8 BigBlkNumOp
[] = OP_BIGBLKNUM
;
486 STATIC EFI_PXE_BASE_CODE_UDP_PORT TftpRequestPort
= TFTP_OPEN_PORT
;
488 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
492 @return Pointer to value field if option found or NULL if not found.
504 if ((OackSize
-= OpLen
) <= 0) {
509 if (!CompareMem (OackPtr
, OptionPtr
, OpLen
)) {
510 return OackPtr
+ OpLen
;
514 } while (--OackSize
);
519 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
520 #define BKSZOP 1 // block size
521 #define TSIZEOP 2 // transfer size
522 #define OVERWRITEOP 4 // overwrite
523 #define BIGBLKNUMOP 8 // big block numbers
529 PXE_BASECODE_DEVICE
*Private
,
530 EFI_IP_ADDRESS
*ServerIpPtr
,
531 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
532 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
534 UINTN
*PacketSizePtr
,
540 struct Tftpv4Req ReqStr
;
548 if (*OurPortPtr
== 0) {
549 OpFlags
= EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
| EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
;
551 OpFlags
= EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
;
554 // build the basic request - opcode, filename, mode
557 u
->ReqStr
.OpCode
= HTONS (Req
);
558 TotalLen
= sizeof (Mode
) + sizeof (u
->ReqStr
.OpCode
) + (Len
= 1 + AsciiStrLen ((CHAR8
*) FilenamePtr
));
560 CopyMem (u
->ReqStr
.FileName
, FilenamePtr
, Len
);
561 Ptr
= (UINT8
*) (u
->ReqStr
.FileName
+ Len
);
563 CopyMem (Ptr
, Mode
, sizeof (Mode
));
564 Ptr
+= sizeof (Mode
);
566 if (Options
& BKSZOP
) {
567 CopyMem (Ptr
, BlockSizeOp
, sizeof (BlockSizeOp
));
568 UtoA10 (*PacketSizePtr
, Ptr
+ sizeof (BlockSizeOp
));
570 TotalLen
+= (Len
= 1 + AsciiStrLen ((CHAR8
*) (Ptr
+ sizeof (BlockSizeOp
))) + sizeof (BlockSizeOp
));
575 if (Options
& TSIZEOP
) {
576 CopyMem (Ptr
, TsizeOp
, sizeof (TsizeOp
));
577 CopyMem (Ptr
+ sizeof (TsizeOp
), "0", 2);
578 TotalLen
+= sizeof (TsizeOp
) + 2;
579 Ptr
+= sizeof (TsizeOp
) + 2;
582 if (Options
& OVERWRITEOP
) {
583 CopyMem (Ptr
, OverwriteOp
, sizeof (OverwriteOp
));
584 CopyMem (Ptr
+ sizeof (OverwriteOp
), "1", 2);
585 TotalLen
+= sizeof (OverwriteOp
) + 2;
586 Ptr
+= sizeof (OverwriteOp
) + 2;
589 if (Options
& BIGBLKNUMOP
) {
590 CopyMem (Ptr
, BigBlkNumOp
, sizeof (BigBlkNumOp
));
591 CopyMem (Ptr
+ sizeof (BigBlkNumOp
), "8", 2);
592 TotalLen
+= sizeof (BigBlkNumOp
) + 2;
593 Ptr
+= sizeof (BigBlkNumOp
) + 2;
613 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
624 PXE_BASECODE_DEVICE
*Private
,
626 UINTN
*PacketSizePtr
,
629 EFI_IP_ADDRESS
*ServerIpPtr
,
630 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
631 EFI_PXE_BASE_CODE_UDP_PORT
*ServerReplyPortPtr
,
632 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
642 SaveReplyLen
= *ReplyLenPtr
;
644 Private
->BigBlkNumFlag
= FALSE
;
650 if (*OurPortPtr
!= 0) {
651 if (++ *OurPortPtr
== 0) {
652 *OurPortPtr
= PXE_RND_PORT_LOW
;
656 // send request from our Ip = StationIp
658 if ((Status
= TftpRwReq (
671 "\nTftpRwReqwResp() Exit #1 %xh (%r)",
679 // read reply to our Ip = StationIp
681 *ReplyLenPtr
= SaveReplyLen
;
683 Status
= TftpUdpRead (
685 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
,
695 } while (Status
== EFI_TIMEOUT
&& --Retries
);
697 if (!Options
|| Status
!= EFI_TFTP_ERROR
) {
700 "\nTftpRwReqwResp() Exit #2 %xh (%r)",
707 Status
= TftpRwReqwResp (
723 DEBUG ((DEBUG_WARN
, "\nTftpRwReqwResp() Exit #3 %xh (%r)", Status
, Status
));
728 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
732 // read on mcast ip, cport, from sport, for data packet
733 // returns success if gets multicast last packet or all up to last block
734 // if not missing, then finished
744 PXE_BASECODE_DEVICE
*Private
,
745 UINT64
*BufferSizePtr
,
747 EFI_IP_ADDRESS
*ServerIpPtr
,
748 EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
,
749 UINT64
*StartBlockPtr
,
752 UINT16 ListenTimeout
,
754 IN BOOLEAN DontUseBuffer
758 struct Tftpv4Ack Header
;
769 LastBlockNum
= *StartBlockPtr
;
770 Timeout
= ListenTimeout
;
773 BufferSize
= *BufferSizePtr
;
774 ReplyLen
= MAX_TFTP_PKT_SIZE
;;
780 if ((SaveReplyLen
= ReplyLen
) > BufferSize
) {
784 /* %%TBD - add big block number support */
787 // get data - loop on resends
790 ReplyLen
= SaveReplyLen
;
792 if ((Status
= TftpUdpRead (
799 &MtftpInfoPtr
->SPort
,
800 &MtftpInfoPtr
->MCastIp
,
801 &MtftpInfoPtr
->CPort
,
807 // make sure a data packet
809 if (Header
.OpCode
!= HTONS (TFTP_DATA
)) {
810 return EFI_PROTOCOL_ERROR
;
812 } while ((BlockNum
= NTOHS (Header
.BlockNum
)) == LastBlockNum
);
815 // make sure still going up
817 if (LastBlockNum
> BlockNum
) {
818 return EFI_PROTOCOL_ERROR
;
821 if (BlockNum
- LastBlockNum
> 0xFFFFFFFF) {
822 return EFI_PROTOCOL_ERROR
;
824 NumMissed
= (UINTN
) (BlockNum
- LastBlockNum
- 1);
827 LastBlockNum
= BlockNum
;
830 // if first time through, some reinitialization
833 *StartBlockPtr
= BlockNum
;
834 PacketSize
= ReplyLen
;
835 Timeout
= TransTimeout
;
837 *NumMissedPtr
= (UINT16
) (*NumMissedPtr
+ NumMissed
);
840 // if missed packets, update start block,
841 // etc. and move packet to proper place in buffer
844 *StartBlockPtr
= BlockNum
;
845 if (!DontUseBuffer
) {
846 Offset
= NumMissed
* PacketSize
;
847 CopyMem (BufferPtr
+ Offset
, BufferPtr
, ReplyLen
);
849 BufferSize
-= Offset
;
853 if (!DontUseBuffer
) {
854 BufferPtr
+= ReplyLen
;
855 BufferSize
-= ReplyLen
;
857 } while (ReplyLen
== PacketSize
&& BlockNum
!= FinalBlock
);
859 *BufferSizePtr
= BufferSize
;
864 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
868 @return // mtftp open session
869 @return // return code EFI_SUCCESS
870 @return // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
871 @return // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
872 @return // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
873 @retval GOTUNI returns NO_DATA go will go to TFTP session)
879 PXE_BASECODE_DEVICE
* Private
,
880 UINT64
*BufferSizePtr
,
882 UINTN
*PacketSizePtr
,
883 EFI_IP_ADDRESS
* ServerIpPtr
,
885 EFI_PXE_BASE_CODE_MTFTP_INFO
* MtftpInfoPtr
,
886 UINT8
*CompletionStatusPtr
,
889 IN BOOLEAN DontUseBuffer
893 EFI_IP_ADDRESS OurReplyIp
;
894 struct Tftpv4Ack Header
;
900 Retries
= NUM_MTFTP_OPEN_RETRIES
;
901 BufferPtr2
= BufferPtr
;
902 *PacketSizePtr
= (UINTN
) (MIN (*BufferSizePtr
, MAX_TFTP_PKT_SIZE
));
906 // send a read request
908 *CompletionStatusPtr
= 0;
910 if ((Status
= TftpRwReq (
915 &MtftpInfoPtr
->SPort
,
916 &MtftpInfoPtr
->CPort
,
928 ZeroMem (&OurReplyIp
, Private
->IpLength
);
929 ReplyLen
= *PacketSizePtr
;
931 if ((Status
= TftpUdpRead (
933 EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
,
938 &MtftpInfoPtr
->SPort
,
940 &MtftpInfoPtr
->CPort
,
941 MtftpInfoPtr
->TransmitTimeout
944 // check for first data packet
946 if (Header
.OpCode
!= HTONS (TFTP_DATA
)) {
947 return EFI_PROTOCOL_ERROR
;
952 if (Header
.BlockNum
!= HTONS (1)) {
955 // if we are not the primary client,
956 // we probably got first and now second
957 // multicast but no unicast, so
958 // *CompletionStatusPtr = GOTMULTI - if this is
959 // the second, can just go on to listen
960 // starting with 2 as the last block
963 if (Header
.BlockNum
!= HTONS (2)) {
967 *CompletionStatusPtr
= 0;
976 *PacketSizePtr
= ReplyLen
;
978 // see if a unicast data packet
982 &Private
->EfiBc
.Mode
->StationIp
,
985 *CompletionStatusPtr
|= GOTUNI
;
988 // if already got multicast packet,
991 if (*CompletionStatusPtr
& GOTMULTI
) {
994 } else if (!CompareMem (
996 &MtftpInfoPtr
->MCastIp
,
1000 // otherwise see if a multicast data packet
1002 *CompletionStatusPtr
|= GOTMULTI
;
1005 // got first - bump pointer so that if
1006 // second multi comes along, we're OK
1008 if (!DontUseBuffer
) {
1009 BufferPtr2
= (UINT8
*) BufferPtr
+ ReplyLen
;
1012 // if already got unicast packet,
1015 if (*CompletionStatusPtr
& GOTUNI
) {
1020 // else protocol error
1022 return EFI_PROTOCOL_ERROR
;
1024 } else if (Status
== EFI_TIMEOUT
) {
1026 // bad return code - if timed out, retry
1031 // else just bad - failed MTFTP open
1036 } while (Status
== EFI_TIMEOUT
&& --Retries
);
1038 if (Status
!= EFI_SUCCESS
) {
1045 // got em both - go into receive mode
1046 // routine to read rest of file after a successful open (TFTP or MTFTP)
1047 // sends ACK and gets next data packet until short packet arrives,
1048 // then sends ACK and (hopefully) times out
1050 return LockStepReceive (
1057 &MtftpInfoPtr
->SPort
,
1058 &MtftpInfoPtr
->MCastIp
,
1059 &MtftpInfoPtr
->CPort
,
1061 MtftpInfoPtr
->TransmitTimeout
,
1066 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1075 PXE_BASECODE_DEVICE
*Private
,
1076 UINT64
*BufferSizePtr
,
1078 EFI_IP_ADDRESS
*ServerIpPtr
,
1080 EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
,
1081 IN BOOLEAN DontUseBuffer
1084 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
1088 UINT64 LastStartBlock
;
1092 UINT16 TransTimeout
;
1093 UINT16 ListenTimeout
;
1094 UINT8
*BufferPtrLocal
;
1096 TransTimeout
= MtftpInfoPtr
->TransmitTimeout
;
1097 ListenTimeout
= MtftpInfoPtr
->ListenTimeout
;
1102 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
;
1104 CopyMem (&Filter
.IpList
[0], &Private
->EfiBc
.Mode
->StationIp
, sizeof (EFI_IP_ADDRESS
));
1105 CopyMem (&Filter
.IpList
[1], &MtftpInfoPtr
->MCastIp
, sizeof (EFI_IP_ADDRESS
));
1107 if ((Status
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
1112 StartBlock
= LastStartBlock
;
1113 BufferSize
= *BufferSizePtr
- Offset
;
1115 if (DontUseBuffer
) {
1117 // overwrie the temp buf
1119 BufferPtrLocal
= BufferPtr
;
1121 BufferPtrLocal
= BufferPtr
+ Offset
;
1125 // special !!! do not leave enabled in saved version on Source Safe
1126 // Following code put in in order to create a special version for regression
1127 // test of MTFTP server to make sure it handles mulitple opens correctly.
1128 // This code should NOT be enabled normally.
1130 if (((Status
= MtftpListen (
1142 )) != EFI_SUCCESS
) && (Status
!= EFI_TIMEOUT
)) {
1149 // if none were received, start block is not reset
1151 if (StartBlock
== LastStartBlock
) {
1155 // timed out with none received - try MTFTP open
1157 if ((Status
= MtftpOpen (
1167 )) != EFI_SUCCESS
) {
1169 // open failure - try TFTP
1174 // return code EFI_SUCCESS
1175 // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
1176 // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
1177 // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
1178 // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
1180 if (CompStat
== (GOTUNI
| GOTMULTI
)) {
1182 // finished - got it all
1189 // offset is two packet lengths
1193 // last block received
1201 ListenTimeout
= TransTimeout
;
1205 // did we get the last block
1207 if (Status
== EFI_SUCCESS
) {
1209 // yes - set the file size if this was first time
1212 *BufferSizePtr
-= BufferSize
;
1215 // if buffer was too small, finished
1217 if (!DontUseBuffer
) {
1218 return EFI_BUFFER_TOO_SMALL
;
1221 // if we got them all, finished
1223 if (!NumMissed
&& StartBlock
== LastStartBlock
+ 1) {
1227 // did not get them all - set last block
1229 LastBlock
= (UINT16
) (StartBlock
- 1);
1232 // compute listen timeout
1234 ListenTimeout
= (UINT16
) ((NumMissed
> MtftpInfoPtr
->ListenTimeout
) ? 0 : (MtftpInfoPtr
->ListenTimeout
- NumMissed
));
1244 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1253 PXE_BASECODE_DEVICE
*Private
,
1254 UINT64
*BufferSizePtr
,
1255 EFI_IP_ADDRESS
*ServerIpPtr
,
1256 EFI_PXE_BASE_CODE_UDP_PORT SrvPort
,
1258 UINTN
*PacketSizePtr
1261 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1262 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1270 struct Tftpv4Oack OAck2Ptr
;
1271 struct Tftpv4Ack Ack2Ptr
;
1272 struct Tftpv4Data Datastr
;
1276 ServerReplyPort
= 0;
1277 ReplyLen
= sizeof (u
.Datastr
.Data
);
1280 // send a write request with the blocksize option -
1281 // sets our IP and port - and receive reply - sets his port
1282 // will retry operation up to 3 times if no response,
1283 // and will retry without options on an error reply
1285 if ((Status
= TftpRwReqwResp (
1287 /* BIGBLKNUMOP | */BKSZOP
| TSIZEOP
,
1299 )) != EFI_SUCCESS
) {
1300 DEBUG ((DEBUG_WARN
, "\nTftpInfo() Exit #1"));
1304 // check for good OACK
1306 if (u
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1308 // now parse it for options
1313 sizeof (BigBlkNumOp
),
1314 u
.OAck2Ptr
.OpAck
[0].Option
,
1315 ReplyLen
+ sizeof (u
.Ack2Ptr
.BlockNum
)
1319 if (AtoU (Ptr
) == 8) {
1320 Private
->BigBlkNumFlag
= TRUE
;
1322 return EFI_PROTOCOL_ERROR
;
1330 sizeof (BlockSizeOp
),
1331 u
.OAck2Ptr
.OpAck
[0].Option
,
1332 ReplyLen
+= sizeof (u
.Ack2Ptr
.BlockNum
)
1335 *PacketSizePtr
= (Ptr
) ? AtoU (Ptr
) : 512;
1343 u
.OAck2Ptr
.OpAck
[0].Option
,
1348 *BufferSizePtr
= AtoU64 (Ptr
);
1351 // teminate session with error
1353 SendError (Private
, ServerIpPtr
, &ServerReplyPort
, &OurPort
);
1362 // if MTFTP get filesize, return unsupported
1364 if (SrvPort
!= TftpRequestPort
) {
1365 SendError (Private
, ServerIpPtr
, &ServerReplyPort
, &OurPort
);
1366 DEBUG ((DEBUG_WARN
, "\nTftpInfo() Exit #3"));
1367 return EFI_UNSUPPORTED
;
1372 // last block received
1377 // does not support the option - do a download with no buffer
1381 Status
= LockStepReceive (
1389 &Private
->EfiBc
.Mode
->StationIp
,
1396 if (Status
!= EFI_SUCCESS
) {
1397 DEBUG ((DEBUG_WARN
, "\nTftpInfo() LockStepReceive() == %Xh", Status
));
1400 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1407 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1416 PXE_BASECODE_DEVICE
*Private
,
1417 UINT64
*BufferSizePtr
,
1419 EFI_IP_ADDRESS
*ServerIpPtr
,
1421 UINTN
*PacketSizePtr
,
1422 EFI_PXE_BASE_CODE_UDP_PORT SrvPort
,
1424 IN BOOLEAN DontUseBuffer
1427 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1428 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1436 struct Tftpv4Ack Ack2Ptr
;
1437 struct Tftpv4Oack OAck2Ptr
;
1438 struct Tftpv4Data Data
;
1439 struct Tftpv4Ack8 Ack8Ptr
;
1440 struct Tftpv4Data8 Data8
;
1444 ServerReplyPort
= 0;
1445 ReplyLen
= (UINTN
) ((*BufferSizePtr
> 0xFFFF) ? 0xFFFF : *BufferSizePtr
);
1448 // send a read request with the blocksize option - sets our IP and port
1449 // - and receive reply - sets his port will retry operation up to 3
1450 // times if no response, and will retry without options on an error
1453 if ((Status
= TftpRwReqwResp (
1455 /* BIGBLKNUMOP | */BKSZOP
,
1467 )) != EFI_SUCCESS
) {
1468 DEBUG ((DEBUG_WARN
, "\nTftpDownload() Exit #1 %xh (%r)", Status
, Status
));
1474 if (U
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1478 CopyMem (U
.Data
.Data
, BufferPtr
, ReplyLen
);
1482 sizeof (BigBlkNumOp
),
1483 U
.OAck2Ptr
.OpAck
[0].Option
,
1484 ReplyLen
+ sizeof (U
.Ack2Ptr
.BlockNum
)
1488 if (AtoU (Ptr
) == 8) {
1489 Private
->BigBlkNumFlag
= TRUE
;
1491 return EFI_PROTOCOL_ERROR
;
1495 // now parse it for blocksize option
1499 sizeof (BlockSizeOp
),
1500 U
.OAck2Ptr
.OpAck
[0].Option
,
1501 ReplyLen
+= sizeof (U
.Ack2Ptr
.BlockNum
)
1504 ReplyLen
= (Ptr
!= NULL
) ? AtoU (Ptr
) : 512;
1508 // last block received
1511 } else if (U
.Ack2Ptr
.OpCode
!= HTONS (TFTP_DATA
) || U
.Ack2Ptr
.BlockNum
!= HTONS (1)) {
1515 DEBUG ((DEBUG_WARN
, "\nTftpDownload() Exit #2 %xh (%r)", Status
, Status
));
1517 return EFI_PROTOCOL_ERROR
;
1520 // got good data packet
1524 // last block received
1529 if (PacketSizePtr
!= NULL
) {
1530 *PacketSizePtr
= ReplyLen
;
1533 // routine to read rest of file after a successful open (TFTP or MTFTP)
1534 // sends ACK and gets next data packet until short packet arrives, then sends
1535 // ACK and (hopefully) times out
1536 // if first packet has been read, BufferPtr and BufferSize must reflect fact
1538 Status
= LockStepReceive (
1546 &Private
->EfiBc
.Mode
->StationIp
,
1553 if (Status
!= EFI_SUCCESS
) {
1554 DEBUG ((DEBUG_WARN
, "\nTftpDownload() Exit #3 %xh (%r)", Status
, Status
));
1556 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1566 if (!EFI_ERROR (Status
)) {
1567 Status
= EFI_BUFFER_TOO_SMALL
;
1575 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1584 PXE_BASECODE_DEVICE
*Private
,
1585 UINT64
*BufferSizePtr
,
1587 EFI_IP_ADDRESS
*ServerIpPtr
,
1589 UINTN
*PacketSizePtr
,
1593 struct Tftpv4Ack Header
;
1594 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1595 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1598 UINT64 TransferSize
;
1605 struct Tftpv4Oack OAck2Ptr
;
1606 struct Tftpv4Ack Ack2Ptr
;
1607 struct Tftpv4Data Datastr
;
1611 ServerReplyPort
= 0;
1612 TransferSize
= *BufferSizePtr
;
1613 ReplyLen
= sizeof (u
.Datastr
.Data
);
1614 Options
= (UINT16
) ((Overwrite
) ? OVERWRITEOP
| BKSZOP
: BKSZOP
);
1617 // send a write request with the blocksize option - sets our IP and port -
1618 // and receive reply - sets his port
1619 // will retry operation up to 3 times if no response, and will retry without
1620 // options on an error reply
1622 if ((Status
= TftpRwReqwResp (
1636 )) != EFI_SUCCESS
) {
1642 if (u
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1644 // parse it for blocksize option
1648 sizeof (BlockSizeOp
),
1649 u
.OAck2Ptr
.OpAck
[0].Option
,
1650 ReplyLen
+= sizeof (u
.Ack2Ptr
.BlockNum
)
1652 *PacketSizePtr
= (Ptr
) ? AtoU (Ptr
) : 512;
1657 else if (u
.Ack2Ptr
.OpCode
== HTONS (TFTP_ACK
)) {
1659 // option was not supported
1661 *PacketSizePtr
= 512;
1663 return EFI_PROTOCOL_ERROR
;
1668 Header
.OpCode
= HTONS (TFTP_DATA
);
1670 Header
.BlockNum
= HTONS (1);
1676 Retries
= NUM_ACK_RETRIES
;
1677 HeaderSize
= sizeof (Header
);
1678 TransferLen
= (UINTN
) (MIN (*PacketSizePtr
, TransferSize
));
1681 // write a data packet and get an ack
1687 if ((Status
= UdpWrite (
1689 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
1699 )) != EFI_SUCCESS
) {
1705 ReplyLen
= sizeof (u
.Datastr
.Data
);
1707 if ((Status
= TftpUdpRead (
1718 )) == EFI_SUCCESS
) {
1720 // check for ACK for this data packet
1722 if (u
.Ack2Ptr
.OpCode
!= HTONS (TFTP_ACK
)) {
1723 return EFI_PROTOCOL_ERROR
;
1726 if (u
.Ack2Ptr
.BlockNum
!= Header
.BlockNum
) {
1728 // not for this packet - continue
1730 Status
= EFI_TIMEOUT
;
1733 } while (Status
== EFI_TIMEOUT
&& --Retries
);
1735 if (Status
!= EFI_SUCCESS
) {
1739 BufferPtr
= (VOID
*) ((UINT8
*) (BufferPtr
) + TransferLen
);
1740 TransferSize
-= TransferLen
;
1742 Header
.BlockNum
= HTONS ((UINT16
) BlockNum
);
1743 } while (TransferLen
== *PacketSizePtr
);
1748 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1752 @return * EFI_INVALID_PARAMETER
1753 @return * EFI_OUT_OF_RESOURCES
1754 @return * EFI_BAD_BUFFER_SIZE
1755 @return * Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(),
1756 @return * TftpDownload() and TftpUpload().
1761 PXE_BASECODE_DEVICE
*Private
,
1762 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation
,
1763 UINT64
*BufferSizePtr
,
1765 EFI_IP_ADDRESS
*ServerIpPtr
,
1767 UINTN
*PacketSizePtr
,
1768 IN EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
, OPTIONAL
1769 IN BOOLEAN Overwrite
,
1770 IN BOOLEAN DontUseBuffer
1773 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
1774 EFI_STATUS StatCode
;
1776 UINT64 BufferSizeLocal
;
1778 UINT8
*BufferPtrLocal
;
1780 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
;
1782 Filter
.reserved
= 0;
1784 /* No error has occurred, yet. */
1785 Private
->EfiBc
.Mode
->TftpErrorReceived
= FALSE
;
1787 /* We must at least have an MTFTP server IP address and
1788 * a pointer to the buffer size.
1790 if (!ServerIpPtr
|| !BufferSizePtr
) {
1791 DEBUG ((DEBUG_WARN
, "\nPxeBcMtftp() Exit #1"));
1793 return EFI_INVALID_PARAMETER
;
1796 Private
->Function
= EFI_PXE_BASE_CODE_FUNCTION_MTFTP
;
1799 // make sure filter set to unicast at start
1801 if ((StatCode
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
1804 "\nPxeBcMtftp() Exit IpFilter() == %Xh",
1811 // set unset parms to default values
1813 if (!PacketSizePtr
) {
1814 *(PacketSizePtr
= &PacketSize
) = MAX_TFTP_PKT_SIZE
;
1817 if ((*PacketSizePtr
> *BufferSizePtr
) &&
1818 (Operation
!= EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
) &&
1819 (Operation
!= EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE
)) {
1820 *PacketSizePtr
= MAX ((UINTN
) *BufferSizePtr
, MIN_TFTP_PKT_SIZE
);
1823 if (*PacketSizePtr
< MIN_TFTP_PKT_SIZE
) {
1824 *PacketSizePtr
= MIN_TFTP_PKT_SIZE
;
1825 return EFI_INVALID_PARAMETER
;
1828 if (*PacketSizePtr
> BUFFER_ALLOCATE_SIZE
) {
1829 *PacketSizePtr
= BUFFER_ALLOCATE_SIZE
;
1832 if (*PacketSizePtr
> MAX_TFTP_PKT_SIZE
) {
1833 *PacketSizePtr
= MAX_TFTP_PKT_SIZE
;
1836 if (Operation
== EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
) {
1837 StatCode
= TftpInfo (
1846 if (StatCode
!= EFI_SUCCESS
) {
1849 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
1857 if (Operation
== EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE
) {
1858 if (!MtftpInfoPtr
|| !MtftpInfoPtr
->SPort
) {
1859 DEBUG ((DEBUG_WARN
, "\nPxeBcMtftp() Exit #2"));
1860 return EFI_INVALID_PARAMETER
;
1862 StatCode
= TftpInfo (
1866 MtftpInfoPtr
->SPort
,
1873 if (StatCode
!= EFI_SUCCESS
) {
1876 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
1885 if (!BufferPtr
&& !DontUseBuffer
) {
1887 // if dontusebuffer is false and no buffer???
1889 DEBUG ((DEBUG_WARN
, "\nPxeBcMtftp() Exit #3"));
1891 // DontUseBuffer can be true only for read_file operation
1893 return EFI_INVALID_PARAMETER
;
1896 if (DontUseBuffer
) {
1897 Status
= gBS
->AllocatePool (
1898 EfiBootServicesData
,
1899 BUFFER_ALLOCATE_SIZE
,
1900 (VOID
**) &BufferPtrLocal
1903 if (EFI_ERROR (Status
) || BufferPtrLocal
== NULL
) {
1904 DEBUG ((DEBUG_NET
, "\nPxeBcMtftp() Exit #4"));
1905 return EFI_OUT_OF_RESOURCES
;
1908 BufferSizeLocal
= BUFFER_ALLOCATE_SIZE
;
1910 if (!*BufferSizePtr
&& Operation
!= EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
) {
1911 DEBUG ((DEBUG_WARN
, "\nPxeBcMtftp() Exit #5"));
1912 return EFI_BAD_BUFFER_SIZE
;
1915 BufferPtrLocal
= BufferPtr
;
1916 BufferSizeLocal
= *BufferSizePtr
;
1919 switch (Operation
) {
1920 case EFI_PXE_BASE_CODE_MTFTP_READ_FILE
:
1921 if (FilenamePtr
== NULL
||
1922 MtftpInfoPtr
== NULL
||
1923 MtftpInfoPtr
->MCastIp
.Addr
[0] == 0 ||
1924 MtftpInfoPtr
->SPort
== 0 ||
1925 MtftpInfoPtr
->CPort
== 0 ||
1926 MtftpInfoPtr
->ListenTimeout
== 0 ||
1927 MtftpInfoPtr
->TransmitTimeout
== 0
1929 StatCode
= EFI_INVALID_PARAMETER
;
1933 // try MTFTP - if fails, drop into TFTP read
1935 if ((StatCode
= MtftpDownload (
1943 )) == EFI_SUCCESS
|| StatCode
== EFI_BUFFER_TOO_SMALL
) {
1944 if (BufferSizePtr
/* %% !DontUseBuffer */ ) {
1945 *BufferSizePtr
= BufferSizeLocal
;
1951 // go back to unicast
1953 if ((StatCode
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
1958 case EFI_PXE_BASE_CODE_TFTP_READ_FILE
:
1959 if (FilenamePtr
== NULL
) {
1960 StatCode
= EFI_INVALID_PARAMETER
;
1964 StatCode
= TftpDownload (
1976 if (StatCode
== EFI_SUCCESS
|| StatCode
== EFI_BUFFER_TOO_SMALL
) {
1977 if (BufferSizePtr
/* !DontUseBuffer */ ) {
1978 *BufferSizePtr
= BufferSizeLocal
;
1984 case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
:
1985 if (FilenamePtr
== NULL
|| DontUseBuffer
) {
1987 // not a valid option
1989 StatCode
= EFI_INVALID_PARAMETER
;
1993 StatCode
= TftpUpload (
2003 if (StatCode
!= EFI_SUCCESS
) {
2006 "\nPxeBcMtftp() Exit #6 %xh (%r)",
2014 case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY
:
2015 if (FilenamePtr
== NULL
|| DontUseBuffer
) {
2017 // not a valid option
2019 StatCode
= EFI_INVALID_PARAMETER
;
2023 StatCode
= TftpDownload (
2035 if (StatCode
!= EFI_SUCCESS
) {
2038 "\nPxeBcMtftp() Exit #7 %xh (%r)",
2046 case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY
:
2047 if (DontUseBuffer
) {
2048 StatCode
= EFI_INVALID_PARAMETER
;
2052 if (MtftpInfoPtr
== NULL
|| !MtftpInfoPtr
->SPort
) {
2055 "\nPxeBcMtftp() Exit #9 %xh (%r)",
2056 EFI_INVALID_PARAMETER
,
2057 EFI_INVALID_PARAMETER
)
2060 return EFI_INVALID_PARAMETER
;
2063 StatCode
= TftpDownload (
2070 MtftpInfoPtr
->SPort
,
2078 StatCode
= EFI_INVALID_PARAMETER
;
2081 if (DontUseBuffer
) {
2082 gBS
->FreePool (BufferPtrLocal
);
2085 if (StatCode
!= EFI_SUCCESS
) {
2088 "\nPxeBcMtftp() Exit #8 %xh (%r)",
2099 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2103 @return * EFI_INVALID_PARAMETER
2104 @return * Status is also returned from PxeBcMtftp();
2110 IN EFI_PXE_BASE_CODE_PROTOCOL
* This
,
2111 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation
,
2112 IN OUT VOID
*BufferPtr
,
2113 IN BOOLEAN Overwrite
,
2114 IN OUT UINT64
*BufferSizePtr
,
2115 IN UINTN
*BlockSizePtr OPTIONAL
,
2116 IN EFI_IP_ADDRESS
* ServerIpPtr
,
2117 IN UINT8
*FilenamePtr
,
2118 IN EFI_PXE_BASE_CODE_MTFTP_INFO
* MtftpInfoPtr OPTIONAL
,
2119 IN BOOLEAN DontUseBuffer
2122 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
2123 EFI_STATUS StatCode
;
2124 PXE_BASECODE_DEVICE
*Private
;
2127 // Lock the instance data and make sure started
2129 StatCode
= EFI_SUCCESS
;
2132 DEBUG ((DEBUG_ERROR
, "BC *This pointer == NULL"));
2133 return EFI_INVALID_PARAMETER
;
2136 Private
= CR (This
, PXE_BASECODE_DEVICE
, EfiBc
, PXE_BASECODE_DEVICE_SIGNATURE
);
2138 if (Private
== NULL
) {
2139 DEBUG ((DEBUG_ERROR
, "PXE_BASECODE_DEVICE poiner == NULL"));
2140 return EFI_INVALID_PARAMETER
;
2143 if (!IS_INADDR_UNICAST (ServerIpPtr
)) {
2145 // The station IP is not a unicast address.
2147 return EFI_INVALID_PARAMETER
;
2150 EfiAcquireLock (&Private
->Lock
);
2152 if (This
->Mode
== NULL
|| !This
->Mode
->Started
) {
2153 DEBUG ((DEBUG_ERROR
, "BC was not started."));
2154 EfiReleaseLock (&Private
->Lock
);
2155 return EFI_NOT_STARTED
;
2160 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
;
2162 Filter
.reserved
= 0;
2164 DEBUG ((DEBUG_WARN
, "\nBcMtftp() Op=%d Buf=%Xh", Operation
, BufferPtr
));
2166 StatCode
= PxeBcMtftp (
2180 // restore to unicast
2182 IpFilter (Private
, &Filter
);
2185 // Unlock the instance data
2187 EfiReleaseLock (&Private
->Lock
);
2191 /* eof - PxeBcMtftp.c */