2 Mtftp6 Wrq process functions implementation.
4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "Mtftp6Impl.h"
13 Build and send a Mtftp6 data packet for upload.
15 @param[in] Instance The pointer to the Mtftp6 instance.
16 @param[in] BlockNum The block num to be sent.
18 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.
19 @retval EFI_SUCCESS The data packet was sent.
20 @retval EFI_ABORTED The user aborted this process.
25 IN MTFTP6_INSTANCE
*Instance
,
29 EFI_MTFTP6_PACKET
*Packet
;
30 EFI_MTFTP6_TOKEN
*Token
;
38 // Allocate net buffer to create data packet.
40 UdpPacket
= NetbufAlloc (Instance
->BlkSize
+ MTFTP6_DATA_HEAD_LEN
);
42 if (UdpPacket
== NULL
) {
43 return EFI_OUT_OF_RESOURCES
;
46 Packet
= (EFI_MTFTP6_PACKET
*)NetbufAllocSpace (
51 ASSERT (Packet
!= NULL
);
53 Packet
->Data
.OpCode
= HTONS (EFI_MTFTP6_OPCODE_DATA
);
54 Packet
->Data
.Block
= HTONS (BlockNum
);
57 // Read the block from either the buffer or PacketNeeded callback
59 Token
= Instance
->Token
;
60 DataLen
= Instance
->BlkSize
;
62 if (Token
->Buffer
!= NULL
) {
63 Start
= MultU64x32 (BlockNum
- 1, Instance
->BlkSize
);
65 if (Token
->BufferSize
< Start
+ Instance
->BlkSize
) {
66 DataLen
= (UINT16
)(Token
->BufferSize
- Start
);
67 Instance
->LastBlk
= BlockNum
;
68 Mtftp6SetLastBlockNum (&Instance
->BlkList
, BlockNum
);
72 NetbufAllocSpace (UdpPacket
, DataLen
, FALSE
);
73 CopyMem (Packet
->Data
.Data
, (UINT8
*)Token
->Buffer
+ Start
, DataLen
);
77 // Get data from PacketNeeded
80 Status
= Token
->PacketNeeded (&Instance
->Mtftp6
, Token
, &DataLen
, (VOID
*)&DataBuf
);
82 if (EFI_ERROR (Status
) || (DataLen
> Instance
->BlkSize
)) {
83 if (DataBuf
!= NULL
) {
84 gBS
->FreePool (DataBuf
);
88 // The received packet has already been freed.
92 EFI_MTFTP6_ERRORCODE_REQUEST_DENIED
,
93 (UINT8
*)"User aborted the transfer"
99 if (DataLen
< Instance
->BlkSize
) {
100 Instance
->LastBlk
= BlockNum
;
101 Mtftp6SetLastBlockNum (&Instance
->BlkList
, BlockNum
);
105 NetbufAllocSpace (UdpPacket
, DataLen
, FALSE
);
106 CopyMem (Packet
->Data
.Data
, DataBuf
, DataLen
);
107 gBS
->FreePool (DataBuf
);
112 // Reset current retry count of the instance.
114 Instance
->CurRetry
= 0;
116 return Mtftp6TransmitPacket (Instance
, UdpPacket
);
120 Function to handle received ACK packet. If the ACK number matches the
121 expected block number, with more data pending, send the next
122 block. Otherwise, tell the caller that we are done.
124 @param[in] Instance The pointer to the Mtftp6 instance.
125 @param[in] Packet The pointer to the received packet.
126 @param[in] Len The length of the packet.
127 @param[out] UdpPacket The net buf of received packet.
128 @param[out] IsCompleted If TRUE, the upload has been completed.
129 Otherwise, the upload has not been completed.
131 @retval EFI_SUCCESS The ACK packet successfully processed.
132 @retval EFI_TFTP_ERROR The block number loops back.
133 @retval Others Failed to transmit the next data packet.
138 IN MTFTP6_INSTANCE
*Instance
,
139 IN EFI_MTFTP6_PACKET
*Packet
,
141 OUT NET_BUF
**UdpPacket
,
142 OUT BOOLEAN
*IsCompleted
149 *IsCompleted
= FALSE
;
150 AckNum
= NTOHS (Packet
->Ack
.Block
[0]);
151 Expected
= Mtftp6GetNextBlockNum (&Instance
->BlkList
);
153 ASSERT (Expected
>= 0);
156 // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp6WrqInput
159 if (Expected
!= AckNum
) {
164 // Remove the acked block number, if this is the last block number,
165 // tell the Mtftp6WrqInput to finish the transfer. This is the last
166 // block number if the block range are empty.
168 Mtftp6RemoveBlockNum (&Instance
->BlkList
, AckNum
, *IsCompleted
, &BlockCounter
);
170 Expected
= Mtftp6GetNextBlockNum (&Instance
->BlkList
);
174 // The block range is empty. It may either because the last
175 // block has been ACKed, or the sequence number just looped back,
176 // that is, there is more than 0xffff blocks.
178 if (Instance
->LastBlk
== AckNum
) {
179 ASSERT (Instance
->LastBlk
>= 1);
184 // Free the received packet before send new packet in ReceiveNotify,
185 // since the udpio might need to be reconfigured.
187 NetbufFree (*UdpPacket
);
190 // Send the Mtftp6 error message if block number rolls back.
194 EFI_MTFTP6_ERRORCODE_REQUEST_DENIED
,
195 (UINT8
*)"Block number rolls back, not supported, try blksize option"
198 return EFI_TFTP_ERROR
;
203 // Free the receive buffer before send new packet since it might need
204 // reconfigure udpio.
206 NetbufFree (*UdpPacket
);
209 return Mtftp6WrqSendBlock (Instance
, (UINT16
)Expected
);
213 Check whether the received OACK is valid. The OACK is valid
215 1. It only include options requested by us.
216 2. It can only include a smaller block size.
217 3. It can't change the proposed time out value.
218 4. Other requirements of the individal MTFTP6 options as required.
220 @param[in] ReplyInfo The pointer to options information in reply packet.
221 @param[in] RequestInfo The pointer to requested options information.
223 @retval TRUE If the option in OACK is valid.
224 @retval FALSE If the option is invalid.
229 IN MTFTP6_EXT_OPTION_INFO
*ReplyInfo
,
230 IN MTFTP6_EXT_OPTION_INFO
*RequestInfo
234 // It is invalid for server to return options we don't request
236 if ((ReplyInfo
->BitMap
& ~RequestInfo
->BitMap
) != 0) {
241 // Server can only specify a smaller block size to be used and
242 // return the timeout matches that requested.
244 if ((((ReplyInfo
->BitMap
& MTFTP6_OPT_BLKSIZE_BIT
) != 0) && (ReplyInfo
->BlkSize
> RequestInfo
->BlkSize
)) ||
245 (((ReplyInfo
->BitMap
& MTFTP6_OPT_TIMEOUT_BIT
) != 0) && (ReplyInfo
->Timeout
!= RequestInfo
->Timeout
))
255 Process the OACK packet for Wrq.
257 @param[in] Instance The pointer to the Mtftp6 instance.
258 @param[in] Packet The pointer to the received packet.
259 @param[in] Len The length of the packet.
260 @param[out] UdpPacket The net buf of received packet.
261 @param[out] IsCompleted If TRUE, the upload has been completed.
262 Otherwise, the upload has not been completed.
264 @retval EFI_SUCCESS The OACK packet successfully processed.
265 @retval EFI_TFTP_ERROR An TFTP communication error happened.
266 @retval Others Failed to process the OACK packet.
270 Mtftp6WrqHandleOack (
271 IN MTFTP6_INSTANCE
*Instance
,
272 IN EFI_MTFTP6_PACKET
*Packet
,
274 OUT NET_BUF
**UdpPacket
,
275 OUT BOOLEAN
*IsCompleted
278 EFI_MTFTP6_OPTION
*Options
;
280 MTFTP6_EXT_OPTION_INFO ExtInfo
;
281 EFI_MTFTP6_PACKET Dummy
;
285 *IsCompleted
= FALSE
;
289 // Ignore the OACK if already started the upload
291 Expected
= Mtftp6GetNextBlockNum (&Instance
->BlkList
);
298 // Parse and validate the options from server
300 ZeroMem (&ExtInfo
, sizeof (MTFTP6_EXT_OPTION_INFO
));
302 Status
= Mtftp6ParseStart (Packet
, Len
, &Count
, &Options
);
304 if (EFI_ERROR (Status
)) {
308 ASSERT (Options
!= NULL
);
310 Status
= Mtftp6ParseExtensionOption (Options
, Count
, FALSE
, Instance
->Operation
, &ExtInfo
);
312 if (EFI_ERROR (Status
) || !Mtftp6WrqOackValid (&ExtInfo
, &Instance
->ExtInfo
)) {
314 // Don't send a MTFTP error packet when out of resource, it can
315 // only make it worse.
317 if (Status
!= EFI_OUT_OF_RESOURCES
) {
319 // Free the received packet before send new packet in ReceiveNotify,
320 // since the udpio might need to be reconfigured.
322 NetbufFree (*UdpPacket
);
325 // Send the Mtftp6 error message if invalid Oack packet received.
329 EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION
,
330 (UINT8
*)"Malformatted OACK packet"
334 return EFI_TFTP_ERROR
;
337 if (ExtInfo
.BlkSize
!= 0) {
338 Instance
->BlkSize
= ExtInfo
.BlkSize
;
341 if (ExtInfo
.Timeout
!= 0) {
342 Instance
->Timeout
= ExtInfo
.Timeout
;
346 // Build a bogus ACK0 packet then pass it to the Mtftp6WrqHandleAck,
347 // which will start the transmission of the first data block.
349 Dummy
.Ack
.OpCode
= HTONS (EFI_MTFTP6_OPCODE_ACK
);
350 Dummy
.Ack
.Block
[0] = 0;
352 return Mtftp6WrqHandleAck (
355 sizeof (EFI_MTFTP6_ACK_HEADER
),
362 The packet process callback for Mtftp6 upload.
364 @param[in] UdpPacket The pointer to the packet received.
365 @param[in] UdpEpt The pointer to the Udp6 access point.
366 @param[in] IoStatus The status from Udp6 instance.
367 @param[in] Context The pointer to the context.
373 IN NET_BUF
*UdpPacket
,
374 IN UDP_END_POINT
*UdpEpt
,
375 IN EFI_STATUS IoStatus
,
379 MTFTP6_INSTANCE
*Instance
;
380 EFI_MTFTP6_PACKET
*Packet
;
387 Instance
= (MTFTP6_INSTANCE
*)Context
;
389 NET_CHECK_SIGNATURE (Instance
, MTFTP6_INSTANCE_SIGNATURE
);
393 Status
= EFI_SUCCESS
;
397 // Return error status if Udp6 instance failed to receive.
399 if (EFI_ERROR (IoStatus
)) {
404 ASSERT (UdpPacket
!= NULL
);
406 if (UdpPacket
->TotalSize
< MTFTP6_OPCODE_LEN
) {
411 // Client send initial request to server's listening port. Server
412 // will select a UDP port to communicate with the client.
414 if (UdpEpt
->RemotePort
!= Instance
->ServerDataPort
) {
415 if (Instance
->ServerDataPort
!= 0) {
418 Instance
->ServerDataPort
= UdpEpt
->RemotePort
;
423 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
425 Len
= UdpPacket
->TotalSize
;
426 TotalNum
= UdpPacket
->BlockOpNum
;
429 Packet
= AllocateZeroPool (Len
);
431 if (Packet
== NULL
) {
432 Status
= EFI_OUT_OF_RESOURCES
;
436 NetbufCopy (UdpPacket
, 0, Len
, (UINT8
*)Packet
);
438 Packet
= (EFI_MTFTP6_PACKET
*)NetbufGetByte (UdpPacket
, 0, NULL
);
439 ASSERT (Packet
!= NULL
);
442 Opcode
= NTOHS (Packet
->OpCode
);
445 // Callback to the user's CheckPacket if provided. Abort the transmission
446 // if CheckPacket returns an EFI_ERROR code.
448 if ((Instance
->Token
->CheckPacket
!= NULL
) &&
449 ((Opcode
== EFI_MTFTP6_OPCODE_OACK
) || (Opcode
== EFI_MTFTP6_OPCODE_ERROR
))
452 Status
= Instance
->Token
->CheckPacket (
459 if (EFI_ERROR (Status
)) {
461 // Send an error message to the server to inform it
463 if (Opcode
!= EFI_MTFTP6_OPCODE_ERROR
) {
465 // Free the received packet before send new packet in ReceiveNotify,
466 // since the udpio might need to be reconfigured.
468 NetbufFree (UdpPacket
);
471 // Send the Mtftp6 error message if user aborted the current session.
475 EFI_MTFTP6_ERRORCODE_REQUEST_DENIED
,
476 (UINT8
*)"User aborted the transfer"
480 Status
= EFI_ABORTED
;
486 // Switch the process routines by the operation code.
489 case EFI_MTFTP6_OPCODE_ACK
:
490 if (Len
!= MTFTP6_OPCODE_LEN
+ MTFTP6_BLKNO_LEN
) {
495 // Handle the Ack packet of Wrq.
497 Status
= Mtftp6WrqHandleAck (Instance
, Packet
, Len
, &UdpPacket
, &IsCompleted
);
500 case EFI_MTFTP6_OPCODE_OACK
:
501 if (Len
<= MTFTP6_OPCODE_LEN
) {
506 // Handle the Oack packet of Wrq.
508 Status
= Mtftp6WrqHandleOack (Instance
, Packet
, Len
, &UdpPacket
, &IsCompleted
);
513 // Drop and return eror if received error message.
515 Status
= EFI_TFTP_ERROR
;
521 // Free the resources, then if !EFI_ERROR (Status) and not completed,
522 // restart the receive, otherwise end the session.
524 if ((Packet
!= NULL
) && (TotalNum
> 1)) {
528 if (UdpPacket
!= NULL
) {
529 NetbufFree (UdpPacket
);
532 if (!EFI_ERROR (Status
) && !IsCompleted
) {
533 Status
= UdpIoRecvDatagram (
542 // Clean up the current session if failed to continue.
544 if (EFI_ERROR (Status
) || IsCompleted
) {
545 Mtftp6OperationClean (Instance
, Status
);
550 Start the Mtftp6 instance to upload. It will first init some states,
551 then send the WRQ request packet, and start to receive the packet.
553 @param[in] Instance The pointer to the Mtftp6 instance.
554 @param[in] Operation The operation code of the current packet.
556 @retval EFI_SUCCESS The Mtftp6 was started to upload.
557 @retval Others Failed to start to upload.
562 IN MTFTP6_INSTANCE
*Instance
,
569 // The valid block number range are [0, 0xffff]. For example:
570 // the client sends an WRQ request to the server, the server
571 // ACK with an ACK0 to let client start transfer the first
574 Status
= Mtftp6InitBlockRange (&Instance
->BlkList
, 0, 0xffff);
576 if (EFI_ERROR (Status
)) {
580 Status
= Mtftp6SendRequest (Instance
, Operation
);
582 if (EFI_ERROR (Status
)) {
586 return UdpIoRecvDatagram (