2 Routines to process Wrq (upload).
4 Copyright (c) 2006 - 2010, 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
) {
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
151 AckNum
= NTOHS (Packet
->Ack
.Block
[0]);
152 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
154 ASSERT (Expected
>= 0);
157 // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp4WrqInput
160 if (Expected
!= AckNum
) {
165 // Remove the acked block number, if this is the last block number,
166 // tell the Mtftp4WrqInput to finish the transfer. This is the last
167 // block number if the block range are empty..
169 Mtftp4RemoveBlockNum (&Instance
->Blocks
, AckNum
, *Completed
,&TotalBlock
);
171 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
176 // The block range is empty. It may either because the the last
177 // block has been ACKed, or the sequence number just looped back,
178 // that is, there is more than 0xffff blocks.
180 if (Instance
->LastBlock
== AckNum
) {
181 ASSERT (Instance
->LastBlock
>= 1);
188 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
189 (UINT8
*) "Block number rolls back, not supported, try blksize option"
192 return EFI_TFTP_ERROR
;
196 return Mtftp4WrqSendBlock (Instance
, (UINT16
) Expected
);
201 Check whether the received OACK is valid.
203 The OACK is valid only if:
204 1. It only include options requested by us
205 2. It can only include a smaller block size
206 3. It can't change the proposed time out value.
207 4. Other requirements of the individal MTFTP options as required.
209 @param Reply The options included in the OACK
210 @param Request The options we requested
212 @retval TRUE The options included in OACK is valid.
213 @retval FALSE The options included in OACK is invalid.
218 IN MTFTP4_OPTION
*Reply
,
219 IN MTFTP4_OPTION
*Request
223 // It is invalid for server to return options we don't request
225 if ((Reply
->Exist
& ~Request
->Exist
) != 0) {
230 // Server can only specify a smaller block size to be used and
231 // return the timeout matches that requested.
233 if ((((Reply
->Exist
& MTFTP4_BLKSIZE_EXIST
) != 0) && (Reply
->BlkSize
> Request
->BlkSize
)) ||
234 (((Reply
->Exist
& MTFTP4_TIMEOUT_EXIST
) != 0) && (Reply
->Timeout
!= Request
->Timeout
))) {
243 Function to handle the MTFTP OACK packet.
245 It parses the packet's options, and update the internal states of the session.
247 @param Instance The MTFTP session
248 @param Packet The received OACK packet
249 @param Len The length of the packet
250 @param Completed Whether the transmisson has completed. NOT used by
253 @retval EFI_SUCCESS The OACK process is OK
254 @retval EFI_TFTP_ERROR Some error occured, and the session reset.
258 Mtftp4WrqHandleOack (
259 IN OUT MTFTP4_PROTOCOL
*Instance
,
260 IN EFI_MTFTP4_PACKET
*Packet
,
262 OUT BOOLEAN
*Completed
266 EFI_MTFTP4_PACKET Bogus
;
273 // Ignore the OACK if already started the upload
275 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
282 // Parse and validate the options from server
284 ZeroMem (&Reply
, sizeof (MTFTP4_OPTION
));
285 Status
= Mtftp4ParseOptionOack (Packet
, Len
, &Reply
);
287 if (EFI_ERROR (Status
) || !Mtftp4WrqOackValid (&Reply
, &Instance
->RequestOption
)) {
289 // Don't send a MTFTP error packet when out of resource, it can
290 // only make it worse.
292 if (Status
!= EFI_OUT_OF_RESOURCES
) {
295 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
296 (UINT8
*) "Mal-formated OACK packet"
300 return EFI_TFTP_ERROR
;
303 if (Reply
.BlkSize
!= 0) {
304 Instance
->BlkSize
= Reply
.BlkSize
;
307 if (Reply
.Timeout
!= 0) {
308 Instance
->Timeout
= Reply
.Timeout
;
312 // Build a bogus ACK0 packet then pass it to the Mtftp4WrqHandleAck,
313 // which will start the transmission of the first data block.
315 Bogus
.Ack
.OpCode
= HTONS (EFI_MTFTP4_OPCODE_ACK
);
316 Bogus
.Ack
.Block
[0] = 0;
318 Status
= Mtftp4WrqHandleAck (
321 sizeof (EFI_MTFTP4_ACK_HEADER
),
330 The input process routine for MTFTP upload.
332 @param UdpPacket The received MTFTP packet.
333 @param EndPoint The local/remote access point
334 @param IoStatus The result of the packet receiving
335 @param Context Opaque parameter for the callback, which is the
341 IN NET_BUF
*UdpPacket
,
342 IN UDP_END_POINT
*EndPoint
,
343 IN EFI_STATUS IoStatus
,
347 MTFTP4_PROTOCOL
*Instance
;
348 EFI_MTFTP4_PACKET
*Packet
;
354 Instance
= (MTFTP4_PROTOCOL
*) Context
;
355 NET_CHECK_SIGNATURE (Instance
, MTFTP4_PROTOCOL_SIGNATURE
);
359 Status
= EFI_SUCCESS
;
361 if (EFI_ERROR (IoStatus
)) {
366 ASSERT (UdpPacket
!= NULL
);
368 if (UdpPacket
->TotalSize
< MTFTP4_OPCODE_LEN
) {
373 // Client send initial request to server's listening port. Server
374 // will select a UDP port to communicate with the client.
376 if (EndPoint
->RemotePort
!= Instance
->ConnectedPort
) {
377 if (Instance
->ConnectedPort
!= 0) {
380 Instance
->ConnectedPort
= EndPoint
->RemotePort
;
385 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
387 Len
= UdpPacket
->TotalSize
;
389 if (UdpPacket
->BlockOpNum
> 1) {
390 Packet
= AllocatePool (Len
);
392 if (Packet
== NULL
) {
393 Status
= EFI_OUT_OF_RESOURCES
;
397 NetbufCopy (UdpPacket
, 0, Len
, (UINT8
*) Packet
);
400 Packet
= (EFI_MTFTP4_PACKET
*) NetbufGetByte (UdpPacket
, 0, NULL
);
403 Opcode
= NTOHS (Packet
->OpCode
);
406 // Call the user's CheckPacket if provided. Abort the transmission
407 // if CheckPacket returns an EFI_ERROR code.
409 if ((Instance
->Token
->CheckPacket
!= NULL
) &&
410 ((Opcode
== EFI_MTFTP4_OPCODE_OACK
) || (Opcode
== EFI_MTFTP4_OPCODE_ERROR
))) {
412 Status
= Instance
->Token
->CheckPacket (
419 if (EFI_ERROR (Status
)) {
421 // Send an error message to the server to inform it
423 if (Opcode
!= EFI_MTFTP4_OPCODE_ERROR
) {
426 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
427 (UINT8
*) "User aborted the transfer"
431 Status
= EFI_ABORTED
;
437 case EFI_MTFTP4_OPCODE_ACK
:
438 if (Len
!= MTFTP4_OPCODE_LEN
+ MTFTP4_BLKNO_LEN
) {
442 Status
= Mtftp4WrqHandleAck (Instance
, Packet
, Len
, &Completed
);
445 case EFI_MTFTP4_OPCODE_OACK
:
446 if (Len
<= MTFTP4_OPCODE_LEN
) {
450 Status
= Mtftp4WrqHandleOack (Instance
, Packet
, Len
, &Completed
);
453 case EFI_MTFTP4_OPCODE_ERROR
:
454 Status
= EFI_TFTP_ERROR
;
463 // Free the resources, then if !EFI_ERROR (Status) and not completed,
464 // restart the receive, otherwise end the session.
466 if ((Packet
!= NULL
) && (UdpPacket
->BlockOpNum
> 1)) {
470 if (UdpPacket
!= NULL
) {
471 NetbufFree (UdpPacket
);
474 if (!EFI_ERROR (Status
) && !Completed
) {
475 Status
= UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4WrqInput
, Instance
, 0);
479 // Status may have been updated by UdpIoRecvDatagram
481 if (EFI_ERROR (Status
) || Completed
) {
482 Mtftp4CleanOperation (Instance
, Status
);
489 Start the MTFTP session for upload.
491 It will first init some states, then send the WRQ request packet,
492 and start receiving the packet.
494 @param Instance The MTFTP session
495 @param Operation Redundant parameter, which is always
496 EFI_MTFTP4_OPCODE_WRQ here.
498 @retval EFI_SUCCESS The upload process has been started.
499 @retval Others Failed to start the upload.
504 IN MTFTP4_PROTOCOL
*Instance
,
511 // The valid block number range are [0, 0xffff]. For example:
512 // the client sends an WRQ request to the server, the server
513 // ACK with an ACK0 to let client start transfer the first
516 Status
= Mtftp4InitBlockRange (&Instance
->Blocks
, 0, 0xffff);
518 if (EFI_ERROR (Status
)) {
522 Status
= Mtftp4SendRequest (Instance
);
524 if (EFI_ERROR (Status
)) {
528 return UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4WrqInput
, Instance
, 0);