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
;
103 Packet
= NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER
));
104 if (Packet
== NULL
) {
105 return EFI_OUT_OF_RESOURCES
;
108 Ack
= (EFI_MTFTP4_PACKET
*) NetbufAllocSpace (
110 sizeof (EFI_MTFTP4_ACK_HEADER
),
113 ASSERT (Ack
!= NULL
);
115 Ack
->Ack
.OpCode
= HTONS (EFI_MTFTP4_OPCODE_ACK
);
116 Ack
->Ack
.Block
[0] = HTONS (BlkNo
);
118 return Mtftp4SendPacket (Instance
, Packet
);
123 Deliver the received data block to the user, which can be saved
124 in the user provide buffer or through the CheckPacket callback.
126 @param Instance The Mtftp session
127 @param Packet The received data packet
128 @param Len The packet length
130 @retval EFI_SUCCESS The data is saved successfully
131 @retval EFI_ABORTED The user tells to abort by return an error through
133 @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small and buffer length is
134 updated to the actual buffer size needed.
139 IN OUT MTFTP4_PROTOCOL
*Instance
,
140 IN EFI_MTFTP4_PACKET
*Packet
,
144 EFI_MTFTP4_TOKEN
*Token
;
153 Token
= Instance
->Token
;
154 Block
= NTOHS (Packet
->Data
.Block
);
155 DataLen
= Len
- MTFTP4_DATA_HEAD_LEN
;
158 // This is the last block, save the block no
160 if (DataLen
< Instance
->BlkSize
) {
162 Instance
->LastBlock
= Block
;
163 Mtftp4SetLastBlockNum (&Instance
->Blocks
, Block
);
167 // Remove this block number from the file hole. If Mtftp4RemoveBlockNum
168 // returns EFI_NOT_FOUND, the block has been saved, don't save it again.
169 // Note that : For bigger files, allowing the block counter to roll over
170 // to accept transfers of unlimited size. So TotalBlock is memorised as
171 // continuous block counter.
173 Status
= Mtftp4RemoveBlockNum (&Instance
->Blocks
, Block
, Completed
, &TotalBlock
);
175 if (Status
== EFI_NOT_FOUND
) {
177 } else if (EFI_ERROR (Status
)) {
181 if (Token
->CheckPacket
!= NULL
) {
182 Status
= Token
->CheckPacket (&Instance
->Mtftp4
, Token
, (UINT16
) Len
, Packet
);
184 if (EFI_ERROR (Status
)) {
187 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
188 (UINT8
*) "User aborted download"
195 if (Token
->Buffer
!= NULL
) {
196 Start
= MultU64x32 (TotalBlock
- 1, Instance
->BlkSize
);
198 if (Start
+ DataLen
<= Token
->BufferSize
) {
199 CopyMem ((UINT8
*) Token
->Buffer
+ Start
, Packet
->Data
.Data
, DataLen
);
202 // Update the file size when received the last block
204 if ((Instance
->LastBlock
== Block
) && Completed
) {
205 Token
->BufferSize
= Start
+ DataLen
;
208 } else if (Instance
->LastBlock
!= 0) {
210 // Don't save the data if the buffer is too small, return
211 // EFI_BUFFER_TOO_SMALL if received the last packet. This
212 // will give a accurate file length.
214 Token
->BufferSize
= Start
+ DataLen
;
218 EFI_MTFTP4_ERRORCODE_DISK_FULL
,
219 (UINT8
*) "User provided memory block is too small"
222 return EFI_BUFFER_TOO_SMALL
;
231 Function to process the received data packets.
233 It will save the block then send back an ACK if it is active.
235 @param Instance The downloading MTFTP session
236 @param Packet The packet received
237 @param Len The length of the packet
238 @param Multicast Whether this packet is multicast or unicast
239 @param Completed Return whether the download has completed
241 @retval EFI_SUCCESS The data packet is successfully processed
242 @retval EFI_ABORTED The download is aborted by the user
243 @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
247 Mtftp4RrqHandleData (
248 IN MTFTP4_PROTOCOL
*Instance
,
249 IN EFI_MTFTP4_PACKET
*Packet
,
251 IN BOOLEAN Multicast
,
252 OUT BOOLEAN
*Completed
260 BlockNum
= NTOHS (Packet
->Data
.Block
);
261 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
263 ASSERT (Expected
>= 0);
266 // If we are active and received an unexpected packet, retransmit
267 // the last ACK then restart receiving. If we are passive, save
270 if (Instance
->Master
&& (Expected
!= BlockNum
)) {
271 Mtftp4Retransmit (Instance
);
275 Status
= Mtftp4RrqSaveBlock (Instance
, Packet
, Len
);
277 if (EFI_ERROR (Status
)) {
282 // Reset the passive client's timer whenever it received a
283 // valid data packet.
285 if (!Instance
->Master
) {
286 Mtftp4SetTimeout (Instance
);
290 // Check whether we have received all the blocks. Send the ACK if we
291 // are active (unicast client or master client for multicast download).
292 // If we have received all the blocks, send an ACK even if we are passive
293 // to tell the server that we are done.
295 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
297 if (Instance
->Master
|| (Expected
< 0)) {
300 // If we are passive client, then the just received Block maybe
301 // isn't the last block. We need to send an ACK to the last block
302 // to inform the server that we are done. If we are active client,
303 // the Block == Instance->LastBlock.
305 BlockNum
= Instance
->LastBlock
;
309 BlockNum
= (UINT16
) (Expected
- 1);
312 Mtftp4RrqSendAck (Instance
, BlockNum
);
320 Validate whether the options received in the server's OACK packet is valid.
322 The options are valid only if:
323 1. The server doesn't include options not requested by us
324 2. The server can only use smaller blksize than that is requested
325 3. The server can only use the same timeout as requested
326 4. The server doesn't change its multicast channel.
328 @param This The downloading Mtftp session
329 @param Reply The options in the OACK packet
330 @param Request The requested options
332 @retval TRUE The options in the OACK is OK.
333 @retval FALSE The options in the OACK is invalid.
338 IN MTFTP4_PROTOCOL
*This
,
339 IN MTFTP4_OPTION
*Reply
,
340 IN MTFTP4_OPTION
*Request
345 // It is invalid for server to return options we don't request
347 if ((Reply
->Exist
&~Request
->Exist
) != 0) {
352 // Server can only specify a smaller block size to be used and
353 // return the timeout matches that requested.
355 if ((((Reply
->Exist
& MTFTP4_BLKSIZE_EXIST
) != 0)&& (Reply
->BlkSize
> Request
->BlkSize
)) ||
356 (((Reply
->Exist
& MTFTP4_TIMEOUT_EXIST
) != 0) && (Reply
->Timeout
!= Request
->Timeout
))) {
361 // The server can send ",,master" to client to change its master
362 // setting. But if it use the specific multicast channel, it can't
363 // change the setting.
365 if (((Reply
->Exist
& MTFTP4_MCAST_EXIST
) != 0) && (This
->McastIp
!= 0)) {
366 if ((Reply
->McastIp
!= 0) && (Reply
->McastIp
!= This
->McastIp
)) {
370 if ((Reply
->McastPort
!= 0) && (Reply
->McastPort
!= This
->McastPort
)) {
380 Configure a UDP IO port to receive the multicast.
382 @param McastIo The UDP IO to configure
383 @param Context The opaque parameter to the function which is the
386 @retval EFI_SUCCESS The UDP child is successfully configured.
387 @retval Others Failed to configure the UDP child.
392 Mtftp4RrqConfigMcastPort (
397 MTFTP4_PROTOCOL
*Instance
;
398 EFI_MTFTP4_CONFIG_DATA
*Config
;
399 EFI_UDP4_CONFIG_DATA UdpConfig
;
400 EFI_IPv4_ADDRESS Group
;
404 Instance
= (MTFTP4_PROTOCOL
*) Context
;
405 Config
= &Instance
->Config
;
407 UdpConfig
.AcceptBroadcast
= FALSE
;
408 UdpConfig
.AcceptPromiscuous
= FALSE
;
409 UdpConfig
.AcceptAnyPort
= FALSE
;
410 UdpConfig
.AllowDuplicatePort
= FALSE
;
411 UdpConfig
.TypeOfService
= 0;
412 UdpConfig
.TimeToLive
= 64;
413 UdpConfig
.DoNotFragment
= FALSE
;
414 UdpConfig
.ReceiveTimeout
= 0;
415 UdpConfig
.TransmitTimeout
= 0;
416 UdpConfig
.UseDefaultAddress
= Config
->UseDefaultSetting
;
417 IP4_COPY_ADDRESS (&UdpConfig
.StationAddress
, &Config
->StationIp
);
418 IP4_COPY_ADDRESS (&UdpConfig
.SubnetMask
, &Config
->SubnetMask
);
419 UdpConfig
.StationPort
= Instance
->McastPort
;
420 UdpConfig
.RemotePort
= 0;
422 Ip
= HTONL (Instance
->ServerIp
);
423 IP4_COPY_ADDRESS (&UdpConfig
.RemoteAddress
, &Ip
);
425 Status
= McastIo
->Protocol
.Udp4
->Configure (McastIo
->Protocol
.Udp4
, &UdpConfig
);
427 if (EFI_ERROR (Status
)) {
431 if (!Config
->UseDefaultSetting
&&
432 !EFI_IP4_EQUAL (&mZeroIp4Addr
, &Config
->GatewayIp
)) {
434 // The station IP address is manually configured and the Gateway IP is not 0.
435 // Add the default route for this UDP instance.
437 Status
= McastIo
->Protocol
.Udp4
->Routes (
438 McastIo
->Protocol
.Udp4
,
445 if (EFI_ERROR (Status
)) {
446 McastIo
->Protocol
.Udp4
->Configure (McastIo
->Protocol
.Udp4
, NULL
);
452 // join the multicast group
454 Ip
= HTONL (Instance
->McastIp
);
455 IP4_COPY_ADDRESS (&Group
, &Ip
);
457 return McastIo
->Protocol
.Udp4
->Groups (McastIo
->Protocol
.Udp4
, TRUE
, &Group
);
462 Function to process the OACK.
464 It will first validate the OACK packet, then update the various negotiated parameters.
466 @param Instance The download MTFTP session
467 @param Packet The packet received
468 @param Len The packet length
469 @param Multicast Whether this packet is received as a multicast
470 @param Completed Returns whether the download has completed. NOT
471 used by this function.
473 @retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child
474 @retval EFI_TFTP_ERROR Some error happened during the process
475 @retval EFI_SUCCESS The OACK is successfully processed.
479 Mtftp4RrqHandleOack (
480 IN OUT MTFTP4_PROTOCOL
*Instance
,
481 IN EFI_MTFTP4_PACKET
*Packet
,
483 IN BOOLEAN Multicast
,
484 OUT BOOLEAN
*Completed
490 EFI_UDP4_PROTOCOL
*Udp4
;
495 // If already started the master download, don't change the
496 // setting. Master download always succeeds.
498 Expected
= Mtftp4GetNextBlockNum (&Instance
->Blocks
);
499 ASSERT (Expected
!= -1);
501 if (Instance
->Master
&& (Expected
!= 1)) {
506 // Parse and validate the options from server
508 ZeroMem (&Reply
, sizeof (MTFTP4_OPTION
));
510 Status
= Mtftp4ParseOptionOack (Packet
, Len
, &Reply
);
512 if (EFI_ERROR (Status
) ||
513 !Mtftp4RrqOackValid (Instance
, &Reply
, &Instance
->RequestOption
)) {
515 // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
517 if (Status
!= EFI_OUT_OF_RESOURCES
) {
520 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
521 (UINT8
*) "Mal-formated OACK packet"
525 return EFI_TFTP_ERROR
;
528 if ((Reply
.Exist
& MTFTP4_MCAST_EXIST
) != 0) {
531 // Save the multicast info. Always update the Master, only update the
532 // multicast IP address, block size, timeoute at the first time. If IP
533 // address is updated, create a UDP child to receive the multicast.
535 Instance
->Master
= Reply
.Master
;
537 if (Instance
->McastIp
== 0) {
538 if ((Reply
.McastIp
== 0) || (Reply
.McastPort
== 0)) {
541 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION
,
542 (UINT8
*) "Illegal multicast setting"
545 return EFI_TFTP_ERROR
;
549 // Create a UDP child then start receive the multicast from it.
551 Instance
->McastIp
= Reply
.McastIp
;
552 Instance
->McastPort
= Reply
.McastPort
;
553 if (Instance
->McastUdpPort
== NULL
) {
554 Instance
->McastUdpPort
= UdpIoCreateIo (
555 Instance
->Service
->Controller
,
556 Instance
->Service
->Image
,
557 Mtftp4RrqConfigMcastPort
,
561 if (Instance
->McastUdpPort
!= NULL
) {
562 Status
= gBS
->OpenProtocol (
563 Instance
->McastUdpPort
->UdpHandle
,
564 &gEfiUdp4ProtocolGuid
,
566 Instance
->Service
->Image
,
568 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
570 if (EFI_ERROR (Status
)) {
571 UdpIoFreeIo (Instance
->McastUdpPort
);
572 Instance
->McastUdpPort
= NULL
;
573 return EFI_DEVICE_ERROR
;
579 if (Instance
->McastUdpPort
== NULL
) {
580 return EFI_DEVICE_ERROR
;
583 Status
= UdpIoRecvDatagram (Instance
->McastUdpPort
, Mtftp4RrqInput
, Instance
, 0);
585 if (EFI_ERROR (Status
)) {
588 EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION
,
589 (UINT8
*) "Failed to create socket to receive multicast packet"
596 // Update the parameters used.
598 if (Reply
.BlkSize
!= 0) {
599 Instance
->BlkSize
= Reply
.BlkSize
;
602 if (Reply
.Timeout
!= 0) {
603 Instance
->Timeout
= Reply
.Timeout
;
608 Instance
->Master
= TRUE
;
610 if (Reply
.BlkSize
!= 0) {
611 Instance
->BlkSize
= Reply
.BlkSize
;
614 if (Reply
.Timeout
!= 0) {
615 Instance
->Timeout
= Reply
.Timeout
;
620 // Send an ACK to (Expected - 1) which is 0 for unicast download,
621 // or tell the server we want to receive the Expected block.
623 return Mtftp4RrqSendAck (Instance
, (UINT16
) (Expected
- 1));
628 The packet process callback for MTFTP download.
630 @param UdpPacket The packet received
631 @param EndPoint The local/remote access point of the packet
632 @param IoStatus The status of the receiving
633 @param Context Opaque parameter, which is the MTFTP session
639 IN NET_BUF
*UdpPacket
,
640 IN UDP_END_POINT
*EndPoint
,
641 IN EFI_STATUS IoStatus
,
645 MTFTP4_PROTOCOL
*Instance
;
646 EFI_MTFTP4_PACKET
*Packet
;
653 Instance
= (MTFTP4_PROTOCOL
*) Context
;
654 NET_CHECK_SIGNATURE (Instance
, MTFTP4_PROTOCOL_SIGNATURE
);
656 Status
= EFI_SUCCESS
;
661 if (EFI_ERROR (IoStatus
)) {
666 ASSERT (UdpPacket
!= NULL
);
669 // Find the port this packet is from to restart receive correctly.
671 Multicast
= (BOOLEAN
) (EndPoint
->LocalAddr
.Addr
[0] == Instance
->McastIp
);
673 if (UdpPacket
->TotalSize
< MTFTP4_OPCODE_LEN
) {
678 // Client send initial request to server's listening port. Server
679 // will select a UDP port to communicate with the client. The server
680 // is required to use the same port as RemotePort to multicast the
683 if (EndPoint
->RemotePort
!= Instance
->ConnectedPort
) {
684 if (Instance
->ConnectedPort
!= 0) {
687 Instance
->ConnectedPort
= EndPoint
->RemotePort
;
692 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
694 Len
= UdpPacket
->TotalSize
;
696 if (UdpPacket
->BlockOpNum
> 1) {
697 Packet
= AllocatePool (Len
);
699 if (Packet
== NULL
) {
700 Status
= EFI_OUT_OF_RESOURCES
;
704 NetbufCopy (UdpPacket
, 0, Len
, (UINT8
*) Packet
);
707 Packet
= (EFI_MTFTP4_PACKET
*) NetbufGetByte (UdpPacket
, 0, NULL
);
708 ASSERT (Packet
!= NULL
);
711 Opcode
= NTOHS (Packet
->OpCode
);
714 // Call the user's CheckPacket if provided. Abort the transmission
715 // if CheckPacket returns an EFI_ERROR code.
717 if ((Instance
->Token
->CheckPacket
!= NULL
) &&
718 ((Opcode
== EFI_MTFTP4_OPCODE_OACK
) || (Opcode
== EFI_MTFTP4_OPCODE_ERROR
))) {
720 Status
= Instance
->Token
->CheckPacket (
727 if (EFI_ERROR (Status
)) {
729 // Send an error message to the server to inform it
731 if (Opcode
!= EFI_MTFTP4_OPCODE_ERROR
) {
734 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED
,
735 (UINT8
*) "User aborted the transfer"
739 Status
= EFI_ABORTED
;
745 case EFI_MTFTP4_OPCODE_DATA
:
746 if ((Len
> (UINT32
) (MTFTP4_DATA_HEAD_LEN
+ Instance
->BlkSize
)) ||
747 (Len
< (UINT32
) MTFTP4_DATA_HEAD_LEN
)) {
751 Status
= Mtftp4RrqHandleData (Instance
, Packet
, Len
, Multicast
, &Completed
);
754 case EFI_MTFTP4_OPCODE_OACK
:
755 if (Multicast
|| (Len
<= MTFTP4_OPCODE_LEN
)) {
759 Status
= Mtftp4RrqHandleOack (Instance
, Packet
, Len
, Multicast
, &Completed
);
762 case EFI_MTFTP4_OPCODE_ERROR
:
763 Status
= EFI_TFTP_ERROR
;
773 // Free the resources, then if !EFI_ERROR (Status), restart the
774 // receive, otherwise end the session.
776 if ((Packet
!= NULL
) && (UdpPacket
->BlockOpNum
> 1)) {
780 if (UdpPacket
!= NULL
) {
781 NetbufFree (UdpPacket
);
784 if (!EFI_ERROR (Status
) && !Completed
) {
786 Status
= UdpIoRecvDatagram (Instance
->McastUdpPort
, Mtftp4RrqInput
, Instance
, 0);
788 Status
= UdpIoRecvDatagram (Instance
->UnicastPort
, Mtftp4RrqInput
, Instance
, 0);
792 if (EFI_ERROR (Status
) || Completed
) {
793 Mtftp4CleanOperation (Instance
, Status
);