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 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php<BR>
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "Mtftp4Impl.h"
21 The packet process callback for MTFTP download.
23 @param UdpPacket The packet received
24 @param EndPoint The local/remote access point of the packet
25 @param IoStatus The status of the receiving
26 @param Context Opaque parameter, which is the MTFTP session
32 IN NET_BUF
*UdpPacket
,
33 IN UDP_END_POINT
*EndPoint
,
34 IN EFI_STATUS IoStatus
,
40 Start the MTFTP session to download.
42 It will first initialize some of the internal states then build and send a RRQ
43 reqeuest packet, at last, it will start receive for the downloading.
45 @param Instance The Mtftp session
46 @param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ
47 or EFI_MTFTP4_OPCODE_DIR.
49 @retval EFI_SUCCESS The mtftp download session is started.
50 @retval Others Failed to start downloading.
55 IN MTFTP4_PROTOCOL
*Instance
,
62 // The valid block number range are [1, 0xffff]. For example:
63 // the client sends an RRQ request to the server, the server
64 // transfers the DATA1 block. If option negoitation is ongoing,
65 // the server will send back an OACK, then client will send ACK0.
67 Status
= Mtftp4InitBlockRange (&Instance
->Blocks
, 1, 0xffff);
69 if (EFI_ERROR (Status
)) {
73 Status
= Mtftp4SendRequest (Instance
);
75 if (EFI_ERROR (Status
)) {
79 return UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4RrqInput
, Instance
, 0);
84 Build and send a ACK packet for the download session.
86 @param Instance The Mtftp session
87 @param BlkNo The BlkNo to ack.
89 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet
90 @retval EFI_SUCCESS The ACK has been sent
91 @retval Others Failed to send the ACK.
96 IN MTFTP4_PROTOCOL
*Instance
,
100 EFI_MTFTP4_PACKET
*Ack
;
104 Status
= EFI_SUCCESS
;
106 Packet
= NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER
));
107 if (Packet
== NULL
) {
108 return EFI_OUT_OF_RESOURCES
;
111 Ack
= (EFI_MTFTP4_PACKET
*) NetbufAllocSpace (
113 sizeof (EFI_MTFTP4_ACK_HEADER
),
116 ASSERT (Ack
!= NULL
);
118 Ack
->Ack
.OpCode
= HTONS (EFI_MTFTP4_OPCODE_ACK
);
119 Ack
->Ack
.Block
[0] = HTONS (BlkNo
);
121 Status
= Mtftp4SendPacket (Instance
, Packet
);
122 if (!EFI_ERROR (Status
)) {
123 Instance
->AckedBlock
= Instance
->TotalBlock
;
131 Deliver the received data block to the user, which can be saved
132 in the user provide buffer or through the CheckPacket callback.
134 @param Instance The Mtftp session
135 @param Packet The received data packet
136 @param Len The packet length
138 @retval EFI_SUCCESS The data is saved successfully
139 @retval EFI_ABORTED The user tells to abort by return an error through
141 @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small and buffer length is
142 updated to the actual buffer size needed.
147 IN OUT MTFTP4_PROTOCOL
*Instance
,
148 IN EFI_MTFTP4_PACKET
*Packet
,
152 EFI_MTFTP4_TOKEN
*Token
;
160 Token
= Instance
->Token
;
161 Block
= NTOHS (Packet
->Data
.Block
);
162 DataLen
= Len
- MTFTP4_DATA_HEAD_LEN
;
165 // This is the last block, save the block no
167 if (DataLen
< Instance
->BlkSize
) {
169 Instance
->LastBlock
= Block
;
170 Mtftp4SetLastBlockNum (&Instance
->Blocks
, Block
);
174 // Remove this block number from the file hole. If Mtftp4RemoveBlockNum
175 // returns EFI_NOT_FOUND, the block has been saved, don't save it again.
176 // Note that : For bigger files, allowing the block counter to roll over
177 // to accept transfers of unlimited size. So TotalBlock is memorised as
178 // continuous block counter.
180 Status
= Mtftp4RemoveBlockNum (&Instance
->Blocks
, Block
, Completed
, &Instance
->TotalBlock
);
182 if (Status
== EFI_NOT_FOUND
) {
184 } else if (EFI_ERROR (Status
)) {
188 if (Token
->CheckPacket
!= NULL
) {
189 Status
= Token
->CheckPacket (&Instance
->Mtftp4
, Token
, (UINT16
) Len
, Packet
);
191 if (EFI_ERROR (Status
)) {
194 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
195 (UINT8
*) "User aborted download"
202 if (Token
->Buffer
!= NULL
) {
203 Start
= MultU64x32 (Instance
->TotalBlock
- 1, Instance
->BlkSize
);
205 if (Start
+ DataLen
<= Token
->BufferSize
) {
206 CopyMem ((UINT8
*) Token
->Buffer
+ Start
, Packet
->Data
.Data
, DataLen
);
209 // Update the file size when received the last block
211 if ((Instance
->LastBlock
== Block
) && Completed
) {
212 Token
->BufferSize
= Start
+ DataLen
;
215 } else if (Instance
->LastBlock
!= 0) {
217 // Don't save the data if the buffer is too small, return
218 // EFI_BUFFER_TOO_SMALL if received the last packet. This
219 // will give a accurate file length.
221 Token
->BufferSize
= Start
+ DataLen
;
225 EFI_MTFTP4_ERRORCODE_DISK_FULL
,
226 (UINT8
*) "User provided memory block is too small"
229 return EFI_BUFFER_TOO_SMALL
;
238 Function to process the received data packets.
240 It will save the block then send back an ACK if it is active.
242 @param Instance The downloading MTFTP session
243 @param Packet The packet received
244 @param Len The length of the packet
245 @param Multicast Whether this packet is multicast or unicast
246 @param Completed Return whether the download has completed
248 @retval EFI_SUCCESS The data packet is successfully processed
249 @retval EFI_ABORTED The download is aborted by the user
250 @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
254 Mtftp4RrqHandleData (
255 IN MTFTP4_PROTOCOL
*Instance
,
256 IN EFI_MTFTP4_PACKET
*Packet
,
258 IN BOOLEAN Multicast
,
259 OUT BOOLEAN
*Completed
267 Status
= EFI_SUCCESS
;
268 BlockNum
= NTOHS (Packet
->Data
.Block
);
269 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
271 ASSERT (Expected
>= 0);
274 // If we are active and received an unexpected packet, transmit
275 // the ACK for the block we received, then restart receiving the
276 // expected one. If we are passive, save the block.
278 if (Instance
->Master
&& (Expected
!= BlockNum
)) {
280 // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).
282 return Mtftp4RrqSendAck (Instance
, (UINT16
) (Expected
- 1));
285 Status
= Mtftp4RrqSaveBlock (Instance
, Packet
, Len
);
287 if (EFI_ERROR (Status
)) {
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
);