2 Routines to process Wrq (upload).
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php<BR>
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "Mtftp4Impl.h"
20 Build then send a MTFTP data packet for the MTFTP upload session.
22 @param Instance The MTFTP upload session.
23 @param BlockNum The block number to send.
25 @retval EFI_OUT_OF_RESOURCES Failed to build the packet.
26 @retval EFI_ABORTED The consumer of this child directs to abort the
27 transmission by return an error through PacketNeeded.
28 @retval EFI_SUCCESS The data is sent.
33 IN OUT MTFTP4_PROTOCOL
*Instance
,
37 EFI_MTFTP4_PACKET
*Packet
;
38 EFI_MTFTP4_TOKEN
*Token
;
46 // Allocate a buffer to hold the user data
48 UdpPacket
= NetbufAlloc (Instance
->BlkSize
+ MTFTP4_DATA_HEAD_LEN
);
50 if (UdpPacket
== NULL
) {
51 return EFI_OUT_OF_RESOURCES
;
54 Packet
= (EFI_MTFTP4_PACKET
*) NetbufAllocSpace (UdpPacket
, MTFTP4_DATA_HEAD_LEN
, FALSE
);
55 ASSERT (Packet
!= NULL
);
57 Packet
->Data
.OpCode
= HTONS (EFI_MTFTP4_OPCODE_DATA
);
58 Packet
->Data
.Block
= HTONS (BlockNum
);
61 // Read the block from either the buffer or PacketNeeded callback
63 Token
= Instance
->Token
;
64 DataLen
= Instance
->BlkSize
;
66 if (Token
->Buffer
!= NULL
) {
67 Start
= MultU64x32 (BlockNum
- 1, Instance
->BlkSize
);
69 if (Token
->BufferSize
< Start
+ Instance
->BlkSize
) {
70 DataLen
= (UINT16
) (Token
->BufferSize
- Start
);
71 Instance
->LastBlock
= BlockNum
;
72 Mtftp4SetLastBlockNum (&Instance
->Blocks
, BlockNum
);
76 NetbufAllocSpace (UdpPacket
, DataLen
, FALSE
);
77 CopyMem (Packet
->Data
.Data
, (UINT8
*) Token
->Buffer
+ Start
, DataLen
);
82 // Get data from PacketNeeded
85 Status
= Token
->PacketNeeded (
92 if (EFI_ERROR (Status
) || (DataLen
> Instance
->BlkSize
)) {
93 if (DataBuf
!= NULL
) {
97 if (UdpPacket
!= NULL
) {
98 NetbufFree (UdpPacket
);
103 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
104 (UINT8
*) "User aborted the transfer"
110 if (DataLen
< Instance
->BlkSize
) {
111 Instance
->LastBlock
= BlockNum
;
112 Mtftp4SetLastBlockNum (&Instance
->Blocks
, BlockNum
);
116 NetbufAllocSpace (UdpPacket
, DataLen
, FALSE
);
117 CopyMem (Packet
->Data
.Data
, DataBuf
, DataLen
);
122 return Mtftp4SendPacket (Instance
, UdpPacket
);
127 Function to handle received ACK packet.
129 If the ACK number matches the expected block number, and there are more
130 data pending, send the next block. Otherwise tell the caller that we are done.
132 @param Instance The MTFTP upload session
133 @param Packet The MTFTP packet received
134 @param Len The packet length
135 @param Completed Return whether the upload has finished.
137 @retval EFI_SUCCESS The ACK is successfully processed.
138 @retval EFI_TFTP_ERROR The block number loops back.
139 @retval Others Failed to transmit the next data packet.
144 IN MTFTP4_PROTOCOL
*Instance
,
145 IN EFI_MTFTP4_PACKET
*Packet
,
147 OUT BOOLEAN
*Completed
155 AckNum
= NTOHS (Packet
->Ack
.Block
[0]);
156 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
158 ASSERT (Expected
>= 0);
161 // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp4WrqInput
164 if (Expected
!= AckNum
) {
169 // Remove the acked block number, if this is the last block number,
170 // tell the Mtftp4WrqInput to finish the transfer. This is the last
171 // block number if the block range are empty..
173 Mtftp4RemoveBlockNum (&Instance
->Blocks
, AckNum
, *Completed
,&TotalBlock
);
175 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
180 // The block range is empty. It may either because the the last
181 // block has been ACKed, or the sequence number just looped back,
182 // that is, there is more than 0xffff blocks.
184 if (Instance
->LastBlock
== AckNum
) {
185 ASSERT (Instance
->LastBlock
>= 1);
192 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
193 (UINT8
*) "Block number rolls back, not supported, try blksize option"
196 return EFI_TFTP_ERROR
;
200 return Mtftp4WrqSendBlock (Instance
, (UINT16
) Expected
);
205 Check whether the received OACK is valid.
207 The OACK is valid only if:
208 1. It only include options requested by us
209 2. It can only include a smaller block size
210 3. It can't change the proposed time out value.
211 4. Other requirements of the individal MTFTP options as required.
213 @param Reply The options included in the OACK
214 @param Request The options we requested
216 @retval TRUE The options included in OACK is valid.
217 @retval FALSE The options included in OACK is invalid.
222 IN MTFTP4_OPTION
*Reply
,
223 IN MTFTP4_OPTION
*Request
227 // It is invalid for server to return options we don't request
229 if ((Reply
->Exist
& ~Request
->Exist
) != 0) {
234 // Server can only specify a smaller block size to be used and
235 // return the timeout matches that requested.
237 if ((((Reply
->Exist
& MTFTP4_BLKSIZE_EXIST
) != 0) && (Reply
->BlkSize
> Request
->BlkSize
)) ||
238 (((Reply
->Exist
& MTFTP4_TIMEOUT_EXIST
) != 0) && (Reply
->Timeout
!= Request
->Timeout
))) {
247 Function to handle the MTFTP OACK packet.
249 It parses the packet's options, and update the internal states of the session.
251 @param Instance The MTFTP session
252 @param Packet The received OACK packet
253 @param Len The length of the packet
254 @param Completed Whether the transmisson has completed. NOT used by
257 @retval EFI_SUCCESS The OACK process is OK
258 @retval EFI_TFTP_ERROR Some error occured, and the session reset.
262 Mtftp4WrqHandleOack (
263 IN OUT MTFTP4_PROTOCOL
*Instance
,
264 IN EFI_MTFTP4_PACKET
*Packet
,
266 OUT BOOLEAN
*Completed
270 EFI_MTFTP4_PACKET Bogus
;
277 // Ignore the OACK if already started the upload
279 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
286 // Parse and validate the options from server
288 ZeroMem (&Reply
, sizeof (MTFTP4_OPTION
));
289 Status
= Mtftp4ParseOptionOack (Packet
, Len
, &Reply
);
291 if (EFI_ERROR (Status
) || !Mtftp4WrqOackValid (&Reply
, &Instance
->RequestOption
)) {
293 // Don't send a MTFTP error packet when out of resource, it can
294 // only make it worse.
296 if (Status
!= EFI_OUT_OF_RESOURCES
) {
299 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
300 (UINT8
*) "Mal-formated OACK packet"
304 return EFI_TFTP_ERROR
;
307 if (Reply
.BlkSize
!= 0) {
308 Instance
->BlkSize
= Reply
.BlkSize
;
311 if (Reply
.Timeout
!= 0) {
312 Instance
->Timeout
= Reply
.Timeout
;
316 // Build a bogus ACK0 packet then pass it to the Mtftp4WrqHandleAck,
317 // which will start the transmission of the first data block.
319 Bogus
.Ack
.OpCode
= HTONS (EFI_MTFTP4_OPCODE_ACK
);
320 Bogus
.Ack
.Block
[0] = 0;
322 Status
= Mtftp4WrqHandleAck (
325 sizeof (EFI_MTFTP4_ACK_HEADER
),
334 The input process routine for MTFTP upload.
336 @param UdpPacket The received MTFTP packet.
337 @param EndPoint The local/remote access point
338 @param IoStatus The result of the packet receiving
339 @param Context Opaque parameter for the callback, which is the
345 IN NET_BUF
*UdpPacket
,
346 IN UDP_END_POINT
*EndPoint
,
347 IN EFI_STATUS IoStatus
,
351 MTFTP4_PROTOCOL
*Instance
;
352 EFI_MTFTP4_PACKET
*Packet
;
358 Instance
= (MTFTP4_PROTOCOL
*) Context
;
359 NET_CHECK_SIGNATURE (Instance
, MTFTP4_PROTOCOL_SIGNATURE
);
363 Status
= EFI_SUCCESS
;
365 if (EFI_ERROR (IoStatus
)) {
370 ASSERT (UdpPacket
!= NULL
);
372 if (UdpPacket
->TotalSize
< MTFTP4_OPCODE_LEN
) {
377 // Client send initial request to server's listening port. Server
378 // will select a UDP port to communicate with the client.
380 if (EndPoint
->RemotePort
!= Instance
->ConnectedPort
) {
381 if (Instance
->ConnectedPort
!= 0) {
384 Instance
->ConnectedPort
= EndPoint
->RemotePort
;
389 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
391 Len
= UdpPacket
->TotalSize
;
393 if (UdpPacket
->BlockOpNum
> 1) {
394 Packet
= AllocatePool (Len
);
396 if (Packet
== NULL
) {
397 Status
= EFI_OUT_OF_RESOURCES
;
401 NetbufCopy (UdpPacket
, 0, Len
, (UINT8
*) Packet
);
404 Packet
= (EFI_MTFTP4_PACKET
*) NetbufGetByte (UdpPacket
, 0, NULL
);
405 ASSERT (Packet
!= NULL
);
408 Opcode
= NTOHS (Packet
->OpCode
);
411 // Call the user's CheckPacket if provided. Abort the transmission
412 // if CheckPacket returns an EFI_ERROR code.
414 if ((Instance
->Token
->CheckPacket
!= NULL
) &&
415 ((Opcode
== EFI_MTFTP4_OPCODE_OACK
) || (Opcode
== EFI_MTFTP4_OPCODE_ERROR
))) {
417 Status
= Instance
->Token
->CheckPacket (
424 if (EFI_ERROR (Status
)) {
426 // Send an error message to the server to inform it
428 if (Opcode
!= EFI_MTFTP4_OPCODE_ERROR
) {
431 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
432 (UINT8
*) "User aborted the transfer"
436 Status
= EFI_ABORTED
;
442 case EFI_MTFTP4_OPCODE_ACK
:
443 if (Len
!= MTFTP4_OPCODE_LEN
+ MTFTP4_BLKNO_LEN
) {
447 Status
= Mtftp4WrqHandleAck (Instance
, Packet
, Len
, &Completed
);
450 case EFI_MTFTP4_OPCODE_OACK
:
451 if (Len
<= MTFTP4_OPCODE_LEN
) {
455 Status
= Mtftp4WrqHandleOack (Instance
, Packet
, Len
, &Completed
);
458 case EFI_MTFTP4_OPCODE_ERROR
:
459 Status
= EFI_TFTP_ERROR
;
468 // Free the resources, then if !EFI_ERROR (Status) and not completed,
469 // restart the receive, otherwise end the session.
471 if ((Packet
!= NULL
) && (UdpPacket
->BlockOpNum
> 1)) {
475 if (UdpPacket
!= NULL
) {
476 NetbufFree (UdpPacket
);
479 if (!EFI_ERROR (Status
) && !Completed
) {
480 Status
= UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4WrqInput
, Instance
, 0);
484 // Status may have been updated by UdpIoRecvDatagram
486 if (EFI_ERROR (Status
) || Completed
) {
487 Mtftp4CleanOperation (Instance
, Status
);
494 Start the MTFTP session for upload.
496 It will first init some states, then send the WRQ request packet,
497 and start receiving the packet.
499 @param Instance The MTFTP session
500 @param Operation Redundant parameter, which is always
501 EFI_MTFTP4_OPCODE_WRQ here.
503 @retval EFI_SUCCESS The upload process has been started.
504 @retval Others Failed to start the upload.
509 IN MTFTP4_PROTOCOL
*Instance
,
516 // The valid block number range are [0, 0xffff]. For example:
517 // the client sends an WRQ request to the server, the server
518 // ACK with an ACK0 to let client start transfer the first
521 Status
= Mtftp4InitBlockRange (&Instance
->Blocks
, 0, 0xffff);
523 if (EFI_ERROR (Status
)) {
527 Status
= Mtftp4SendRequest (Instance
);
529 if (EFI_ERROR (Status
)) {
533 return UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4WrqInput
, Instance
, 0);