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
10 #include "Mtftp4Impl.h"
13 The packet process callback for MTFTP download.
15 @param UdpPacket The packet received
16 @param EndPoint The local/remote access point of the packet
17 @param IoStatus The status of the receiving
18 @param Context Opaque parameter, which is the MTFTP session
24 IN NET_BUF
*UdpPacket
,
25 IN UDP_END_POINT
*EndPoint
,
26 IN EFI_STATUS IoStatus
,
31 Start the MTFTP session to download.
33 It will first initialize some of the internal states then build and send a RRQ
34 request packet, at last, it will start receive for the downloading.
36 @param Instance The Mtftp session
37 @param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ
38 or EFI_MTFTP4_OPCODE_DIR.
40 @retval EFI_SUCCESS The mtftp download session is started.
41 @retval Others Failed to start downloading.
46 IN MTFTP4_PROTOCOL
*Instance
,
53 // The valid block number range are [1, 0xffff]. For example:
54 // the client sends an RRQ request to the server, the server
55 // transfers the DATA1 block. If option negotiation is ongoing,
56 // the server will send back an OACK, then client will send ACK0.
58 Status
= Mtftp4InitBlockRange (&Instance
->Blocks
, 1, 0xffff);
60 if (EFI_ERROR (Status
)) {
64 Status
= Mtftp4SendRequest (Instance
);
66 if (EFI_ERROR (Status
)) {
70 return UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4RrqInput
, Instance
, 0);
74 Build and send a ACK packet for the download session.
76 @param Instance The Mtftp session
77 @param BlkNo The BlkNo to ack.
79 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet
80 @retval EFI_SUCCESS The ACK has been sent
81 @retval Others Failed to send the ACK.
86 IN MTFTP4_PROTOCOL
*Instance
,
90 EFI_MTFTP4_PACKET
*Ack
;
96 Packet
= NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER
));
98 return EFI_OUT_OF_RESOURCES
;
101 Ack
= (EFI_MTFTP4_PACKET
*)NetbufAllocSpace (
103 sizeof (EFI_MTFTP4_ACK_HEADER
),
106 ASSERT (Ack
!= NULL
);
108 Ack
->Ack
.OpCode
= HTONS (EFI_MTFTP4_OPCODE_ACK
);
109 Ack
->Ack
.Block
[0] = HTONS (BlkNo
);
111 Status
= Mtftp4SendPacket (Instance
, Packet
);
112 if (!EFI_ERROR (Status
)) {
113 Instance
->AckedBlock
= Instance
->TotalBlock
;
120 Deliver the received data block to the user, which can be saved
121 in the user provide buffer or through the CheckPacket callback.
123 @param Instance The Mtftp session
124 @param Packet The received data packet
125 @param Len The packet length
127 @retval EFI_SUCCESS The data is saved successfully
128 @retval EFI_ABORTED The user tells to abort by return an error through
130 @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small and buffer length is
131 updated to the actual buffer size needed.
136 IN OUT MTFTP4_PROTOCOL
*Instance
,
137 IN EFI_MTFTP4_PACKET
*Packet
,
141 EFI_MTFTP4_TOKEN
*Token
;
150 Token
= Instance
->Token
;
151 Block
= NTOHS (Packet
->Data
.Block
);
152 DataLen
= Len
- MTFTP4_DATA_HEAD_LEN
;
155 // This is the last block, save the block no
157 if (DataLen
< Instance
->BlkSize
) {
159 Instance
->LastBlock
= Block
;
160 Mtftp4SetLastBlockNum (&Instance
->Blocks
, Block
);
164 // Remove this block number from the file hole. If Mtftp4RemoveBlockNum
165 // returns EFI_NOT_FOUND, the block has been saved, don't save it again.
166 // Note that : For bigger files, allowing the block counter to roll over
167 // to accept transfers of unlimited size. So BlockCounter is memorised as
168 // continuous block counter.
170 Status
= Mtftp4RemoveBlockNum (&Instance
->Blocks
, Block
, Completed
, &BlockCounter
);
172 if (Status
== EFI_NOT_FOUND
) {
174 } else if (EFI_ERROR (Status
)) {
178 if (Token
->CheckPacket
!= NULL
) {
179 Status
= Token
->CheckPacket (&Instance
->Mtftp4
, Token
, (UINT16
)Len
, Packet
);
181 if (EFI_ERROR (Status
)) {
184 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
185 (UINT8
*)"User aborted download"
192 if (Token
->Buffer
!= NULL
) {
193 Start
= MultU64x32 (BlockCounter
- 1, Instance
->BlkSize
);
195 if (Start
+ DataLen
<= Token
->BufferSize
) {
196 CopyMem ((UINT8
*)Token
->Buffer
+ Start
, Packet
->Data
.Data
, DataLen
);
199 // Update the file size when received the last block
201 if ((Instance
->LastBlock
== Block
) && Completed
) {
202 Token
->BufferSize
= Start
+ DataLen
;
204 } else if (Instance
->LastBlock
!= 0) {
206 // Don't save the data if the buffer is too small, return
207 // EFI_BUFFER_TOO_SMALL if received the last packet. This
208 // will give a accurate file length.
210 Token
->BufferSize
= Start
+ DataLen
;
214 EFI_MTFTP4_ERRORCODE_DISK_FULL
,
215 (UINT8
*)"User provided memory block is too small"
218 return EFI_BUFFER_TOO_SMALL
;
226 Function to process the received data packets.
228 It will save the block then send back an ACK if it is active.
230 @param Instance The downloading MTFTP session
231 @param Packet The packet received
232 @param Len The length of the packet
233 @param Multicast Whether this packet is multicast or unicast
234 @param Completed Return whether the download has completed
236 @retval EFI_SUCCESS The data packet is successfully processed
237 @retval EFI_ABORTED The download is aborted by the user
238 @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
242 Mtftp4RrqHandleData (
243 IN MTFTP4_PROTOCOL
*Instance
,
244 IN EFI_MTFTP4_PACKET
*Packet
,
246 IN BOOLEAN Multicast
,
247 OUT BOOLEAN
*Completed
255 Status
= EFI_SUCCESS
;
256 BlockNum
= NTOHS (Packet
->Data
.Block
);
257 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
259 ASSERT (Expected
>= 0);
262 // If we are active (Master) and received an unexpected packet, transmit
263 // the ACK for the block we received, then restart receiving the
264 // expected one. If we are passive (Slave), save the block.
266 if (Instance
->Master
&& (Expected
!= BlockNum
)) {
268 // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).
270 return Mtftp4RrqSendAck (Instance
, (UINT16
)(Expected
- 1));
273 Status
= Mtftp4RrqSaveBlock (Instance
, Packet
, Len
);
275 if (EFI_ERROR (Status
)) {
280 // Record the total received and saved block number.
282 Instance
->TotalBlock
++;
285 // Reset the passive client's timer whenever it received a
286 // valid data packet.
288 if (!Instance
->Master
) {
289 Mtftp4SetTimeout (Instance
);
293 // Check whether we have received all the blocks. Send the ACK if we
294 // are active (unicast client or master client for multicast download).
295 // If we have received all the blocks, send an ACK even if we are passive
296 // to tell the server that we are done.
298 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
300 if (Instance
->Master
|| (Expected
< 0)) {
303 // If we are passive client, then the just received Block maybe
304 // isn't the last block. We need to send an ACK to the last block
305 // to inform the server that we are done. If we are active client,
306 // the Block == Instance->LastBlock.
308 BlockNum
= Instance
->LastBlock
;
311 BlockNum
= (UINT16
)(Expected
- 1);
314 if ((Instance
->WindowSize
== (Instance
->TotalBlock
- Instance
->AckedBlock
)) || (Expected
< 0)) {
315 Status
= Mtftp4RrqSendAck (Instance
, BlockNum
);
323 Validate whether the options received in the server's OACK packet is valid.
325 The options are valid only if:
326 1. The server doesn't include options not requested by us
327 2. The server can only use smaller blksize than that is requested
328 3. The server can only use the same timeout as requested
329 4. The server doesn't change its multicast channel.
331 @param This The downloading Mtftp session
332 @param Reply The options in the OACK packet
333 @param Request The requested options
335 @retval TRUE The options in the OACK is OK.
336 @retval FALSE The options in the OACK is invalid.
341 IN MTFTP4_PROTOCOL
*This
,
342 IN MTFTP4_OPTION
*Reply
,
343 IN MTFTP4_OPTION
*Request
347 // It is invalid for server to return options we don't request
349 if ((Reply
->Exist
&~Request
->Exist
) != 0) {
354 // Server can only specify a smaller block size and window size to be used and
355 // return the timeout matches that requested.
357 if ((((Reply
->Exist
& MTFTP4_BLKSIZE_EXIST
) != 0) && (Reply
->BlkSize
> Request
->BlkSize
)) ||
358 (((Reply
->Exist
& MTFTP4_WINDOWSIZE_EXIST
) != 0) && (Reply
->WindowSize
> Request
->WindowSize
)) ||
359 (((Reply
->Exist
& MTFTP4_TIMEOUT_EXIST
) != 0) && (Reply
->Timeout
!= Request
->Timeout
))
366 // The server can send ",,master" to client to change its master
367 // setting. But if it use the specific multicast channel, it can't
368 // change the setting.
370 if (((Reply
->Exist
& MTFTP4_MCAST_EXIST
) != 0) && (This
->McastIp
!= 0)) {
371 if ((Reply
->McastIp
!= 0) && (Reply
->McastIp
!= This
->McastIp
)) {
375 if ((Reply
->McastPort
!= 0) && (Reply
->McastPort
!= This
->McastPort
)) {
384 Configure a UDP IO port to receive the multicast.
386 @param McastIo The UDP IO to configure
387 @param Context The opaque parameter to the function which is the
390 @retval EFI_SUCCESS The UDP child is successfully configured.
391 @retval Others Failed to configure the UDP child.
396 Mtftp4RrqConfigMcastPort (
401 MTFTP4_PROTOCOL
*Instance
;
402 EFI_MTFTP4_CONFIG_DATA
*Config
;
403 EFI_UDP4_CONFIG_DATA UdpConfig
;
404 EFI_IPv4_ADDRESS Group
;
408 Instance
= (MTFTP4_PROTOCOL
*)Context
;
409 Config
= &Instance
->Config
;
411 UdpConfig
.AcceptBroadcast
= FALSE
;
412 UdpConfig
.AcceptPromiscuous
= FALSE
;
413 UdpConfig
.AcceptAnyPort
= FALSE
;
414 UdpConfig
.AllowDuplicatePort
= FALSE
;
415 UdpConfig
.TypeOfService
= 0;
416 UdpConfig
.TimeToLive
= 64;
417 UdpConfig
.DoNotFragment
= FALSE
;
418 UdpConfig
.ReceiveTimeout
= 0;
419 UdpConfig
.TransmitTimeout
= 0;
420 UdpConfig
.UseDefaultAddress
= Config
->UseDefaultSetting
;
421 IP4_COPY_ADDRESS (&UdpConfig
.StationAddress
, &Config
->StationIp
);
422 IP4_COPY_ADDRESS (&UdpConfig
.SubnetMask
, &Config
->SubnetMask
);
423 UdpConfig
.StationPort
= Instance
->McastPort
;
424 UdpConfig
.RemotePort
= 0;
426 Ip
= HTONL (Instance
->ServerIp
);
427 IP4_COPY_ADDRESS (&UdpConfig
.RemoteAddress
, &Ip
);
429 Status
= McastIo
->Protocol
.Udp4
->Configure (McastIo
->Protocol
.Udp4
, &UdpConfig
);
431 if (EFI_ERROR (Status
)) {
435 if (!Config
->UseDefaultSetting
&&
436 !EFI_IP4_EQUAL (&mZeroIp4Addr
, &Config
->GatewayIp
))
439 // The station IP address is manually configured and the Gateway IP is not 0.
440 // Add the default route for this UDP instance.
442 Status
= McastIo
->Protocol
.Udp4
->Routes (
443 McastIo
->Protocol
.Udp4
,
450 if (EFI_ERROR (Status
)) {
451 McastIo
->Protocol
.Udp4
->Configure (McastIo
->Protocol
.Udp4
, NULL
);
457 // join the multicast group
459 Ip
= HTONL (Instance
->McastIp
);
460 IP4_COPY_ADDRESS (&Group
, &Ip
);
462 return McastIo
->Protocol
.Udp4
->Groups (McastIo
->Protocol
.Udp4
, TRUE
, &Group
);
466 Function to process the OACK.
468 It will first validate the OACK packet, then update the various negotiated parameters.
470 @param Instance The download MTFTP session
471 @param Packet The packet received
472 @param Len The packet length
473 @param Multicast Whether this packet is received as a multicast
474 @param Completed Returns whether the download has completed. NOT
475 used by this function.
477 @retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child
478 @retval EFI_TFTP_ERROR Some error happened during the process
479 @retval EFI_SUCCESS The OACK is successfully processed.
483 Mtftp4RrqHandleOack (
484 IN OUT MTFTP4_PROTOCOL
*Instance
,
485 IN EFI_MTFTP4_PACKET
*Packet
,
487 IN BOOLEAN Multicast
,
488 OUT BOOLEAN
*Completed
494 EFI_UDP4_PROTOCOL
*Udp4
;
499 // If already started the master download, don't change the
500 // setting. Master download always succeeds.
502 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
503 ASSERT (Expected
!= -1);
505 if (Instance
->Master
&& (Expected
!= 1)) {
510 // Parse and validate the options from server
512 ZeroMem (&Reply
, sizeof (MTFTP4_OPTION
));
514 Status
= Mtftp4ParseOptionOack (Packet
, Len
, Instance
->Operation
, &Reply
);
516 if (EFI_ERROR (Status
) ||
517 !Mtftp4RrqOackValid (Instance
, &Reply
, &Instance
->RequestOption
))
520 // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
522 if (Status
!= EFI_OUT_OF_RESOURCES
) {
525 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
526 (UINT8
*)"Malformatted OACK packet"
530 return EFI_TFTP_ERROR
;
533 if ((Reply
.Exist
& MTFTP4_MCAST_EXIST
) != 0) {
535 // Save the multicast info. Always update the Master, only update the
536 // multicast IP address, block size, window size, timeout at the first time.
537 // If IP address is updated, create a UDP child to receive the multicast.
539 Instance
->Master
= Reply
.Master
;
541 if (Instance
->McastIp
== 0) {
542 if ((Reply
.McastIp
== 0) || (Reply
.McastPort
== 0)) {
545 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
546 (UINT8
*)"Illegal multicast setting"
549 return EFI_TFTP_ERROR
;
553 // Create a UDP child then start receive the multicast from it.
555 Instance
->McastIp
= Reply
.McastIp
;
556 Instance
->McastPort
= Reply
.McastPort
;
557 if (Instance
->McastUdpPort
== NULL
) {
558 Instance
->McastUdpPort
= UdpIoCreateIo (
559 Instance
->Service
->Controller
,
560 Instance
->Service
->Image
,
561 Mtftp4RrqConfigMcastPort
,
565 if (Instance
->McastUdpPort
!= NULL
) {
566 Status
= gBS
->OpenProtocol (
567 Instance
->McastUdpPort
->UdpHandle
,
568 &gEfiUdp4ProtocolGuid
,
570 Instance
->Service
->Image
,
572 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
574 if (EFI_ERROR (Status
)) {
575 UdpIoFreeIo (Instance
->McastUdpPort
);
576 Instance
->McastUdpPort
= NULL
;
577 return EFI_DEVICE_ERROR
;
582 if (Instance
->McastUdpPort
== NULL
) {
583 return EFI_DEVICE_ERROR
;
586 Status
= UdpIoRecvDatagram (Instance
->McastUdpPort
, Mtftp4RrqInput
, Instance
, 0);
588 if (EFI_ERROR (Status
)) {
591 EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION
,
592 (UINT8
*)"Failed to create socket to receive multicast packet"
599 // Update the parameters used.
601 if (Reply
.BlkSize
!= 0) {
602 Instance
->BlkSize
= Reply
.BlkSize
;
605 if (Reply
.WindowSize
!= 0) {
606 Instance
->WindowSize
= Reply
.WindowSize
;
609 if (Reply
.Timeout
!= 0) {
610 Instance
->Timeout
= Reply
.Timeout
;
614 Instance
->Master
= TRUE
;
616 if (Reply
.BlkSize
!= 0) {
617 Instance
->BlkSize
= Reply
.BlkSize
;
620 if (Reply
.WindowSize
!= 0) {
621 Instance
->WindowSize
= Reply
.WindowSize
;
624 if (Reply
.Timeout
!= 0) {
625 Instance
->Timeout
= Reply
.Timeout
;
630 // Send an ACK to (Expected - 1) which is 0 for unicast download,
631 // or tell the server we want to receive the Expected block.
633 return Mtftp4RrqSendAck (Instance
, (UINT16
)(Expected
- 1));
637 The packet process callback for MTFTP download.
639 @param UdpPacket The packet received
640 @param EndPoint The local/remote access point of the packet
641 @param IoStatus The status of the receiving
642 @param Context Opaque parameter, which is the MTFTP session
648 IN NET_BUF
*UdpPacket
,
649 IN UDP_END_POINT
*EndPoint
,
650 IN EFI_STATUS IoStatus
,
654 MTFTP4_PROTOCOL
*Instance
;
655 EFI_MTFTP4_PACKET
*Packet
;
662 Instance
= (MTFTP4_PROTOCOL
*)Context
;
663 NET_CHECK_SIGNATURE (Instance
, MTFTP4_PROTOCOL_SIGNATURE
);
665 Status
= EFI_SUCCESS
;
670 if (EFI_ERROR (IoStatus
)) {
675 ASSERT (UdpPacket
!= NULL
);
678 // Find the port this packet is from to restart receive correctly.
680 Multicast
= (BOOLEAN
)(EndPoint
->LocalAddr
.Addr
[0] == Instance
->McastIp
);
682 if (UdpPacket
->TotalSize
< MTFTP4_OPCODE_LEN
) {
687 // Client send initial request to server's listening port. Server
688 // will select a UDP port to communicate with the client. The server
689 // is required to use the same port as RemotePort to multicast the
692 if (EndPoint
->RemotePort
!= Instance
->ConnectedPort
) {
693 if (Instance
->ConnectedPort
!= 0) {
696 Instance
->ConnectedPort
= EndPoint
->RemotePort
;
701 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
703 Len
= UdpPacket
->TotalSize
;
705 if (UdpPacket
->BlockOpNum
> 1) {
706 Packet
= AllocatePool (Len
);
708 if (Packet
== NULL
) {
709 Status
= EFI_OUT_OF_RESOURCES
;
713 NetbufCopy (UdpPacket
, 0, Len
, (UINT8
*)Packet
);
715 Packet
= (EFI_MTFTP4_PACKET
*)NetbufGetByte (UdpPacket
, 0, NULL
);
716 ASSERT (Packet
!= NULL
);
719 Opcode
= NTOHS (Packet
->OpCode
);
722 // Call the user's CheckPacket if provided. Abort the transmission
723 // if CheckPacket returns an EFI_ERROR code.
725 if ((Instance
->Token
->CheckPacket
!= NULL
) &&
726 ((Opcode
== EFI_MTFTP4_OPCODE_OACK
) || (Opcode
== EFI_MTFTP4_OPCODE_ERROR
)))
728 Status
= Instance
->Token
->CheckPacket (
735 if (EFI_ERROR (Status
)) {
737 // Send an error message to the server to inform it
739 if (Opcode
!= EFI_MTFTP4_OPCODE_ERROR
) {
742 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
743 (UINT8
*)"User aborted the transfer"
747 Status
= EFI_ABORTED
;
753 case EFI_MTFTP4_OPCODE_DATA
:
754 if ((Len
> (UINT32
)(MTFTP4_DATA_HEAD_LEN
+ Instance
->BlkSize
)) ||
755 (Len
< (UINT32
)MTFTP4_DATA_HEAD_LEN
))
760 Status
= Mtftp4RrqHandleData (Instance
, Packet
, Len
, Multicast
, &Completed
);
763 case EFI_MTFTP4_OPCODE_OACK
:
764 if (Multicast
|| (Len
<= MTFTP4_OPCODE_LEN
)) {
768 Status
= Mtftp4RrqHandleOack (Instance
, Packet
, Len
, Multicast
, &Completed
);
771 case EFI_MTFTP4_OPCODE_ERROR
:
772 Status
= EFI_TFTP_ERROR
;
782 // Free the resources, then if !EFI_ERROR (Status), restart the
783 // receive, otherwise end the session.
785 if ((Packet
!= NULL
) && (UdpPacket
->BlockOpNum
> 1)) {
789 if (UdpPacket
!= NULL
) {
790 NetbufFree (UdpPacket
);
793 if (!EFI_ERROR (Status
) && !Completed
) {
795 Status
= UdpIoRecvDatagram (Instance
->McastUdpPort
, Mtftp4RrqInput
, Instance
, 0);
797 Status
= UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4RrqInput
, Instance
, 0);
801 if (EFI_ERROR (Status
) || Completed
) {
802 Mtftp4CleanOperation (Instance
, Status
);