3 Copyright (c) 2006, 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.
18 Routines to process Wrq (upload)
23 #include "Mtftp4Impl.h"
27 IN NET_BUF
*UdpPacket
,
28 IN UDP_POINTS
*Points
,
29 IN EFI_STATUS IoStatus
,
35 Start the MTFTP session for pload. It will first init some states,
36 then send the WRQ request packet, and start receiving the packet.
38 @param Instance The MTFTP session
39 @param Operation Redundant parameter, which is always
40 EFI_MTFTP4_OPCODE_WRQ here.
42 @retval EFI_SUCCESS The upload process has been started.
43 @retval Others Failed to start the upload.
48 IN MTFTP4_PROTOCOL
*Instance
,
55 // The valid block number range are [0, 0xffff]. For example:
56 // the client sends an WRQ request to the server, the server
57 // ACK with an ACK0 to let client start transfer the first
60 Status
= Mtftp4InitBlockRange (&Instance
->Blocks
, 0, 0xffff);
62 if (EFI_ERROR (Status
)) {
66 Status
= Mtftp4SendRequest (Instance
);
68 if (EFI_ERROR (Status
)) {
72 return UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4WrqInput
, Instance
, 0);
77 Build then send a MTFTP data packet for the MTFTP upload session.
79 @param Instance The MTFTP upload session
80 @param BlockNum The block number to send
82 @retval EFI_OUT_OF_RESOURCES Failed to build the packet
83 @retval EFI_ABORTED The consumer of this child directs to abort the
84 transmission by return an error through
86 @retval EFI_SUCCESS The data is sent.
91 IN MTFTP4_PROTOCOL
*Instance
,
95 EFI_MTFTP4_PACKET
*Packet
;
96 EFI_MTFTP4_TOKEN
*Token
;
104 // Allocate a buffer to hold the user data
106 UdpPacket
= NetbufAlloc (Instance
->BlkSize
+ MTFTP4_DATA_HEAD_LEN
);
108 if (UdpPacket
== NULL
) {
109 return EFI_OUT_OF_RESOURCES
;
112 Packet
= (EFI_MTFTP4_PACKET
*)NetbufAllocSpace (UdpPacket
, MTFTP4_DATA_HEAD_LEN
, FALSE
);
114 Packet
->Data
.OpCode
= HTONS (EFI_MTFTP4_OPCODE_DATA
);
115 Packet
->Data
.Block
= HTONS (BlockNum
);
118 // Read the block from either the buffer or PacketNeeded callback
120 Token
= Instance
->Token
;
121 DataLen
= Instance
->BlkSize
;
123 if (Token
->Buffer
!= NULL
) {
124 Start
= MultU64x32 (BlockNum
- 1, Instance
->BlkSize
);
126 if (Token
->BufferSize
< Start
+ Instance
->BlkSize
) {
127 DataLen
= (UINT16
) (Token
->BufferSize
- Start
);
128 Instance
->LastBlock
= BlockNum
;
129 Mtftp4SetLastBlockNum (&Instance
->Blocks
, BlockNum
);
133 NetbufAllocSpace (UdpPacket
, DataLen
, FALSE
);
134 NetCopyMem (Packet
->Data
.Data
, (UINT8
*) Token
->Buffer
+ Start
, DataLen
);
139 // Get data from PacketNeeded
142 Status
= Token
->PacketNeeded (&Instance
->Mtftp4
, Token
, &DataLen
, &DataBuf
);
144 if (EFI_ERROR (Status
) || (DataLen
> Instance
->BlkSize
)) {
145 if (DataBuf
!= NULL
) {
146 gBS
->FreePool (DataBuf
);
151 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
152 "User aborted the transfer"
158 if (DataLen
< Instance
->BlkSize
) {
159 Instance
->LastBlock
= BlockNum
;
160 Mtftp4SetLastBlockNum (&Instance
->Blocks
, BlockNum
);
164 NetbufAllocSpace (UdpPacket
, DataLen
, FALSE
);
165 NetCopyMem (Packet
->Data
.Data
, DataBuf
, DataLen
);
166 gBS
->FreePool (DataBuf
);
170 return Mtftp4SendPacket (Instance
, UdpPacket
);
175 Function to handle received ACK packet. If the ACK number matches the
176 expected block number, and there are more data pending, send the next
177 block. Otherwise tell the caller that we are done.
179 @param Instance The MTFTP upload session
180 @param Packet The MTFTP packet received
181 @param Len The packet length
182 @param Completed Return whether the upload has finished.
184 @retval EFI_SUCCESS The ACK is successfully processed.
185 @retval EFI_TFTP_ERROR The block number loops back.
186 @retval Others Failed to transmit the next data packet.
191 IN MTFTP4_PROTOCOL
*Instance
,
192 IN EFI_MTFTP4_PACKET
*Packet
,
194 OUT BOOLEAN
*Completed
201 AckNum
= NTOHS (Packet
->Ack
.Block
[0]);
202 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
204 ASSERT (Expected
>= 0);
207 // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp4WrqInput
210 if (Expected
!= AckNum
) {
215 // Remove the acked block number, if this is the last block number,
216 // tell the Mtftp4WrqInput to finish the transfer. This is the last
217 // block number if the block range are empty..
219 Mtftp4RemoveBlockNum (&Instance
->Blocks
, AckNum
);
221 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
225 // The block range is empty. It may either because the the last
226 // block has been ACKed, or the sequence number just looped back,
227 // that is, there is more than 0xffff blocks.
229 if (Instance
->LastBlock
== AckNum
) {
230 ASSERT (Instance
->LastBlock
>= 1);
237 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
238 "Block number rolls back, not supported, try blksize option"
241 return EFI_TFTP_ERROR
;
245 return Mtftp4WrqSendBlock (Instance
, (UINT16
) Expected
);
250 Check whether the received OACK is valid. The OACK is valid
252 1. It only include options requested by us
253 2. It can only include a smaller block size
254 3. It can't change the proposed time out value.
255 4. Other requirements of the individal MTFTP options as required.s
257 @param Reply The options included in the OACK
258 @param Request The options we requested
260 @return TRUE if the options included in OACK is valid, otherwise FALSE.
265 IN MTFTP4_OPTION
*Reply
,
266 IN MTFTP4_OPTION
*Request
270 // It is invalid for server to return options we don't request
272 if ((Reply
->Exist
&~Request
->Exist
) != 0) {
277 // Server can only specify a smaller block size to be used and
278 // return the timeout matches that requested.
280 if (((Reply
->Exist
& MTFTP4_BLKSIZE_EXIST
) && (Reply
->BlkSize
> Request
->BlkSize
)) ||
281 ((Reply
->Exist
& MTFTP4_TIMEOUT_EXIST
) && (Reply
->Timeout
!= Request
->Timeout
))) {
290 Function to handle the MTFTP OACK packet. It parses the packet's
291 options, and update the internal states of the session
293 @param Instance The MTFTP session
294 @param Packet The received OACK packet
295 @param Len The length of the packet
296 @param Completed Whether the transmisson has completed. NOT used by
299 @retval EFI_SUCCESS The OACK process is OK
300 @retval EFI_TFTP_ERROR Some error occured, and the session reset.
304 Mtftp4WrqHandleOack (
305 IN MTFTP4_PROTOCOL
*Instance
,
306 IN EFI_MTFTP4_PACKET
*Packet
,
308 OUT BOOLEAN
*Completed
312 EFI_MTFTP4_PACKET Bogus
;
319 // Ignore the OACK if already started the upload
321 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
328 // Parse and validate the options from server
330 NetZeroMem (&Reply
, sizeof (MTFTP4_OPTION
));
331 Status
= Mtftp4ParseOptionOack (Packet
, Len
, &Reply
);
333 if (EFI_ERROR (Status
) || !Mtftp4WrqOackValid (&Reply
, &Instance
->RequestOption
)) {
335 // Don't send a MTFTP error packet when out of resource, it can
336 // only make it worse.
338 if (Status
!= EFI_OUT_OF_RESOURCES
) {
341 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
342 "Mal-formated OACK packet"
346 return EFI_TFTP_ERROR
;
349 if (Reply
.BlkSize
!= 0) {
350 Instance
->BlkSize
= Reply
.BlkSize
;
353 if (Reply
.Timeout
!= 0) {
354 Instance
->Timeout
= Reply
.Timeout
;
358 // Build a bogus ACK0 packet then pass it to the Mtftp4WrqHandleAck,
359 // which will start the transmission of the first data block.
361 Bogus
.Ack
.OpCode
= HTONS (EFI_MTFTP4_OPCODE_ACK
);
362 Bogus
.Ack
.Block
[0] = 0;
364 return Mtftp4WrqHandleAck (Instance
, &Bogus
, sizeof (EFI_MTFTP4_ACK_HEADER
), Completed
);
369 The input process routine for MTFTP upload.
371 @param UdpPacket The received MTFTP packet.
372 @param Points The local/remote access point
373 @param IoStatus The result of the packet receiving
374 @param Context Opaque parameter for the callback, which is the
382 IN NET_BUF
*UdpPacket
,
383 IN UDP_POINTS
*Points
,
384 IN EFI_STATUS IoStatus
,
388 MTFTP4_PROTOCOL
*Instance
;
389 EFI_MTFTP4_PACKET
*Packet
;
395 Instance
= (MTFTP4_PROTOCOL
*) Context
;
396 NET_CHECK_SIGNATURE (Instance
, MTFTP4_PROTOCOL_SIGNATURE
);
400 Status
= EFI_SUCCESS
;
402 if (EFI_ERROR (IoStatus
)) {
407 ASSERT (UdpPacket
!= NULL
);
409 if (UdpPacket
->TotalSize
< MTFTP4_OPCODE_LEN
) {
414 // Client send initial request to server's listening port. Server
415 // will select a UDP port to communicate with the client.
417 if (Points
->RemotePort
!= Instance
->ConnectedPort
) {
418 if (Instance
->ConnectedPort
!= 0) {
421 Instance
->ConnectedPort
= Points
->RemotePort
;
426 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
428 Len
= UdpPacket
->TotalSize
;
430 if (UdpPacket
->BlockOpNum
> 1) {
431 Packet
= NetAllocatePool (Len
);
433 if (Packet
== NULL
) {
434 Status
= EFI_OUT_OF_RESOURCES
;
438 NetbufCopy (UdpPacket
, 0, Len
, (UINT8
*) Packet
);
441 Packet
= (EFI_MTFTP4_PACKET
*) NetbufGetByte (UdpPacket
, 0, NULL
);
444 Opcode
= NTOHS (Packet
->OpCode
);
447 // Call the user's CheckPacket if provided. Abort the transmission
448 // if CheckPacket returns an EFI_ERROR code.
450 if ((Instance
->Token
->CheckPacket
!= NULL
) &&
451 ((Opcode
== EFI_MTFTP4_OPCODE_OACK
) || (Opcode
== EFI_MTFTP4_OPCODE_ERROR
))) {
453 Status
= Instance
->Token
->CheckPacket (
460 if (EFI_ERROR (Status
)) {
462 // Send an error message to the server to inform it
464 if (Opcode
!= EFI_MTFTP4_OPCODE_ERROR
) {
467 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
468 "User aborted the transfer"
472 Status
= EFI_ABORTED
;
478 case EFI_MTFTP4_OPCODE_ACK
:
479 if (Len
!= MTFTP4_OPCODE_LEN
+ MTFTP4_BLKNO_LEN
) {
483 Status
= Mtftp4WrqHandleAck (Instance
, Packet
, Len
, &Completed
);
486 case EFI_MTFTP4_OPCODE_OACK
:
487 if (Len
<= MTFTP4_OPCODE_LEN
) {
491 Status
= Mtftp4WrqHandleOack (Instance
, Packet
, Len
, &Completed
);
494 case EFI_MTFTP4_OPCODE_ERROR
:
495 Status
= EFI_TFTP_ERROR
;
501 // Free the resources, then if !EFI_ERROR (Status) and not completed,
502 // restart the receive, otherwise end the session.
504 if ((Packet
!= NULL
) && (UdpPacket
->BlockOpNum
> 1)) {
505 NetFreePool (Packet
);
508 if (UdpPacket
!= NULL
) {
509 NetbufFree (UdpPacket
);
512 if (!EFI_ERROR (Status
) && !Completed
) {
513 Status
= UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4WrqInput
, Instance
, 0);
517 // Status may have been updated by UdpIoRecvDatagram
519 if (EFI_ERROR (Status
) || Completed
) {
520 Mtftp4CleanOperation (Instance
, Status
);