3 Copyright (c) 2006 - 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.
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 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
73 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
77 PXE_BASECODE_DEVICE
*Private
,
82 EFI_IP_ADDRESS
*ServerIpPtr
,
83 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
84 EFI_IP_ADDRESS
*OurIpPtr
,
85 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
90 Read TFTP packet. If TFTP ERROR packet is read, fill in TFTP error
91 information in Mode structure and return TFTP_ERROR status.
111 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
113 EFI_EVENT TimeoutEvent
;
119 Status
= gBS
->CreateEvent (
127 if (EFI_ERROR (Status
)) {
131 Status
= gBS
->SetTimer (
134 Timeout
* 10000000 + 1000000
137 if (EFI_ERROR (Status
)) {
138 gBS
->CloseEvent (TimeoutEvent
);
144 HeaderSize
= Private
->BigBlkNumFlag
? sizeof (struct Tftpv4Ack8
) : sizeof (struct Tftpv4Ack
);
146 #define ERROR_MESSAGE_PTR ((struct Tftpv4Error *) HeaderPtr)
162 if (Status
!= EFI_SUCCESS
|| ERROR_MESSAGE_PTR
->OpCode
!= HTONS (TFTP_ERROR
)) {
163 gBS
->CloseEvent (TimeoutEvent
);
167 // got an error packet
168 // write one byte error code followed by error message
170 PxeBcMode
= Private
->EfiBc
.Mode
;
171 PxeBcMode
->TftpErrorReceived
= TRUE
;
172 PxeBcMode
->TftpError
.ErrorCode
= (UINT8
) NTOHS (ERROR_MESSAGE_PTR
->ErrCode
);
173 HeaderSize
= EFI_MIN (*BufferSizePtr
, sizeof PxeBcMode
->TftpError
.ErrorString
);
174 CopyMem (PxeBcMode
->TftpError
.ErrorString
, BufferPtr
, HeaderSize
);
176 gBS
->CloseEvent (TimeoutEvent
);
177 return EFI_TFTP_ERROR
;
180 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
184 PXE_BASECODE_DEVICE
*Private
,
185 EFI_IP_ADDRESS
*ServerIpPtr
,
186 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
187 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
191 Send TFTP ERROR message to TFTP server
202 struct Tftpv4Error
*ErrStr
;
205 ErrStr
= (VOID
*) Private
->TftpErrorBuffer
;
206 Len
= sizeof *ErrStr
;
208 ErrStr
->OpCode
= HTONS (TFTP_ERROR
);
209 ErrStr
->ErrCode
= HTONS (TFTP_ERR_OPTION
);
210 ErrStr
->ErrMsg
[0] = 0;
214 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
227 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
231 PXE_BASECODE_DEVICE
*Private
,
232 EFI_IP_ADDRESS
*ServerIpPtr
,
233 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
234 EFI_IP_ADDRESS
*ReplyIpPtr
,
235 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
244 Send TFTP ACK packet to server and read next DATA packet.
247 Private := Pointer to PxeBc interface
248 ServerIpPtr := Pointer to TFTP server IP address
249 ServerPortPtr := Pointer to TFTP server UDP port
250 ReplyIpPtr := Pointer to TFTP DATA packet destination IP address
251 OurPortPtr := Pointer to TFTP client UDP port
253 ReplyLenPtr := Pointer to packet length
254 PxeBcMode := Pointer to packet buffer
255 BlockNumPtr := Pointer to block number
256 AckOnly := TRUE == Send last ack - do not wait for reply
261 struct Tftpv4Data DataBuffer
;
262 struct Tftpv4Ack
*Ack2Ptr
;
263 struct Tftpv4Ack8
*Ack8Ptr
;
267 Ack2Ptr
= (VOID
*) Private
->TftpAckBuffer
;
268 Ack8Ptr
= (VOID
*) Private
->TftpAckBuffer
;
270 if (Private
->BigBlkNumFlag
) {
271 Len
= sizeof (struct Tftpv4Ack8
);
273 Ack8Ptr
->OpCode
= HTONS (TFTP_ACK8
);
274 Ack8Ptr
->BlockNum
= Swap64 (*BlockNumPtr
);
278 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
290 if (EFI_ERROR (Status
)) {
294 Len
= sizeof (struct Tftpv4Ack
);
296 Ack2Ptr
->OpCode
= HTONS (TFTP_ACK
);
297 Ack2Ptr
->BlockNum
= HTONS ((UINT16
) *BlockNumPtr
);
301 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
313 if (EFI_ERROR (Status
)) {
320 // ACK of last packet. This is just a courtesy.
321 // Do not wait for response.
328 Status
= TftpUdpRead (
341 if (EFI_ERROR (Status
) && Status
!= EFI_BUFFER_TOO_SMALL
) {
345 // got a good reply (so far)
346 // check for next data packet
348 if (!Private
->BigBlkNumFlag
&& DataBuffer
.Header
.OpCode
== HTONS (TFTP_DATA
)) {
349 if (Status
== EFI_BUFFER_TOO_SMALL
) {
350 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
353 *BlockNumPtr
= NTOHS (DataBuffer
.Header
.BlockNum
);
357 if (Private
->BigBlkNumFlag
&& DataBuffer
.Header
.OpCode
== HTONS (TFTP_DATA8
)) {
358 if (Status
== EFI_BUFFER_TOO_SMALL
) {
359 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
362 *BlockNumPtr
= Swap64 (*(UINT64
*) &DataBuffer
.Header
.BlockNum
);
366 return EFI_PROTOCOL_ERROR
;
369 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
373 PXE_BASECODE_DEVICE
*Private
,
375 UINT64
*BufferSizePtr
,
378 EFI_IP_ADDRESS
*ServerIpPtr
,
379 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
380 EFI_IP_ADDRESS
*ReplyIpPtr
,
381 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
384 IN BOOLEAN DontUseBuffer
388 Read rest of file after successfull M/TFTP request.
391 Private := Pointer to PxeBc interface
392 PacketSize := Pointer to packet size
393 BufferSizePtr := Pointer to buffer (file) size
394 Offset := Offset into buffer of next packet
395 BufferPtr := Pointer to receive buffer
396 ServerIpPtr := Pointer to TFTP server IP address
397 ServerPortPtr := Pointer to TFTP server UDP port
398 ReplyIpPtr := Pointer to TFTP DATA packet destination IP address
399 OurPortPtr := Pointer to TFTP client UDP port
400 LastBlock := Last block number received
402 DontUseBuffer := TRUE == throw away data, just count # of bytes
414 ReplyLen
= PacketSize
;
415 BlockNum
= LastBlock
;
417 DEBUG ((EFI_D_INFO
, "\nLockStepReceive() PacketSize = %d", PacketSize
));
420 BufferSize
= PacketSize
;
422 BufferSize
= *BufferSizePtr
- Offset
;
426 while (ReplyLen
>= 512 && ReplyLen
== PacketSize
) {
427 if (BufferSize
< PacketSize
) {
428 ReplyLen
= (UINTN
) ((BufferSize
> 0) ? BufferSize
: 0);
434 // write an ack packet and get data - retry up to NUM_ACK_RETRIES on timeout
436 Retries
= NUM_ACK_RETRIES
;
441 Status
= SendAckAndGetData (
454 if (!EFI_ERROR (Status
) || Status
== EFI_BUFFER_TOO_SMALL
) {
455 if (BlockNum
== LastBlock
) {
456 DEBUG ((EFI_D_NET
, "\nresend"));
458 // a resend - continue
460 Status
= EFI_TIMEOUT
;
461 } else if (Private
->BigBlkNumFlag
) {
462 if (BlockNum
!= ++LastBlock
) {
463 DEBUG ((EFI_D_NET
, "\nLockStepReceive() Exit #1a"));
465 // not correct blocknum - error
467 return EFI_PROTOCOL_ERROR
;
470 LastBlock
= (LastBlock
+ 1) & 0xFFFF;
471 if (BlockNum
!= LastBlock
) {
472 DEBUG ((EFI_D_NET
, "\nLockStepReceive() Exit #1b"));
473 return EFI_PROTOCOL_ERROR
;
475 // not correct blocknum - error
480 } while (Status
== EFI_TIMEOUT
&& --Retries
);
482 if (EFI_ERROR (Status
)) {
483 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
484 SendError (Private
, ServerIpPtr
, ServerPortPtr
, OurPortPtr
);
491 BufferSize
+= ReplyLen
;
493 BufferPtr
+= ReplyLen
;
494 BufferSize
-= ReplyLen
;
498 // while (ReplyLen == PacketSize);
501 if (BufferSizePtr
!= NULL
) {
502 *BufferSizePtr
= (BufferSize
- PacketSize
);
505 *BufferSizePtr
-= BufferSize
;
508 /* Send ACK of last packet. */
527 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
532 STATIC UINT8 Mode
[] = MODE_BINARY
;
533 STATIC UINT8 BlockSizeOp
[] = OP_BLKSIZE
;
534 STATIC UINT8 TsizeOp
[] = OP_TFRSIZE
;
535 STATIC UINT8 OverwriteOp
[] = OP_OVERWRITE
;
536 STATIC UINT8 BigBlkNumOp
[] = OP_BIGBLKNUM
;
537 STATIC EFI_PXE_BASE_CODE_UDP_PORT TftpRequestPort
= TFTP_OPEN_PORT
;
539 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
550 Check TFTP OACK packet for option.
553 OptionPtr := Pointer to option string to find
554 OpLen := Length of option string
555 OackPtr := Pointer to OACK data
556 OackSize := Length of OACK data
559 Pointer to value field if option found or NULL if not found.
562 if ((OackSize
-= OpLen
) <= 0) {
567 if (!CompareMem (OackPtr
, OptionPtr
, OpLen
)) {
568 return OackPtr
+ OpLen
;
572 } while (--OackSize
);
577 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
578 #define BKSZOP 1 // block size
579 #define TSIZEOP 2 // transfer size
580 #define OVERWRITEOP 4 // overwrite
581 #define BIGBLKNUMOP 8 // big block numbers
587 PXE_BASECODE_DEVICE
*Private
,
588 EFI_IP_ADDRESS
*ServerIpPtr
,
589 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
590 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
592 UINTN
*PacketSizePtr
,
597 Send TFTP RRQ/WRQ packet.
600 Req := Type of request to send
601 Options := One or more of the #define values above
602 Private := Pointer to PxeBc interface
603 ServerIpPtr := Pointer to TFTP server IP address
604 ServerPortPtr := Pointer to TFTP server UDP port
605 OurPortPtr := Pointer to TFTP client UDP port
606 FilenamePtr := Pointer to TFTP file or directory name
607 PacketSizePtr := Pointer to block size
615 struct Tftpv4Req ReqStr
;
623 if (*OurPortPtr
== 0) {
624 OpFlags
= EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
| EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
;
626 OpFlags
= EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
;
629 // build the basic request - opcode, filename, mode
632 u
->ReqStr
.OpCode
= HTONS (Req
);
633 TotalLen
= sizeof (Mode
) + sizeof (u
->ReqStr
.OpCode
) + (Len
= 1 + AsciiStrLen ((CHAR8
*)FilenamePtr
));
635 CopyMem (u
->ReqStr
.FileName
, FilenamePtr
, Len
);
636 Ptr
= (UINT8
*) (u
->ReqStr
.FileName
+ Len
);
638 CopyMem (Ptr
, Mode
, sizeof (Mode
));
639 Ptr
+= sizeof (Mode
);
641 if (Options
& BKSZOP
) {
642 CopyMem (Ptr
, BlockSizeOp
, sizeof (BlockSizeOp
));
643 UtoA10 (*PacketSizePtr
, Ptr
+ sizeof (BlockSizeOp
));
645 TotalLen
+= (Len
= 1 + AsciiStrLen ((CHAR8
*)Ptr
+ sizeof (BlockSizeOp
)) + sizeof (BlockSizeOp
));
650 if (Options
& TSIZEOP
) {
651 CopyMem (Ptr
, TsizeOp
, sizeof (TsizeOp
));
652 CopyMem (Ptr
+ sizeof (TsizeOp
), "0", 2);
653 TotalLen
+= sizeof (TsizeOp
) + 2;
654 Ptr
+= sizeof (TsizeOp
) + 2;
657 if (Options
& OVERWRITEOP
) {
658 CopyMem (Ptr
, OverwriteOp
, sizeof (OverwriteOp
));
659 CopyMem (Ptr
+ sizeof (OverwriteOp
), "1", 2);
660 TotalLen
+= sizeof (OverwriteOp
) + 2;
661 Ptr
+= sizeof (OverwriteOp
) + 2;
664 if (Options
& BIGBLKNUMOP
) {
665 CopyMem (Ptr
, BigBlkNumOp
, sizeof (BigBlkNumOp
));
666 CopyMem (Ptr
+ sizeof (BigBlkNumOp
), "8", 2);
667 TotalLen
+= sizeof (BigBlkNumOp
) + 2;
668 Ptr
+= sizeof (BigBlkNumOp
) + 2;
688 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
694 PXE_BASECODE_DEVICE
*Private
,
696 UINTN
*PacketSizePtr
,
699 EFI_IP_ADDRESS
*ServerIpPtr
,
700 EFI_PXE_BASE_CODE_UDP_PORT
*ServerPortPtr
,
701 EFI_PXE_BASE_CODE_UDP_PORT
*ServerReplyPortPtr
,
702 EFI_PXE_BASE_CODE_UDP_PORT
*OurPortPtr
,
708 Start TFTP session. Issue request and wait for response.
709 Retry three times on error. If failed using options,
710 retry three times w/o options on error.
713 Req := TFTP request type
714 Options := TFTP option bits
715 Private := Pointer to PxeBc interface
717 PacketSizePtr := Pointer to block size
720 ServerIpPtr := Pointer to TFTP server IP address
721 ServerPortPtr := Pointer to TFTP server UDP port
722 ServerReplyPortPtr :=
723 OurPortPtr := Pointer to TFTP client UDP Port
724 FilenamePtr := Pointer to file or directory name
735 SaveReplyLen
= *ReplyLenPtr
;
737 Private
->BigBlkNumFlag
= FALSE
;
743 if (*OurPortPtr
!= 0) {
744 if (++ *OurPortPtr
== 0) {
745 *OurPortPtr
= PXE_RND_PORT_LOW
;
749 // send request from our Ip = StationIp
751 if ((Status
= TftpRwReq (
764 "\nTftpRwReqwResp() Exit #1 %xh (%r)",
772 // read reply to our Ip = StationIp
774 *ReplyLenPtr
= SaveReplyLen
;
776 Status
= TftpUdpRead (
778 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
,
788 } while (Status
== EFI_TIMEOUT
&& --Retries
);
790 if (!Options
|| Status
!= EFI_TFTP_ERROR
) {
793 "\nTftpRwReqwResp() Exit #2 %xh (%r)",
800 Status
= TftpRwReqwResp (
816 DEBUG ((EFI_D_WARN
, "\nTftpRwReqwResp() Exit #3 %xh (%r)", Status
, Status
));
821 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
825 // read on mcast ip, cport, from sport, for data packet
826 // returns success if gets multicast last packet or all up to last block
827 // if not missing, then finished
832 PXE_BASECODE_DEVICE
*Private
,
833 UINT64
*BufferSizePtr
,
835 EFI_IP_ADDRESS
*ServerIpPtr
,
836 EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
,
837 UINT64
*StartBlockPtr
,
840 UINT16 ListenTimeout
,
842 IN BOOLEAN DontUseBuffer
846 Listen for MTFTP traffic and save desired packets.
849 Private := Pointer to PxeBc interface
852 ServerIpPtr := Pointer to TFTP server IP address
853 MtftpInfoPtr := Pointer to MTFTP session information
854 StartBlockPtr := IN=first block we are looking for OUT=first block received
855 NumMissedPtr := Number of blocks missed
859 DontUseBuffer := TRUE == throw packets away, just count bytes
865 struct Tftpv4Ack Header
;
876 LastBlockNum
= *StartBlockPtr
;
877 Timeout
= ListenTimeout
;
880 BufferSize
= *BufferSizePtr
;
881 ReplyLen
= MAX_TFTP_PKT_SIZE
;;
887 if ((SaveReplyLen
= ReplyLen
) > BufferSize
) {
888 SaveReplyLen
= (UINTN
) BufferSize
;
891 /* %%TBD - add big block number support */
894 // get data - loop on resends
897 ReplyLen
= SaveReplyLen
;
899 if ((Status
= TftpUdpRead (
906 &MtftpInfoPtr
->SPort
,
907 &MtftpInfoPtr
->MCastIp
,
908 &MtftpInfoPtr
->CPort
,
914 // make sure a data packet
916 if (Header
.OpCode
!= HTONS (TFTP_DATA
)) {
917 return EFI_PROTOCOL_ERROR
;
919 } while ((BlockNum
= NTOHS (Header
.BlockNum
)) == LastBlockNum
);
922 // make sure still going up
924 if (LastBlockNum
> BlockNum
) {
925 return EFI_PROTOCOL_ERROR
;
928 if (BlockNum
- LastBlockNum
> 0xFFFFFFFF) {
929 return EFI_PROTOCOL_ERROR
;
931 NumMissed
= (UINTN
) (BlockNum
- LastBlockNum
- 1);
934 LastBlockNum
= BlockNum
;
937 // if first time through, some reinitialization
940 *StartBlockPtr
= BlockNum
;
941 PacketSize
= ReplyLen
;
942 Timeout
= TransTimeout
;
944 *NumMissedPtr
= (UINT16
) (*NumMissedPtr
+ NumMissed
);
947 // if missed packets, update start block,
948 // etc. and move packet to proper place in buffer
951 *StartBlockPtr
= BlockNum
;
952 if (!DontUseBuffer
) {
953 Offset
= NumMissed
* PacketSize
;
954 CopyMem (BufferPtr
+ Offset
, BufferPtr
, ReplyLen
);
956 BufferSize
-= Offset
;
960 if (!DontUseBuffer
) {
961 BufferPtr
+= ReplyLen
;
962 BufferSize
-= ReplyLen
;
964 } while (ReplyLen
== PacketSize
&& BlockNum
!= FinalBlock
);
966 *BufferSizePtr
= BufferSize
;
971 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
975 PXE_BASECODE_DEVICE
* Private
,
976 UINT64
*BufferSizePtr
,
978 UINTN
*PacketSizePtr
,
979 EFI_IP_ADDRESS
* ServerIpPtr
,
981 EFI_PXE_BASE_CODE_MTFTP_INFO
* MtftpInfoPtr
,
982 UINT8
*CompletionStatusPtr
,
985 IN BOOLEAN DontUseBuffer
992 Private := Pointer to PxeBc interface
993 BufferSizePtr := IN=buffer size OUT=transfer size
999 CompletionStatusPtr :=
1003 // mtftp open session
1004 // return code EFI_SUCCESS
1005 // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
1006 // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
1007 // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
1008 // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
1012 EFI_IP_ADDRESS OurReplyIp
;
1013 struct Tftpv4Ack Header
;
1019 Retries
= NUM_MTFTP_OPEN_RETRIES
;
1020 BufferPtr2
= BufferPtr
;
1021 *PacketSizePtr
= (UINTN
) (EFI_MIN (*BufferSizePtr
, MAX_TFTP_PKT_SIZE
));
1025 // send a read request
1027 *CompletionStatusPtr
= 0;
1029 if ((Status
= TftpRwReq (
1034 &MtftpInfoPtr
->SPort
,
1035 &MtftpInfoPtr
->CPort
,
1039 )) != EFI_SUCCESS
) {
1047 ZeroMem (&OurReplyIp
, Private
->IpLength
);
1048 ReplyLen
= *PacketSizePtr
;
1050 if ((Status
= TftpUdpRead (
1052 EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
,
1054 (UINTN
*) &ReplyLen
,
1057 &MtftpInfoPtr
->SPort
,
1059 &MtftpInfoPtr
->CPort
,
1060 MtftpInfoPtr
->TransmitTimeout
1061 )) == EFI_SUCCESS
) {
1063 // check for first data packet
1065 if (Header
.OpCode
!= HTONS (TFTP_DATA
)) {
1066 return EFI_PROTOCOL_ERROR
;
1071 if (Header
.BlockNum
!= HTONS (1)) {
1074 // if we are not the primary client,
1075 // we probably got first and now second
1076 // multicast but no unicast, so
1077 // *CompletionStatusPtr = GOTMULTI - if this is
1078 // the second, can just go on to listen
1079 // starting with 2 as the last block
1082 if (Header
.BlockNum
!= HTONS (2)) {
1086 *CompletionStatusPtr
= 0;
1095 *PacketSizePtr
= ReplyLen
;
1097 // see if a unicast data packet
1101 &Private
->EfiBc
.Mode
->StationIp
,
1104 *CompletionStatusPtr
|= GOTUNI
;
1107 // if already got multicast packet,
1110 if (*CompletionStatusPtr
& GOTMULTI
) {
1113 } else if (!CompareMem (
1115 &MtftpInfoPtr
->MCastIp
,
1119 // otherwise see if a multicast data packet
1121 *CompletionStatusPtr
|= GOTMULTI
;
1124 // got first - bump pointer so that if
1125 // second multi comes along, we're OK
1127 if (!DontUseBuffer
) {
1128 BufferPtr2
= (UINT8
*) BufferPtr
+ ReplyLen
;
1131 // if already got unicast packet,
1134 if (*CompletionStatusPtr
& GOTUNI
) {
1139 // else protocol error
1141 return EFI_PROTOCOL_ERROR
;
1143 } else if (Status
== EFI_TIMEOUT
) {
1145 // bad return code - if timed out, retry
1150 // else just bad - failed MTFTP open
1155 } while (Status
== EFI_TIMEOUT
&& --Retries
);
1157 if (Status
!= EFI_SUCCESS
) {
1164 // got em both - go into receive mode
1165 // routine to read rest of file after a successful open (TFTP or MTFTP)
1166 // sends ACK and gets next data packet until short packet arrives,
1167 // then sends ACK and (hopefully) times out
1169 return LockStepReceive (
1176 &MtftpInfoPtr
->SPort
,
1177 &MtftpInfoPtr
->MCastIp
,
1178 &MtftpInfoPtr
->CPort
,
1180 MtftpInfoPtr
->TransmitTimeout
,
1185 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1189 PXE_BASECODE_DEVICE
*Private
,
1190 UINT64
*BufferSizePtr
,
1192 EFI_IP_ADDRESS
*ServerIpPtr
,
1194 EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
,
1195 IN BOOLEAN DontUseBuffer
1198 Routine description:
1202 // if did not get any packets, try MTFTP open
1203 // if got all packets, return
1204 // compute listen timeout and loop
1207 Private := Pointer to PxeBc interface
1218 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
1222 UINT64 LastStartBlock
;
1226 UINT16 TransTimeout
;
1227 UINT16 ListenTimeout
;
1228 UINT8
*BufferPtrLocal
;
1230 TransTimeout
= MtftpInfoPtr
->TransmitTimeout
;
1231 ListenTimeout
= MtftpInfoPtr
->ListenTimeout
;
1236 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
;
1238 CopyMem (&Filter
.IpList
[0], &Private
->EfiBc
.Mode
->StationIp
, sizeof (EFI_IP_ADDRESS
));
1239 CopyMem (&Filter
.IpList
[1], &MtftpInfoPtr
->MCastIp
, sizeof (EFI_IP_ADDRESS
));
1241 if ((Status
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
1246 StartBlock
= LastStartBlock
;
1247 BufferSize
= *BufferSizePtr
- Offset
;
1249 if (DontUseBuffer
) {
1251 // overwrie the temp buf
1253 BufferPtrLocal
= BufferPtr
;
1255 BufferPtrLocal
= BufferPtr
+ Offset
;
1259 if (((Status
= MtftpListen (
1271 )) != EFI_SUCCESS
) && (Status
!= EFI_TIMEOUT
)) {
1278 // if none were received, start block is not reset
1280 if (StartBlock
== LastStartBlock
) {
1284 // timed out with none received - try MTFTP open
1286 if ((Status
= MtftpOpen (
1296 )) != EFI_SUCCESS
) {
1298 // open failure - try TFTP
1303 // return code EFI_SUCCESS
1304 // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
1305 // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
1306 // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
1307 // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
1309 if (CompStat
== (GOTUNI
| GOTMULTI
)) {
1311 // finished - got it all
1318 // offset is two packet lengths
1322 // last block received
1330 ListenTimeout
= TransTimeout
;
1334 // did we get the last block
1336 if (Status
== EFI_SUCCESS
) {
1338 // yes - set the file size if this was first time
1341 *BufferSizePtr
-= BufferSize
;
1344 // if buffer was too small, finished
1346 if (!DontUseBuffer
) {
1347 return EFI_BUFFER_TOO_SMALL
;
1350 // if we got them all, finished
1352 if (!NumMissed
&& StartBlock
== LastStartBlock
+ 1) {
1356 // did not get them all - set last block
1358 LastBlock
= (UINT16
) (StartBlock
- 1);
1361 // compute listen timeout
1363 ListenTimeout
= (UINT16
) ((NumMissed
> MtftpInfoPtr
->ListenTimeout
) ? 0 : (MtftpInfoPtr
->ListenTimeout
- NumMissed
));
1373 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1377 PXE_BASECODE_DEVICE
*Private
,
1378 UINT64
*BufferSizePtr
,
1379 EFI_IP_ADDRESS
*ServerIpPtr
,
1380 EFI_PXE_BASE_CODE_UDP_PORT SrvPort
,
1382 UINTN
*PacketSizePtr
1385 Routine description:
1386 // TFTP info request routine
1387 // send read request with block size and transfer size options
1389 // send error to terminate session
1390 // if OACK received, set info
1403 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1404 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1412 struct Tftpv4Oack OAck2Ptr
;
1413 struct Tftpv4Ack Ack2Ptr
;
1414 struct Tftpv4Data Datastr
;
1418 ServerReplyPort
= 0;
1419 ReplyLen
= sizeof (u
.Datastr
.Data
);
1422 // send a write request with the blocksize option -
1423 // sets our IP and port - and receive reply - sets his port
1424 // will retry operation up to 3 times if no response,
1425 // and will retry without options on an error reply
1427 if ((Status
= TftpRwReqwResp (
1429 /* BIGBLKNUMOP | */BKSZOP
| TSIZEOP
,
1441 )) != EFI_SUCCESS
) {
1442 DEBUG ((EFI_D_WARN
, "\nTftpInfo() Exit #1"));
1446 // check for good OACK
1448 if (u
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1450 // now parse it for options
1455 sizeof (BigBlkNumOp
),
1456 u
.OAck2Ptr
.OpAck
[0].Option
,
1457 ReplyLen
+ sizeof (u
.Ack2Ptr
.BlockNum
)
1461 if (AtoU (Ptr
) == 8) {
1462 Private
->BigBlkNumFlag
= TRUE
;
1464 return EFI_PROTOCOL_ERROR
;
1472 sizeof (BlockSizeOp
),
1473 u
.OAck2Ptr
.OpAck
[0].Option
,
1474 ReplyLen
+= sizeof (u
.Ack2Ptr
.BlockNum
)
1477 *PacketSizePtr
= (Ptr
) ? AtoU (Ptr
) : 512;
1485 u
.OAck2Ptr
.OpAck
[0].Option
,
1490 *BufferSizePtr
= AtoU64 (Ptr
);
1493 // teminate session with error
1495 SendError (Private
, ServerIpPtr
, &ServerReplyPort
, &OurPort
);
1504 // if MTFTP get filesize, return unsupported
1506 if (SrvPort
!= TftpRequestPort
) {
1507 SendError (Private
, ServerIpPtr
, &ServerReplyPort
, &OurPort
);
1508 DEBUG ((EFI_D_WARN
, "\nTftpInfo() Exit #3"));
1509 return EFI_UNSUPPORTED
;
1514 // last block received
1519 // does not support the option - do a download with no buffer
1523 Status
= LockStepReceive (
1531 &Private
->EfiBc
.Mode
->StationIp
,
1538 if (Status
!= EFI_SUCCESS
) {
1539 DEBUG ((EFI_D_WARN
, "\nTftpInfo() LockStepReceive() == %Xh", Status
));
1542 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1549 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1553 PXE_BASECODE_DEVICE
*Private
,
1554 UINT64
*BufferSizePtr
,
1556 EFI_IP_ADDRESS
*ServerIpPtr
,
1558 UINTN
*PacketSizePtr
,
1559 EFI_PXE_BASE_CODE_UDP_PORT SrvPort
,
1561 IN BOOLEAN DontUseBuffer
1564 Routine description:
1565 // tftp read session
1566 // send read request
1572 // while data size is max
1588 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1589 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1597 struct Tftpv4Ack Ack2Ptr
;
1598 struct Tftpv4Oack OAck2Ptr
;
1599 struct Tftpv4Data Data
;
1600 struct Tftpv4Ack8 Ack8Ptr
;
1601 struct Tftpv4Data8 Data8
;
1605 ServerReplyPort
= 0;
1606 ReplyLen
= (UINTN
) ((*BufferSizePtr
> 0xFFFF) ? 0xFFFF : *BufferSizePtr
);
1609 // send a read request with the blocksize option - sets our IP and port
1610 // - and receive reply - sets his port will retry operation up to 3
1611 // times if no response, and will retry without options on an error
1614 if ((Status
= TftpRwReqwResp (
1616 /* BIGBLKNUMOP | */BKSZOP
,
1628 )) != EFI_SUCCESS
) {
1629 DEBUG ((EFI_D_WARN
, "\nTftpDownload() Exit #1 %xh (%r)", Status
, Status
));
1635 if (U
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1639 CopyMem (U
.Data
.Data
, BufferPtr
, ReplyLen
);
1643 sizeof (BigBlkNumOp
),
1644 U
.OAck2Ptr
.OpAck
[0].Option
,
1645 ReplyLen
+ sizeof (U
.Ack2Ptr
.BlockNum
)
1649 if (AtoU (Ptr
) == 8) {
1650 Private
->BigBlkNumFlag
= TRUE
;
1652 return EFI_PROTOCOL_ERROR
;
1656 // now parse it for blocksize option
1660 sizeof (BlockSizeOp
),
1661 U
.OAck2Ptr
.OpAck
[0].Option
,
1662 ReplyLen
+= sizeof (U
.Ack2Ptr
.BlockNum
)
1665 ReplyLen
= (Ptr
!= NULL
) ? AtoU (Ptr
) : 512;
1669 // last block received
1672 } else if (U
.Ack2Ptr
.OpCode
!= HTONS (TFTP_DATA
) || U
.Ack2Ptr
.BlockNum
!= HTONS (1)) {
1676 DEBUG ((EFI_D_WARN
, "\nTftpDownload() Exit #2 %xh (%r)", Status
, Status
));
1678 return EFI_PROTOCOL_ERROR
;
1681 // got good data packet
1685 // last block received
1690 if (PacketSizePtr
!= NULL
) {
1691 *PacketSizePtr
= ReplyLen
;
1694 // routine to read rest of file after a successful open (TFTP or MTFTP)
1695 // sends ACK and gets next data packet until short packet arrives, then sends
1696 // ACK and (hopefully) times out
1697 // if first packet has been read, BufferPtr and BufferSize must reflect fact
1699 Status
= LockStepReceive (
1707 &Private
->EfiBc
.Mode
->StationIp
,
1714 if (Status
!= EFI_SUCCESS
) {
1715 DEBUG ((EFI_D_WARN
, "\nTftpDownload() Exit #3 %xh (%r)", Status
, Status
));
1717 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1727 if (!EFI_ERROR (Status
)) {
1728 Status
= EFI_BUFFER_TOO_SMALL
;
1736 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1740 PXE_BASECODE_DEVICE
*Private
,
1741 UINT64
*BufferSizePtr
,
1743 EFI_IP_ADDRESS
*ServerIpPtr
,
1745 UINTN
*PacketSizePtr
,
1749 Routine description:
1750 // tftp write session
1751 // send write request
1754 // send min (rest of data, max data packet)
1756 // while data size is max
1770 struct Tftpv4Ack Header
;
1771 EFI_PXE_BASE_CODE_UDP_PORT OurPort
;
1772 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort
;
1775 UINT64 TransferSize
;
1782 struct Tftpv4Oack OAck2Ptr
;
1783 struct Tftpv4Ack Ack2Ptr
;
1784 struct Tftpv4Data Datastr
;
1788 ServerReplyPort
= 0;
1789 TransferSize
= *BufferSizePtr
;
1790 ReplyLen
= sizeof (u
.Datastr
.Data
);
1791 Options
= (UINT16
) ((Overwrite
) ? OVERWRITEOP
| BKSZOP
: BKSZOP
);
1794 // send a write request with the blocksize option - sets our IP and port -
1795 // and receive reply - sets his port
1796 // will retry operation up to 3 times if no response, and will retry without
1797 // options on an error reply
1799 if ((Status
= TftpRwReqwResp (
1813 )) != EFI_SUCCESS
) {
1819 if (u
.OAck2Ptr
.OpCode
== HTONS (TFTP_OACK
)) {
1821 // parse it for blocksize option
1825 sizeof (BlockSizeOp
),
1826 u
.OAck2Ptr
.OpAck
[0].Option
,
1827 ReplyLen
+= sizeof (u
.Ack2Ptr
.BlockNum
)
1829 *PacketSizePtr
= (Ptr
) ? AtoU (Ptr
) : 512;
1834 else if (u
.Ack2Ptr
.OpCode
== HTONS (TFTP_ACK
)) {
1836 // option was not supported
1838 *PacketSizePtr
= 512;
1840 return EFI_PROTOCOL_ERROR
;
1845 Header
.OpCode
= HTONS (TFTP_DATA
);
1847 Header
.BlockNum
= HTONS (1);
1853 Retries
= NUM_ACK_RETRIES
;
1854 HeaderSize
= sizeof (Header
);
1855 TransferLen
= (UINTN
) (EFI_MIN (*PacketSizePtr
, TransferSize
));
1858 // write a data packet and get an ack
1864 if ((Status
= UdpWrite (
1866 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT
,
1876 )) != EFI_SUCCESS
) {
1882 ReplyLen
= sizeof (u
.Datastr
.Data
);
1884 if ((Status
= TftpUdpRead (
1895 )) == EFI_SUCCESS
) {
1897 // check for ACK for this data packet
1899 if (u
.Ack2Ptr
.OpCode
!= HTONS (TFTP_ACK
)) {
1900 return EFI_PROTOCOL_ERROR
;
1903 if (u
.Ack2Ptr
.BlockNum
!= Header
.BlockNum
) {
1905 // not for this packet - continue
1907 Status
= EFI_TIMEOUT
;
1910 } while (Status
== EFI_TIMEOUT
&& --Retries
);
1912 if (Status
!= EFI_SUCCESS
) {
1916 BufferPtr
= (VOID
*) ((UINT8
*) (BufferPtr
) + TransferLen
);
1917 TransferSize
-= TransferLen
;
1919 Header
.BlockNum
= HTONS ((UINT16
) BlockNum
);
1920 } while (TransferLen
== *PacketSizePtr
);
1925 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1929 PXE_BASECODE_DEVICE
*Private
,
1930 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation
,
1931 UINT64
*BufferSizePtr
,
1933 EFI_IP_ADDRESS
*ServerIpPtr
,
1935 UINTN
*PacketSizePtr
,
1936 IN EFI_PXE_BASE_CODE_MTFTP_INFO
*MtftpInfoPtr
, OPTIONAL
1937 IN BOOLEAN Overwrite
,
1938 IN BOOLEAN DontUseBuffer
1941 Routine description:
1942 MTFTP API entry point
1957 * EFI_INVALID_PARAMETER
1958 * EFI_OUT_OF_RESOURCES
1959 * EFI_BAD_BUFFER_SIZE
1960 * Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(),
1961 * TftpDownload() and TftpUpload().
1964 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
1965 EFI_STATUS StatCode
;
1966 UINT64 BufferSizeLocal
;
1968 UINT8
*BufferPtrLocal
;
1970 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
;
1972 Filter
.reserved
= 0;
1974 /* No error has occurred, yet. */
1975 Private
->EfiBc
.Mode
->TftpErrorReceived
= FALSE
;
1977 /* We must at least have an MTFTP server IP address and
1978 * a pointer to the buffer size.
1980 if (!ServerIpPtr
|| !BufferSizePtr
) {
1981 DEBUG ((EFI_D_WARN
, "\nPxeBcMtftp() Exit #1"));
1983 return EFI_INVALID_PARAMETER
;
1986 Private
->Function
= EFI_PXE_BASE_CODE_FUNCTION_MTFTP
;
1989 // make sure filter set to unicast at start
1991 if ((StatCode
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
1994 "\nPxeBcMtftp() Exit IpFilter() == %Xh",
2001 // set unset parms to default values
2003 if (!PacketSizePtr
) {
2004 *(PacketSizePtr
= &PacketSize
) = MAX_TFTP_PKT_SIZE
;
2007 if (*PacketSizePtr
> *BufferSizePtr
) {
2008 *PacketSizePtr
= (UINTN
) *BufferSizePtr
;
2011 if (*PacketSizePtr
< MIN_TFTP_PKT_SIZE
) {
2012 *PacketSizePtr
= MIN_TFTP_PKT_SIZE
;
2015 if (*PacketSizePtr
> BUFFER_ALLOCATE_SIZE
) {
2016 *PacketSizePtr
= BUFFER_ALLOCATE_SIZE
;
2019 if (*PacketSizePtr
> MAX_TFTP_PKT_SIZE
) {
2020 *PacketSizePtr
= MAX_TFTP_PKT_SIZE
;
2023 if (Operation
== EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
) {
2024 StatCode
= TftpInfo (
2033 if (StatCode
!= EFI_SUCCESS
) {
2036 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
2044 if (Operation
== EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE
) {
2045 if (!MtftpInfoPtr
|| !MtftpInfoPtr
->SPort
) {
2046 DEBUG ((EFI_D_WARN
, "\nPxeBcMtftp() Exit #2"));
2047 return EFI_INVALID_PARAMETER
;
2049 StatCode
= TftpInfo (
2053 MtftpInfoPtr
->SPort
,
2060 if (StatCode
!= EFI_SUCCESS
) {
2063 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
2072 if (!BufferPtr
&& !DontUseBuffer
) {
2074 // if dontusebuffer is false and no buffer???
2076 DEBUG ((EFI_D_WARN
, "\nPxeBcMtftp() Exit #3"));
2078 // DontUseBuffer can be true only for read_file operation
2080 return EFI_INVALID_PARAMETER
;
2083 if (DontUseBuffer
) {
2084 BufferPtrLocal
= AllocatePool (BUFFER_ALLOCATE_SIZE
);
2085 if (BufferPtrLocal
== NULL
) {
2086 DEBUG ((EFI_D_NET
, "\nPxeBcMtftp() Exit #4"));
2087 return EFI_OUT_OF_RESOURCES
;
2090 BufferSizeLocal
= BUFFER_ALLOCATE_SIZE
;
2092 if (!*BufferSizePtr
&& Operation
!= EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
) {
2093 DEBUG ((EFI_D_WARN
, "\nPxeBcMtftp() Exit #5"));
2094 return EFI_BAD_BUFFER_SIZE
;
2097 BufferPtrLocal
= BufferPtr
;
2098 BufferSizeLocal
= *BufferSizePtr
;
2101 switch (Operation
) {
2102 case EFI_PXE_BASE_CODE_MTFTP_READ_FILE
:
2103 if (FilenamePtr
== NULL
||
2104 MtftpInfoPtr
== NULL
||
2105 MtftpInfoPtr
->MCastIp
.Addr
[0] == 0 ||
2106 MtftpInfoPtr
->SPort
== 0 ||
2107 MtftpInfoPtr
->CPort
== 0 ||
2108 MtftpInfoPtr
->ListenTimeout
== 0 ||
2109 MtftpInfoPtr
->TransmitTimeout
== 0
2111 StatCode
= EFI_INVALID_PARAMETER
;
2115 // try MTFTP - if fails, drop into TFTP read
2117 if ((StatCode
= MtftpDownload (
2125 )) == EFI_SUCCESS
|| StatCode
== EFI_BUFFER_TOO_SMALL
) {
2126 if (BufferSizePtr
/* %% !DontUseBuffer */ ) {
2127 *BufferSizePtr
= BufferSizeLocal
;
2133 // go back to unicast
2135 if ((StatCode
= IpFilter (Private
, &Filter
)) != EFI_SUCCESS
) {
2140 case EFI_PXE_BASE_CODE_TFTP_READ_FILE
:
2141 if (FilenamePtr
== NULL
) {
2142 StatCode
= EFI_INVALID_PARAMETER
;
2146 StatCode
= TftpDownload (
2158 if (StatCode
== EFI_SUCCESS
|| StatCode
== EFI_BUFFER_TOO_SMALL
) {
2159 if (BufferSizePtr
/* !DontUseBuffer */ ) {
2160 *BufferSizePtr
= BufferSizeLocal
;
2166 case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
:
2167 if (FilenamePtr
== NULL
|| DontUseBuffer
) {
2169 // not a valid option
2171 StatCode
= EFI_INVALID_PARAMETER
;
2175 StatCode
= TftpUpload (
2185 if (StatCode
!= EFI_SUCCESS
) {
2188 "\nPxeBcMtftp() Exit #6 %xh (%r)",
2196 case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY
:
2197 if (FilenamePtr
== NULL
|| DontUseBuffer
) {
2199 // not a valid option
2201 StatCode
= EFI_INVALID_PARAMETER
;
2205 StatCode
= TftpDownload (
2217 if (StatCode
!= EFI_SUCCESS
) {
2220 "\nPxeBcMtftp() Exit #7 %xh (%r)",
2228 case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY
:
2229 if (DontUseBuffer
) {
2230 StatCode
= EFI_INVALID_PARAMETER
;
2234 if (MtftpInfoPtr
== NULL
|| !MtftpInfoPtr
->SPort
) {
2237 "\nPxeBcMtftp() Exit #9 %xh (%r)",
2238 EFI_INVALID_PARAMETER
,
2239 EFI_INVALID_PARAMETER
)
2242 return EFI_INVALID_PARAMETER
;
2245 StatCode
= TftpDownload (
2252 MtftpInfoPtr
->SPort
,
2260 StatCode
= EFI_INVALID_PARAMETER
;
2263 if (DontUseBuffer
) {
2264 FreePool (BufferPtrLocal
);
2267 if (StatCode
!= EFI_SUCCESS
) {
2270 "\nPxeBcMtftp() Exit #8 %xh (%r)",
2281 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2285 IN EFI_PXE_BASE_CODE_PROTOCOL
* This
,
2286 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation
,
2287 IN OUT VOID
*BufferPtr
,
2288 IN BOOLEAN Overwrite
,
2289 IN OUT UINT64
*BufferSizePtr
,
2290 IN UINTN
*BlockSizePtr OPTIONAL
,
2291 IN EFI_IP_ADDRESS
* ServerIpPtr
,
2292 IN UINT8
*FilenamePtr
,
2293 IN EFI_PXE_BASE_CODE_MTFTP_INFO
* MtftpInfoPtr OPTIONAL
,
2294 IN BOOLEAN DontUseBuffer
2297 Routine description:
2298 MTFTP API entry point.
2313 * EFI_INVALID_PARAMETER
2314 * Status is also returned from PxeBcMtftp();
2317 EFI_PXE_BASE_CODE_IP_FILTER Filter
;
2318 EFI_STATUS StatCode
;
2319 PXE_BASECODE_DEVICE
*Private
;
2322 // Lock the instance data and make sure started
2324 StatCode
= EFI_SUCCESS
;
2327 DEBUG ((EFI_D_ERROR
, "BC *This pointer == NULL"));
2328 return EFI_INVALID_PARAMETER
;
2331 Private
= CR (This
, PXE_BASECODE_DEVICE
, EfiBc
, PXE_BASECODE_DEVICE_SIGNATURE
);
2333 if (Private
== NULL
) {
2334 DEBUG ((EFI_D_ERROR
, "PXE_BASECODE_DEVICE poiner == NULL"));
2335 return EFI_INVALID_PARAMETER
;
2338 EfiAcquireLock (&Private
->Lock
);
2340 if (This
->Mode
== NULL
|| !This
->Mode
->Started
) {
2341 DEBUG ((EFI_D_ERROR
, "BC was not started."));
2342 EfiReleaseLock (&Private
->Lock
);
2343 return EFI_NOT_STARTED
;
2348 Filter
.Filters
= EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
;
2350 Filter
.reserved
= 0;
2352 DEBUG ((EFI_D_WARN
, "\nBcMtftp() Op=%d Buf=%Xh", Operation
, BufferPtr
));
2354 StatCode
= PxeBcMtftp (
2368 // restore to unicast
2370 IpFilter (Private
, &Filter
);
2373 // Unlock the instance data
2375 EfiReleaseLock (&Private
->Lock
);
2379 /* eof - PxeBcMtftp.c */