2 Routines to process Wrq (upload).
4 Copyright (c) 2006 - 2009, Intel Corporation<BR>
5 All rights reserved. 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
) {
99 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
100 (UINT8
*) "User aborted the transfer"
106 if (DataLen
< Instance
->BlkSize
) {
107 Instance
->LastBlock
= BlockNum
;
108 Mtftp4SetLastBlockNum (&Instance
->Blocks
, BlockNum
);
112 NetbufAllocSpace (UdpPacket
, DataLen
, FALSE
);
113 CopyMem (Packet
->Data
.Data
, DataBuf
, DataLen
);
118 return Mtftp4SendPacket (Instance
, UdpPacket
);
123 Function to handle received ACK packet.
125 If the ACK number matches the expected block number, and there are more
126 data pending, send the next block. Otherwise tell the caller that we are done.
128 @param Instance The MTFTP upload session
129 @param Packet The MTFTP packet received
130 @param Len The packet length
131 @param Completed Return whether the upload has finished.
133 @retval EFI_SUCCESS The ACK is successfully processed.
134 @retval EFI_TFTP_ERROR The block number loops back.
135 @retval Others Failed to transmit the next data packet.
140 IN MTFTP4_PROTOCOL
*Instance
,
141 IN EFI_MTFTP4_PACKET
*Packet
,
143 OUT BOOLEAN
*Completed
150 AckNum
= NTOHS (Packet
->Ack
.Block
[0]);
151 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
153 ASSERT (Expected
>= 0);
156 // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp4WrqInput
159 if (Expected
!= AckNum
) {
164 // Remove the acked block number, if this is the last block number,
165 // tell the Mtftp4WrqInput to finish the transfer. This is the last
166 // block number if the block range are empty..
168 Mtftp4RemoveBlockNum (&Instance
->Blocks
, AckNum
);
170 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
175 // The block range is empty. It may either because the the last
176 // block has been ACKed, or the sequence number just looped back,
177 // that is, there is more than 0xffff blocks.
179 if (Instance
->LastBlock
== AckNum
) {
180 ASSERT (Instance
->LastBlock
>= 1);
187 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
188 (UINT8
*) "Block number rolls back, not supported, try blksize option"
191 return EFI_TFTP_ERROR
;
195 return Mtftp4WrqSendBlock (Instance
, (UINT16
) Expected
);
200 Check whether the received OACK is valid.
202 The OACK is valid only if:
203 1. It only include options requested by us
204 2. It can only include a smaller block size
205 3. It can't change the proposed time out value.
206 4. Other requirements of the individal MTFTP options as required.
208 @param Reply The options included in the OACK
209 @param Request The options we requested
211 @retval TRUE The options included in OACK is valid.
212 @retval FALSE The options included in OACK is invalid.
217 IN MTFTP4_OPTION
*Reply
,
218 IN MTFTP4_OPTION
*Request
222 // It is invalid for server to return options we don't request
224 if ((Reply
->Exist
& ~Request
->Exist
) != 0) {
229 // Server can only specify a smaller block size to be used and
230 // return the timeout matches that requested.
232 if ((((Reply
->Exist
& MTFTP4_BLKSIZE_EXIST
) != 0) && (Reply
->BlkSize
> Request
->BlkSize
)) ||
233 (((Reply
->Exist
& MTFTP4_TIMEOUT_EXIST
) != 0) && (Reply
->Timeout
!= Request
->Timeout
))) {
242 Function to handle the MTFTP OACK packet.
244 It parses the packet's options, and update the internal states of the session.
246 @param Instance The MTFTP session
247 @param Packet The received OACK packet
248 @param Len The length of the packet
249 @param Completed Whether the transmisson has completed. NOT used by
252 @retval EFI_SUCCESS The OACK process is OK
253 @retval EFI_TFTP_ERROR Some error occured, and the session reset.
257 Mtftp4WrqHandleOack (
258 IN OUT MTFTP4_PROTOCOL
*Instance
,
259 IN EFI_MTFTP4_PACKET
*Packet
,
261 OUT BOOLEAN
*Completed
265 EFI_MTFTP4_PACKET Bogus
;
272 // Ignore the OACK if already started the upload
274 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
281 // Parse and validate the options from server
283 ZeroMem (&Reply
, sizeof (MTFTP4_OPTION
));
284 Status
= Mtftp4ParseOptionOack (Packet
, Len
, &Reply
);
286 if (EFI_ERROR (Status
) || !Mtftp4WrqOackValid (&Reply
, &Instance
->RequestOption
)) {
288 // Don't send a MTFTP error packet when out of resource, it can
289 // only make it worse.
291 if (Status
!= EFI_OUT_OF_RESOURCES
) {
294 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
295 (UINT8
*) "Mal-formated OACK packet"
299 return EFI_TFTP_ERROR
;
302 if (Reply
.BlkSize
!= 0) {
303 Instance
->BlkSize
= Reply
.BlkSize
;
306 if (Reply
.Timeout
!= 0) {
307 Instance
->Timeout
= Reply
.Timeout
;
311 // Build a bogus ACK0 packet then pass it to the Mtftp4WrqHandleAck,
312 // which will start the transmission of the first data block.
314 Bogus
.Ack
.OpCode
= HTONS (EFI_MTFTP4_OPCODE_ACK
);
315 Bogus
.Ack
.Block
[0] = 0;
317 Status
= Mtftp4WrqHandleAck (
320 sizeof (EFI_MTFTP4_ACK_HEADER
),
329 The input process routine for MTFTP upload.
331 @param UdpPacket The received MTFTP packet.
332 @param EndPoint The local/remote access point
333 @param IoStatus The result of the packet receiving
334 @param Context Opaque parameter for the callback, which is the
340 IN NET_BUF
*UdpPacket
,
341 IN UDP_END_POINT
*EndPoint
,
342 IN EFI_STATUS IoStatus
,
346 MTFTP4_PROTOCOL
*Instance
;
347 EFI_MTFTP4_PACKET
*Packet
;
353 Instance
= (MTFTP4_PROTOCOL
*) Context
;
354 NET_CHECK_SIGNATURE (Instance
, MTFTP4_PROTOCOL_SIGNATURE
);
358 Status
= EFI_SUCCESS
;
360 if (EFI_ERROR (IoStatus
)) {
365 ASSERT (UdpPacket
!= NULL
);
367 if (UdpPacket
->TotalSize
< MTFTP4_OPCODE_LEN
) {
372 // Client send initial request to server's listening port. Server
373 // will select a UDP port to communicate with the client.
375 if (EndPoint
->RemotePort
!= Instance
->ConnectedPort
) {
376 if (Instance
->ConnectedPort
!= 0) {
379 Instance
->ConnectedPort
= EndPoint
->RemotePort
;
384 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
386 Len
= UdpPacket
->TotalSize
;
388 if (UdpPacket
->BlockOpNum
> 1) {
389 Packet
= AllocatePool (Len
);
391 if (Packet
== NULL
) {
392 Status
= EFI_OUT_OF_RESOURCES
;
396 NetbufCopy (UdpPacket
, 0, Len
, (UINT8
*) Packet
);
399 Packet
= (EFI_MTFTP4_PACKET
*) NetbufGetByte (UdpPacket
, 0, NULL
);
402 Opcode
= NTOHS (Packet
->OpCode
);
405 // Call the user's CheckPacket if provided. Abort the transmission
406 // if CheckPacket returns an EFI_ERROR code.
408 if ((Instance
->Token
->CheckPacket
!= NULL
) &&
409 ((Opcode
== EFI_MTFTP4_OPCODE_OACK
) || (Opcode
== EFI_MTFTP4_OPCODE_ERROR
))) {
411 Status
= Instance
->Token
->CheckPacket (
418 if (EFI_ERROR (Status
)) {
420 // Send an error message to the server to inform it
422 if (Opcode
!= EFI_MTFTP4_OPCODE_ERROR
) {
425 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
426 (UINT8
*) "User aborted the transfer"
430 Status
= EFI_ABORTED
;
436 case EFI_MTFTP4_OPCODE_ACK
:
437 if (Len
!= MTFTP4_OPCODE_LEN
+ MTFTP4_BLKNO_LEN
) {
441 Status
= Mtftp4WrqHandleAck (Instance
, Packet
, Len
, &Completed
);
444 case EFI_MTFTP4_OPCODE_OACK
:
445 if (Len
<= MTFTP4_OPCODE_LEN
) {
449 Status
= Mtftp4WrqHandleOack (Instance
, Packet
, Len
, &Completed
);
452 case EFI_MTFTP4_OPCODE_ERROR
:
453 Status
= EFI_TFTP_ERROR
;
462 // Free the resources, then if !EFI_ERROR (Status) and not completed,
463 // restart the receive, otherwise end the session.
465 if ((Packet
!= NULL
) && (UdpPacket
->BlockOpNum
> 1)) {
469 if (UdpPacket
!= NULL
) {
470 NetbufFree (UdpPacket
);
473 if (!EFI_ERROR (Status
) && !Completed
) {
474 Status
= UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4WrqInput
, Instance
, 0);
478 // Status may have been updated by UdpIoRecvDatagram
480 if (EFI_ERROR (Status
) || Completed
) {
481 Mtftp4CleanOperation (Instance
, Status
);
488 Start the MTFTP session for upload.
490 It will first init some states, then send the WRQ request packet,
491 and start receiving the packet.
493 @param Instance The MTFTP session
494 @param Operation Redundant parameter, which is always
495 EFI_MTFTP4_OPCODE_WRQ here.
497 @retval EFI_SUCCESS The upload process has been started.
498 @retval Others Failed to start the upload.
503 IN MTFTP4_PROTOCOL
*Instance
,
510 // The valid block number range are [0, 0xffff]. For example:
511 // the client sends an WRQ request to the server, the server
512 // ACK with an ACK0 to let client start transfer the first
515 Status
= Mtftp4InitBlockRange (&Instance
->Blocks
, 0, 0xffff);
517 if (EFI_ERROR (Status
)) {
521 Status
= Mtftp4SendRequest (Instance
);
523 if (EFI_ERROR (Status
)) {
527 return UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4WrqInput
, Instance
, 0);