NetworkPkg/Mtftp6Dxe: Support windowsize in read request operation.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=886

This patch is to support the TFTP windowsize option described in RFC 7440.
The feature allows the client and server to negotiate a window size of
consecutive blocks to send as an alternative for replacing the single-block
lockstep schema.

Currently, the windowsize for write request operation is not supported since
there is no real use cases.

Cc: Ye Ting <ting.ye@intel.com>
Cc: Fu Siyuan <siyuan.fu@intel.com>
Cc: Shao Ming <ming.shao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Wu Jiaxin <jiaxin.wu@intel.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Fu Siyuan <siyuan.fu@intel.com>
Reviewed-by: Ye Ting <ting.ye@intel.com>
This commit is contained in:
Jiaxin Wu 2018-09-14 15:47:52 +08:00
parent 6c047cfab1
commit f3427f12a4
6 changed files with 90 additions and 24 deletions

View File

@ -1,7 +1,7 @@
/** @file /** @file
Mtftp6 internal data structure and definition declaration. Mtftp6 internal data structure and definition declaration.
Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved. <BR> Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. <BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
@ -46,6 +46,7 @@ typedef struct _MTFTP6_INSTANCE MTFTP6_INSTANCE;
#define MTFTP6_GET_MAPPING_TIMEOUT 3 #define MTFTP6_GET_MAPPING_TIMEOUT 3
#define MTFTP6_DEFAULT_MAX_RETRY 5 #define MTFTP6_DEFAULT_MAX_RETRY 5
#define MTFTP6_DEFAULT_BLK_SIZE 512 #define MTFTP6_DEFAULT_BLK_SIZE 512
#define MTFTP6_DEFAULT_WINDOWSIZE 1
#define MTFTP6_TICK_PER_SECOND 10000000U #define MTFTP6_TICK_PER_SECOND 10000000U
#define MTFTP6_SERVICE_FROM_THIS(a) CR (a, MTFTP6_SERVICE, ServiceBinding, MTFTP6_SERVICE_SIGNATURE) #define MTFTP6_SERVICE_FROM_THIS(a) CR (a, MTFTP6_SERVICE, ServiceBinding, MTFTP6_SERVICE_SIGNATURE)
@ -77,6 +78,16 @@ struct _MTFTP6_INSTANCE {
UINT16 LastBlk; UINT16 LastBlk;
LIST_ENTRY BlkList; LIST_ENTRY BlkList;
UINT16 Operation;
UINT16 WindowSize;
//
// Record the total received block number and the already acked block number.
//
UINT64 TotalBlock;
UINT64 AckedBlock;
EFI_IPv6_ADDRESS ServerIp; EFI_IPv6_ADDRESS ServerIp;
UINT16 ServerCmdPort; UINT16 ServerCmdPort;
UINT16 ServerDataPort; UINT16 ServerDataPort;

View File

@ -1,7 +1,7 @@
/** @file /** @file
Mtftp6 option parse functions implementation. Mtftp6 option parse functions implementation.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR> Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
@ -17,6 +17,7 @@
CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM] = { CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM] = {
"blksize", "blksize",
"windowsize",
"timeout", "timeout",
"tsize", "tsize",
"multicast" "multicast"
@ -146,6 +147,7 @@ Mtftp6ParseMcastOption (
@param[in] Count The num of the extension options. @param[in] Count The num of the extension options.
@param[in] IsRequest If FALSE, the extension options is included @param[in] IsRequest If FALSE, the extension options is included
by a request packet. by a request packet.
@param[in] Operation The current performed operation.
@param[in] ExtInfo The pointer to the option information to be filled. @param[in] ExtInfo The pointer to the option information to be filled.
@retval EFI_SUCCESS Parse the multicast option successfully. @retval EFI_SUCCESS Parse the multicast option successfully.
@ -158,6 +160,7 @@ Mtftp6ParseExtensionOption (
IN EFI_MTFTP6_OPTION *Options, IN EFI_MTFTP6_OPTION *Options,
IN UINT32 Count, IN UINT32 Count,
IN BOOLEAN IsRequest, IN BOOLEAN IsRequest,
IN UINT16 Operation,
IN MTFTP6_EXT_OPTION_INFO *ExtInfo IN MTFTP6_EXT_OPTION_INFO *ExtInfo
) )
{ {
@ -228,6 +231,23 @@ Mtftp6ParseExtensionOption (
ExtInfo->BitMap |= MTFTP6_OPT_MCAST_BIT; ExtInfo->BitMap |= MTFTP6_OPT_MCAST_BIT;
} else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "windowsize") == 0) {
if (Operation == EFI_MTFTP6_OPCODE_WRQ) {
//
// Currently, windowsize is not supported in the write operation.
//
return EFI_UNSUPPORTED;
}
Value = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);
if ((Value < 1)) {
return EFI_INVALID_PARAMETER;
}
ExtInfo->WindowSize = (UINT16) Value;
ExtInfo->BitMap |= MTFTP6_OPT_WINDOWSIZE_BIT;
} else if (IsRequest) { } else if (IsRequest) {
// //
// If it's a request, unsupported; else if it's a reply, ignore. // If it's a request, unsupported; else if it's a reply, ignore.

View File

@ -1,7 +1,7 @@
/** @file /** @file
Mtftp6 option parse functions declaration. Mtftp6 option parse functions declaration.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR> Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
@ -26,7 +26,7 @@
#include <Library/MemoryAllocationLib.h> #include <Library/MemoryAllocationLib.h>
#include <Library/UefiRuntimeServicesTableLib.h> #include <Library/UefiRuntimeServicesTableLib.h>
#define MTFTP6_SUPPORTED_OPTIONS_NUM 4 #define MTFTP6_SUPPORTED_OPTIONS_NUM 5
#define MTFTP6_OPCODE_LEN 2 #define MTFTP6_OPCODE_LEN 2
#define MTFTP6_ERRCODE_LEN 2 #define MTFTP6_ERRCODE_LEN 2
#define MTFTP6_BLKNO_LEN 2 #define MTFTP6_BLKNO_LEN 2
@ -39,11 +39,13 @@
#define MTFTP6_OPT_TIMEOUT_BIT 0x02 #define MTFTP6_OPT_TIMEOUT_BIT 0x02
#define MTFTP6_OPT_TSIZE_BIT 0x04 #define MTFTP6_OPT_TSIZE_BIT 0x04
#define MTFTP6_OPT_MCAST_BIT 0x08 #define MTFTP6_OPT_MCAST_BIT 0x08
#define MTFTP6_OPT_WINDOWSIZE_BIT 0X10
extern CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM]; extern CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM];
typedef struct { typedef struct {
UINT16 BlkSize; UINT16 BlkSize;
UINT16 WindowSize;
UINT8 Timeout; UINT8 Timeout;
UINT32 Tsize; UINT32 Tsize;
EFI_IPv6_ADDRESS McastIp; EFI_IPv6_ADDRESS McastIp;
@ -76,11 +78,12 @@ Mtftp6ParseMcastOption (
@param[in] Count The num of the extension options. @param[in] Count The num of the extension options.
@param[in] IsRequest If FALSE, the extension options is included @param[in] IsRequest If FALSE, the extension options is included
by a request packet. by a request packet.
@param[in] Operation The current performed operation.
@param[in] ExtInfo The pointer to the option information to be filled. @param[in] ExtInfo The pointer to the option information to be filled.
@retval EFI_SUCCESS Parse the multi-cast option successfully. @retval EFI_SUCCESS Parse the multicast option successfully.
@retval EFI_INVALID_PARAMETER An option is malformatted. @retval EFI_INVALID_PARAMETER There is one option is malformatted at least.
@retval EFI_UNSUPPORTED An option is not supported. @retval EFI_UNSUPPORTED There is one option is not supported at least.
**/ **/
EFI_STATUS EFI_STATUS
@ -88,6 +91,7 @@ Mtftp6ParseExtensionOption (
IN EFI_MTFTP6_OPTION *Options, IN EFI_MTFTP6_OPTION *Options,
IN UINT32 Count, IN UINT32 Count,
IN BOOLEAN IsRequest, IN BOOLEAN IsRequest,
IN UINT16 Operation,
IN MTFTP6_EXT_OPTION_INFO *ExtInfo IN MTFTP6_EXT_OPTION_INFO *ExtInfo
); );

View File

@ -1,7 +1,7 @@
/** @file /** @file
Mtftp6 Rrq process functions implementation. Mtftp6 Rrq process functions implementation.
Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR> Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
@ -35,6 +35,9 @@ Mtftp6RrqSendAck (
{ {
EFI_MTFTP6_PACKET *Ack; EFI_MTFTP6_PACKET *Ack;
NET_BUF *Packet; NET_BUF *Packet;
EFI_STATUS Status;
Status = EFI_SUCCESS;
// //
// Allocate net buffer to create ack packet. // Allocate net buffer to create ack packet.
@ -61,7 +64,12 @@ Mtftp6RrqSendAck (
Instance->CurRetry = 0; Instance->CurRetry = 0;
Instance->LastPacket = Packet; Instance->LastPacket = Packet;
return Mtftp6TransmitPacket (Instance, Packet); Status = Mtftp6TransmitPacket (Instance, Packet);
if (!EFI_ERROR (Status)) {
Instance->AckedBlock = Instance->TotalBlock;
}
return Status;
} }
@ -94,7 +102,6 @@ Mtftp6RrqSaveBlock (
UINT16 Block; UINT16 Block;
UINT64 Start; UINT64 Start;
UINT32 DataLen; UINT32 DataLen;
UINT64 TotalBlock;
BOOLEAN Completed; BOOLEAN Completed;
Completed = FALSE; Completed = FALSE;
@ -118,7 +125,7 @@ Mtftp6RrqSaveBlock (
// to accept transfers of unlimited size. So TotalBlock is memorised as // to accept transfers of unlimited size. So TotalBlock is memorised as
// continuous block counter. // continuous block counter.
// //
Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, &TotalBlock); Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, &Instance->TotalBlock);
if (Status == EFI_NOT_FOUND) { if (Status == EFI_NOT_FOUND) {
return EFI_SUCCESS; return EFI_SUCCESS;
@ -154,7 +161,7 @@ Mtftp6RrqSaveBlock (
if (Token->Buffer != NULL) { if (Token->Buffer != NULL) {
Start = MultU64x32 (TotalBlock - 1, Instance->BlkSize); Start = MultU64x32 (Instance->TotalBlock - 1, Instance->BlkSize);
if (Start + DataLen <= Token->BufferSize) { if (Start + DataLen <= Token->BufferSize) {
CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen); CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);
// //
@ -224,15 +231,16 @@ Mtftp6RrqHandleData (
INTN Expected; INTN Expected;
*IsCompleted = FALSE; *IsCompleted = FALSE;
Status = EFI_SUCCESS;
BlockNum = NTOHS (Packet->Data.Block); BlockNum = NTOHS (Packet->Data.Block);
Expected = Mtftp6GetNextBlockNum (&Instance->BlkList); Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
ASSERT (Expected >= 0); ASSERT (Expected >= 0);
// //
// If we are active and received an unexpected packet, retransmit // If we are active and received an unexpected packet, transmit
// the last ACK then restart receiving. If we are passive, save // the ACK for the block we received, then restart receiving the
// the block. // expected one. If we are passive, save the block.
// //
if (Instance->IsMaster && (Expected != BlockNum)) { if (Instance->IsMaster && (Expected != BlockNum)) {
// //
@ -242,8 +250,10 @@ Mtftp6RrqHandleData (
NetbufFree (*UdpPacket); NetbufFree (*UdpPacket);
*UdpPacket = NULL; *UdpPacket = NULL;
Mtftp6TransmitPacket (Instance, Instance->LastPacket); //
return EFI_SUCCESS; // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).
//
return Mtftp6RrqSendAck (Instance, (UINT16) (Expected - 1));
} }
Status = Mtftp6RrqSaveBlock (Instance, Packet, Len, UdpPacket); Status = Mtftp6RrqSaveBlock (Instance, Packet, Len, UdpPacket);
@ -288,10 +298,12 @@ Mtftp6RrqHandleData (
NetbufFree (*UdpPacket); NetbufFree (*UdpPacket);
*UdpPacket = NULL; *UdpPacket = NULL;
Mtftp6RrqSendAck (Instance, BlockNum); if (Instance->WindowSize == (Instance->TotalBlock - Instance->AckedBlock) || Expected < 0) {
Status = Mtftp6RrqSendAck (Instance, BlockNum);
}
} }
return EFI_SUCCESS; return Status;
} }
@ -326,10 +338,11 @@ Mtftp6RrqOackValid (
} }
// //
// Server can only specify a smaller block size to be used and // Server can only specify a smaller block size and windowsize to be used and
// return the timeout matches that requested. // return the timeout matches that requested.
// //
if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) || if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
(((ReplyInfo->BitMap & MTFTP6_OPT_WINDOWSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
(((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout)) (((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))
) { ) {
return FALSE; return FALSE;
@ -485,7 +498,7 @@ Mtftp6RrqHandleOack (
// //
// Parse the extensive options in the packet. // Parse the extensive options in the packet.
// //
Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo); Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, Instance->Operation, &ExtInfo);
if (EFI_ERROR (Status) || !Mtftp6RrqOackValid (Instance, &ExtInfo, &Instance->ExtInfo)) { if (EFI_ERROR (Status) || !Mtftp6RrqOackValid (Instance, &ExtInfo, &Instance->ExtInfo)) {
// //
@ -515,7 +528,7 @@ Mtftp6RrqHandleOack (
// //
// Save the multicast info. Always update the Master, only update the // Save the multicast info. Always update the Master, only update the
// multicast IP address, block size, timeoute at the first time. If IP // multicast IP address, block size, window size, timeoute at the first time. If IP
// address is updated, create a UDP child to receive the multicast. // address is updated, create a UDP child to receive the multicast.
// //
Instance->IsMaster = ExtInfo.IsMaster; Instance->IsMaster = ExtInfo.IsMaster;
@ -612,6 +625,10 @@ Mtftp6RrqHandleOack (
Instance->BlkSize = ExtInfo.BlkSize; Instance->BlkSize = ExtInfo.BlkSize;
} }
if (ExtInfo.WindowSize != 0) {
Instance->WindowSize = ExtInfo.WindowSize;
}
if (ExtInfo.Timeout != 0) { if (ExtInfo.Timeout != 0) {
Instance->Timeout = ExtInfo.Timeout; Instance->Timeout = ExtInfo.Timeout;
} }
@ -625,6 +642,10 @@ Mtftp6RrqHandleOack (
Instance->BlkSize = ExtInfo.BlkSize; Instance->BlkSize = ExtInfo.BlkSize;
} }
if (ExtInfo.WindowSize != 0) {
Instance->WindowSize = ExtInfo.WindowSize;
}
if (ExtInfo.Timeout != 0) { if (ExtInfo.Timeout != 0) {
Instance->Timeout = ExtInfo.Timeout; Instance->Timeout = ExtInfo.Timeout;
} }

View File

@ -979,6 +979,10 @@ Mtftp6OperationClean (
Instance->ServerDataPort = 0; Instance->ServerDataPort = 0;
Instance->McastPort = 0; Instance->McastPort = 0;
Instance->BlkSize = 0; Instance->BlkSize = 0;
Instance->Operation = 0;
Instance->WindowSize = 1;
Instance->TotalBlock = 0;
Instance->AckedBlock = 0;
Instance->LastBlk = 0; Instance->LastBlk = 0;
Instance->PacketToLive = 0; Instance->PacketToLive = 0;
Instance->MaxRetry = 0; Instance->MaxRetry = 0;
@ -1051,6 +1055,8 @@ Mtftp6OperationStart (
Status = EFI_SUCCESS; Status = EFI_SUCCESS;
Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK); Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
Instance->Operation = OpCode;
// //
// Parse the extension options in the request packet. // Parse the extension options in the request packet.
// //
@ -1060,6 +1066,7 @@ Mtftp6OperationStart (
Token->OptionList, Token->OptionList,
Token->OptionCount, Token->OptionCount,
TRUE, TRUE,
Instance->Operation,
&Instance->ExtInfo &Instance->ExtInfo
); );
@ -1105,6 +1112,9 @@ Mtftp6OperationStart (
if (Instance->BlkSize == 0) { if (Instance->BlkSize == 0) {
Instance->BlkSize = MTFTP6_DEFAULT_BLK_SIZE; Instance->BlkSize = MTFTP6_DEFAULT_BLK_SIZE;
} }
if (Instance->WindowSize == 0) {
Instance->WindowSize = MTFTP6_DEFAULT_WINDOWSIZE;
}
if (Instance->MaxRetry == 0) { if (Instance->MaxRetry == 0) {
Instance->MaxRetry = MTFTP6_DEFAULT_MAX_RETRY; Instance->MaxRetry = MTFTP6_DEFAULT_MAX_RETRY;
} }

View File

@ -318,7 +318,7 @@ Mtftp6WrqHandleOack (
} }
ASSERT (Options != NULL); ASSERT (Options != NULL);
Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo); Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, Instance->Operation, &ExtInfo);
if (EFI_ERROR(Status) || !Mtftp6WrqOackValid (&ExtInfo, &Instance->ExtInfo)) { if (EFI_ERROR(Status) || !Mtftp6WrqOackValid (&ExtInfo, &Instance->ExtInfo)) {
// //