2 Routines to process Rrq (download).
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "Mtftp4Impl.h"
15 The packet process callback for MTFTP download.
17 @param UdpPacket The packet received
18 @param EndPoint The local/remote access point of the packet
19 @param IoStatus The status of the receiving
20 @param Context Opaque parameter, which is the MTFTP session
26 IN NET_BUF
*UdpPacket
,
27 IN UDP_END_POINT
*EndPoint
,
28 IN EFI_STATUS IoStatus
,
34 Start the MTFTP session to download.
36 It will first initialize some of the internal states then build and send a RRQ
37 reqeuest packet, at last, it will start receive for the downloading.
39 @param Instance The Mtftp session
40 @param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ
41 or EFI_MTFTP4_OPCODE_DIR.
43 @retval EFI_SUCCESS The mtftp download session is started.
44 @retval Others Failed to start downloading.
49 IN MTFTP4_PROTOCOL
*Instance
,
56 // The valid block number range are [1, 0xffff]. For example:
57 // the client sends an RRQ request to the server, the server
58 // transfers the DATA1 block. If option negoitation is ongoing,
59 // the server will send back an OACK, then client will send ACK0.
61 Status
= Mtftp4InitBlockRange (&Instance
->Blocks
, 1, 0xffff);
63 if (EFI_ERROR (Status
)) {
67 Status
= Mtftp4SendRequest (Instance
);
69 if (EFI_ERROR (Status
)) {
73 return UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4RrqInput
, Instance
, 0);
78 Build and send a ACK packet for the download session.
80 @param Instance The Mtftp session
81 @param BlkNo The BlkNo to ack.
83 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet
84 @retval EFI_SUCCESS The ACK has been sent
85 @retval Others Failed to send the ACK.
90 IN MTFTP4_PROTOCOL
*Instance
,
94 EFI_MTFTP4_PACKET
*Ack
;
100 Packet
= NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER
));
101 if (Packet
== NULL
) {
102 return EFI_OUT_OF_RESOURCES
;
105 Ack
= (EFI_MTFTP4_PACKET
*) NetbufAllocSpace (
107 sizeof (EFI_MTFTP4_ACK_HEADER
),
110 ASSERT (Ack
!= NULL
);
112 Ack
->Ack
.OpCode
= HTONS (EFI_MTFTP4_OPCODE_ACK
);
113 Ack
->Ack
.Block
[0] = HTONS (BlkNo
);
115 Status
= Mtftp4SendPacket (Instance
, Packet
);
116 if (!EFI_ERROR (Status
)) {
117 Instance
->AckedBlock
= Instance
->TotalBlock
;
125 Deliver the received data block to the user, which can be saved
126 in the user provide buffer or through the CheckPacket callback.
128 @param Instance The Mtftp session
129 @param Packet The received data packet
130 @param Len The packet length
132 @retval EFI_SUCCESS The data is saved successfully
133 @retval EFI_ABORTED The user tells to abort by return an error through
135 @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small and buffer length is
136 updated to the actual buffer size needed.
141 IN OUT MTFTP4_PROTOCOL
*Instance
,
142 IN EFI_MTFTP4_PACKET
*Packet
,
146 EFI_MTFTP4_TOKEN
*Token
;
155 Token
= Instance
->Token
;
156 Block
= NTOHS (Packet
->Data
.Block
);
157 DataLen
= Len
- MTFTP4_DATA_HEAD_LEN
;
160 // This is the last block, save the block no
162 if (DataLen
< Instance
->BlkSize
) {
164 Instance
->LastBlock
= Block
;
165 Mtftp4SetLastBlockNum (&Instance
->Blocks
, Block
);
169 // Remove this block number from the file hole. If Mtftp4RemoveBlockNum
170 // returns EFI_NOT_FOUND, the block has been saved, don't save it again.
171 // Note that : For bigger files, allowing the block counter to roll over
172 // to accept transfers of unlimited size. So BlockCounter is memorised as
173 // continuous block counter.
175 Status
= Mtftp4RemoveBlockNum (&Instance
->Blocks
, Block
, Completed
, &BlockCounter
);
177 if (Status
== EFI_NOT_FOUND
) {
179 } else if (EFI_ERROR (Status
)) {
183 if (Token
->CheckPacket
!= NULL
) {
184 Status
= Token
->CheckPacket (&Instance
->Mtftp4
, Token
, (UINT16
) Len
, Packet
);
186 if (EFI_ERROR (Status
)) {
189 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
190 (UINT8
*) "User aborted download"
197 if (Token
->Buffer
!= NULL
) {
198 Start
= MultU64x32 (BlockCounter
- 1, Instance
->BlkSize
);
200 if (Start
+ DataLen
<= Token
->BufferSize
) {
201 CopyMem ((UINT8
*) Token
->Buffer
+ Start
, Packet
->Data
.Data
, DataLen
);
204 // Update the file size when received the last block
206 if ((Instance
->LastBlock
== Block
) && Completed
) {
207 Token
->BufferSize
= Start
+ DataLen
;
210 } else if (Instance
->LastBlock
!= 0) {
212 // Don't save the data if the buffer is too small, return
213 // EFI_BUFFER_TOO_SMALL if received the last packet. This
214 // will give a accurate file length.
216 Token
->BufferSize
= Start
+ DataLen
;
220 EFI_MTFTP4_ERRORCODE_DISK_FULL
,
221 (UINT8
*) "User provided memory block is too small"
224 return EFI_BUFFER_TOO_SMALL
;
233 Function to process the received data packets.
235 It will save the block then send back an ACK if it is active.
237 @param Instance The downloading MTFTP session
238 @param Packet The packet received
239 @param Len The length of the packet
240 @param Multicast Whether this packet is multicast or unicast
241 @param Completed Return whether the download has completed
243 @retval EFI_SUCCESS The data packet is successfully processed
244 @retval EFI_ABORTED The download is aborted by the user
245 @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
249 Mtftp4RrqHandleData (
250 IN MTFTP4_PROTOCOL
*Instance
,
251 IN EFI_MTFTP4_PACKET
*Packet
,
253 IN BOOLEAN Multicast
,
254 OUT BOOLEAN
*Completed
262 Status
= EFI_SUCCESS
;
263 BlockNum
= NTOHS (Packet
->Data
.Block
);
264 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
266 ASSERT (Expected
>= 0);
269 // If we are active (Master) and received an unexpected packet, transmit
270 // the ACK for the block we received, then restart receiving the
271 // expected one. If we are passive (Slave), save the block.
273 if (Instance
->Master
&& (Expected
!= BlockNum
)) {
275 // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).
277 return Mtftp4RrqSendAck (Instance
, (UINT16
) (Expected
- 1));
280 Status
= Mtftp4RrqSaveBlock (Instance
, Packet
, Len
);
282 if (EFI_ERROR (Status
)) {
287 // Record the total received and saved block number.
289 Instance
->TotalBlock
++;
292 // Reset the passive client's timer whenever it received a
293 // valid data packet.
295 if (!Instance
->Master
) {
296 Mtftp4SetTimeout (Instance
);
300 // Check whether we have received all the blocks. Send the ACK if we
301 // are active (unicast client or master client for multicast download).
302 // If we have received all the blocks, send an ACK even if we are passive
303 // to tell the server that we are done.
305 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
307 if (Instance
->Master
|| (Expected
< 0)) {
310 // If we are passive client, then the just received Block maybe
311 // isn't the last block. We need to send an ACK to the last block
312 // to inform the server that we are done. If we are active client,
313 // the Block == Instance->LastBlock.
315 BlockNum
= Instance
->LastBlock
;
319 BlockNum
= (UINT16
) (Expected
- 1);
322 if (Instance
->WindowSize
== (Instance
->TotalBlock
- Instance
->AckedBlock
) || Expected
< 0) {
323 Status
= Mtftp4RrqSendAck (Instance
, BlockNum
);
333 Validate whether the options received in the server's OACK packet is valid.
335 The options are valid only if:
336 1. The server doesn't include options not requested by us
337 2. The server can only use smaller blksize than that is requested
338 3. The server can only use the same timeout as requested
339 4. The server doesn't change its multicast channel.
341 @param This The downloading Mtftp session
342 @param Reply The options in the OACK packet
343 @param Request The requested options
345 @retval TRUE The options in the OACK is OK.
346 @retval FALSE The options in the OACK is invalid.
351 IN MTFTP4_PROTOCOL
*This
,
352 IN MTFTP4_OPTION
*Reply
,
353 IN MTFTP4_OPTION
*Request
358 // It is invalid for server to return options we don't request
360 if ((Reply
->Exist
&~Request
->Exist
) != 0) {
365 // Server can only specify a smaller block size and window size to be used and
366 // return the timeout matches that requested.
368 if ((((Reply
->Exist
& MTFTP4_BLKSIZE_EXIST
) != 0)&& (Reply
->BlkSize
> Request
->BlkSize
)) ||
369 (((Reply
->Exist
& MTFTP4_WINDOWSIZE_EXIST
) != 0)&& (Reply
->WindowSize
> Request
->WindowSize
)) ||
370 (((Reply
->Exist
& MTFTP4_TIMEOUT_EXIST
) != 0) && (Reply
->Timeout
!= Request
->Timeout
))
376 // The server can send ",,master" to client to change its master
377 // setting. But if it use the specific multicast channel, it can't
378 // change the setting.
380 if (((Reply
->Exist
& MTFTP4_MCAST_EXIST
) != 0) && (This
->McastIp
!= 0)) {
381 if ((Reply
->McastIp
!= 0) && (Reply
->McastIp
!= This
->McastIp
)) {
385 if ((Reply
->McastPort
!= 0) && (Reply
->McastPort
!= This
->McastPort
)) {
395 Configure a UDP IO port to receive the multicast.
397 @param McastIo The UDP IO to configure
398 @param Context The opaque parameter to the function which is the
401 @retval EFI_SUCCESS The UDP child is successfully configured.
402 @retval Others Failed to configure the UDP child.
407 Mtftp4RrqConfigMcastPort (
412 MTFTP4_PROTOCOL
*Instance
;
413 EFI_MTFTP4_CONFIG_DATA
*Config
;
414 EFI_UDP4_CONFIG_DATA UdpConfig
;
415 EFI_IPv4_ADDRESS Group
;
419 Instance
= (MTFTP4_PROTOCOL
*) Context
;
420 Config
= &Instance
->Config
;
422 UdpConfig
.AcceptBroadcast
= FALSE
;
423 UdpConfig
.AcceptPromiscuous
= FALSE
;
424 UdpConfig
.AcceptAnyPort
= FALSE
;
425 UdpConfig
.AllowDuplicatePort
= FALSE
;
426 UdpConfig
.TypeOfService
= 0;
427 UdpConfig
.TimeToLive
= 64;
428 UdpConfig
.DoNotFragment
= FALSE
;
429 UdpConfig
.ReceiveTimeout
= 0;
430 UdpConfig
.TransmitTimeout
= 0;
431 UdpConfig
.UseDefaultAddress
= Config
->UseDefaultSetting
;
432 IP4_COPY_ADDRESS (&UdpConfig
.StationAddress
, &Config
->StationIp
);
433 IP4_COPY_ADDRESS (&UdpConfig
.SubnetMask
, &Config
->SubnetMask
);
434 UdpConfig
.StationPort
= Instance
->McastPort
;
435 UdpConfig
.RemotePort
= 0;
437 Ip
= HTONL (Instance
->ServerIp
);
438 IP4_COPY_ADDRESS (&UdpConfig
.RemoteAddress
, &Ip
);
440 Status
= McastIo
->Protocol
.Udp4
->Configure (McastIo
->Protocol
.Udp4
, &UdpConfig
);
442 if (EFI_ERROR (Status
)) {
446 if (!Config
->UseDefaultSetting
&&
447 !EFI_IP4_EQUAL (&mZeroIp4Addr
, &Config
->GatewayIp
)) {
449 // The station IP address is manually configured and the Gateway IP is not 0.
450 // Add the default route for this UDP instance.
452 Status
= McastIo
->Protocol
.Udp4
->Routes (
453 McastIo
->Protocol
.Udp4
,
460 if (EFI_ERROR (Status
)) {
461 McastIo
->Protocol
.Udp4
->Configure (McastIo
->Protocol
.Udp4
, NULL
);
467 // join the multicast group
469 Ip
= HTONL (Instance
->McastIp
);
470 IP4_COPY_ADDRESS (&Group
, &Ip
);
472 return McastIo
->Protocol
.Udp4
->Groups (McastIo
->Protocol
.Udp4
, TRUE
, &Group
);
477 Function to process the OACK.
479 It will first validate the OACK packet, then update the various negotiated parameters.
481 @param Instance The download MTFTP session
482 @param Packet The packet received
483 @param Len The packet length
484 @param Multicast Whether this packet is received as a multicast
485 @param Completed Returns whether the download has completed. NOT
486 used by this function.
488 @retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child
489 @retval EFI_TFTP_ERROR Some error happened during the process
490 @retval EFI_SUCCESS The OACK is successfully processed.
494 Mtftp4RrqHandleOack (
495 IN OUT MTFTP4_PROTOCOL
*Instance
,
496 IN EFI_MTFTP4_PACKET
*Packet
,
498 IN BOOLEAN Multicast
,
499 OUT BOOLEAN
*Completed
505 EFI_UDP4_PROTOCOL
*Udp4
;
510 // If already started the master download, don't change the
511 // setting. Master download always succeeds.
513 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
514 ASSERT (Expected
!= -1);
516 if (Instance
->Master
&& (Expected
!= 1)) {
521 // Parse and validate the options from server
523 ZeroMem (&Reply
, sizeof (MTFTP4_OPTION
));
525 Status
= Mtftp4ParseOptionOack (Packet
, Len
, Instance
->Operation
, &Reply
);
527 if (EFI_ERROR (Status
) ||
528 !Mtftp4RrqOackValid (Instance
, &Reply
, &Instance
->RequestOption
)) {
530 // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
532 if (Status
!= EFI_OUT_OF_RESOURCES
) {
535 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
536 (UINT8
*) "Mal-formated OACK packet"
540 return EFI_TFTP_ERROR
;
543 if ((Reply
.Exist
& MTFTP4_MCAST_EXIST
) != 0) {
546 // Save the multicast info. Always update the Master, only update the
547 // multicast IP address, block size, window size, timeoute at the first time. If IP
548 // address is updated, create a UDP child to receive the multicast.
550 Instance
->Master
= Reply
.Master
;
552 if (Instance
->McastIp
== 0) {
553 if ((Reply
.McastIp
== 0) || (Reply
.McastPort
== 0)) {
556 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
557 (UINT8
*) "Illegal multicast setting"
560 return EFI_TFTP_ERROR
;
564 // Create a UDP child then start receive the multicast from it.
566 Instance
->McastIp
= Reply
.McastIp
;
567 Instance
->McastPort
= Reply
.McastPort
;
568 if (Instance
->McastUdpPort
== NULL
) {
569 Instance
->McastUdpPort
= UdpIoCreateIo (
570 Instance
->Service
->Controller
,
571 Instance
->Service
->Image
,
572 Mtftp4RrqConfigMcastPort
,
576 if (Instance
->McastUdpPort
!= NULL
) {
577 Status
= gBS
->OpenProtocol (
578 Instance
->McastUdpPort
->UdpHandle
,
579 &gEfiUdp4ProtocolGuid
,
581 Instance
->Service
->Image
,
583 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
585 if (EFI_ERROR (Status
)) {
586 UdpIoFreeIo (Instance
->McastUdpPort
);
587 Instance
->McastUdpPort
= NULL
;
588 return EFI_DEVICE_ERROR
;
594 if (Instance
->McastUdpPort
== NULL
) {
595 return EFI_DEVICE_ERROR
;
598 Status
= UdpIoRecvDatagram (Instance
->McastUdpPort
, Mtftp4RrqInput
, Instance
, 0);
600 if (EFI_ERROR (Status
)) {
603 EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION
,
604 (UINT8
*) "Failed to create socket to receive multicast packet"
611 // Update the parameters used.
613 if (Reply
.BlkSize
!= 0) {
614 Instance
->BlkSize
= Reply
.BlkSize
;
617 if (Reply
.WindowSize
!= 0) {
618 Instance
->WindowSize
= Reply
.WindowSize
;
621 if (Reply
.Timeout
!= 0) {
622 Instance
->Timeout
= Reply
.Timeout
;
627 Instance
->Master
= TRUE
;
629 if (Reply
.BlkSize
!= 0) {
630 Instance
->BlkSize
= Reply
.BlkSize
;
633 if (Reply
.WindowSize
!= 0) {
634 Instance
->WindowSize
= Reply
.WindowSize
;
637 if (Reply
.Timeout
!= 0) {
638 Instance
->Timeout
= Reply
.Timeout
;
643 // Send an ACK to (Expected - 1) which is 0 for unicast download,
644 // or tell the server we want to receive the Expected block.
646 return Mtftp4RrqSendAck (Instance
, (UINT16
) (Expected
- 1));
651 The packet process callback for MTFTP download.
653 @param UdpPacket The packet received
654 @param EndPoint The local/remote access point of the packet
655 @param IoStatus The status of the receiving
656 @param Context Opaque parameter, which is the MTFTP session
662 IN NET_BUF
*UdpPacket
,
663 IN UDP_END_POINT
*EndPoint
,
664 IN EFI_STATUS IoStatus
,
668 MTFTP4_PROTOCOL
*Instance
;
669 EFI_MTFTP4_PACKET
*Packet
;
676 Instance
= (MTFTP4_PROTOCOL
*) Context
;
677 NET_CHECK_SIGNATURE (Instance
, MTFTP4_PROTOCOL_SIGNATURE
);
679 Status
= EFI_SUCCESS
;
684 if (EFI_ERROR (IoStatus
)) {
689 ASSERT (UdpPacket
!= NULL
);
692 // Find the port this packet is from to restart receive correctly.
694 Multicast
= (BOOLEAN
) (EndPoint
->LocalAddr
.Addr
[0] == Instance
->McastIp
);
696 if (UdpPacket
->TotalSize
< MTFTP4_OPCODE_LEN
) {
701 // Client send initial request to server's listening port. Server
702 // will select a UDP port to communicate with the client. The server
703 // is required to use the same port as RemotePort to multicast the
706 if (EndPoint
->RemotePort
!= Instance
->ConnectedPort
) {
707 if (Instance
->ConnectedPort
!= 0) {
710 Instance
->ConnectedPort
= EndPoint
->RemotePort
;
715 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
717 Len
= UdpPacket
->TotalSize
;
719 if (UdpPacket
->BlockOpNum
> 1) {
720 Packet
= AllocatePool (Len
);
722 if (Packet
== NULL
) {
723 Status
= EFI_OUT_OF_RESOURCES
;
727 NetbufCopy (UdpPacket
, 0, Len
, (UINT8
*) Packet
);
730 Packet
= (EFI_MTFTP4_PACKET
*) NetbufGetByte (UdpPacket
, 0, NULL
);
731 ASSERT (Packet
!= NULL
);
734 Opcode
= NTOHS (Packet
->OpCode
);
737 // Call the user's CheckPacket if provided. Abort the transmission
738 // if CheckPacket returns an EFI_ERROR code.
740 if ((Instance
->Token
->CheckPacket
!= NULL
) &&
741 ((Opcode
== EFI_MTFTP4_OPCODE_OACK
) || (Opcode
== EFI_MTFTP4_OPCODE_ERROR
))) {
743 Status
= Instance
->Token
->CheckPacket (
750 if (EFI_ERROR (Status
)) {
752 // Send an error message to the server to inform it
754 if (Opcode
!= EFI_MTFTP4_OPCODE_ERROR
) {
757 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
758 (UINT8
*) "User aborted the transfer"
762 Status
= EFI_ABORTED
;
768 case EFI_MTFTP4_OPCODE_DATA
:
769 if ((Len
> (UINT32
) (MTFTP4_DATA_HEAD_LEN
+ Instance
->BlkSize
)) ||
770 (Len
< (UINT32
) MTFTP4_DATA_HEAD_LEN
)) {
774 Status
= Mtftp4RrqHandleData (Instance
, Packet
, Len
, Multicast
, &Completed
);
777 case EFI_MTFTP4_OPCODE_OACK
:
778 if (Multicast
|| (Len
<= MTFTP4_OPCODE_LEN
)) {
782 Status
= Mtftp4RrqHandleOack (Instance
, Packet
, Len
, Multicast
, &Completed
);
785 case EFI_MTFTP4_OPCODE_ERROR
:
786 Status
= EFI_TFTP_ERROR
;
796 // Free the resources, then if !EFI_ERROR (Status), restart the
797 // receive, otherwise end the session.
799 if ((Packet
!= NULL
) && (UdpPacket
->BlockOpNum
> 1)) {
803 if (UdpPacket
!= NULL
) {
804 NetbufFree (UdpPacket
);
807 if (!EFI_ERROR (Status
) && !Completed
) {
809 Status
= UdpIoRecvDatagram (Instance
->McastUdpPort
, Mtftp4RrqInput
, Instance
, 0);
811 Status
= UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4RrqInput
, Instance
, 0);
815 if (EFI_ERROR (Status
) || Completed
) {
816 Mtftp4CleanOperation (Instance
, Status
);