/** @file\r
Routines to process Rrq (download).\r
- \r
-Copyright (c) 2006 - 2007, Intel Corporation<BR>\r
-All rights reserved. This program and the accompanying materials\r
+\r
+(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
http://opensource.org/licenses/bsd-license.php<BR>\r
The packet process callback for MTFTP download.\r
\r
@param UdpPacket The packet received\r
- @param Points The local/remote access point of the packet\r
+ @param EndPoint The local/remote access point of the packet\r
@param IoStatus The status of the receiving\r
@param Context Opaque parameter, which is the MTFTP session\r
\r
**/\r
VOID\r
+EFIAPI\r
Mtftp4RrqInput (\r
IN NET_BUF *UdpPacket,\r
- IN UDP_POINTS *Points,\r
+ IN UDP_END_POINT *EndPoint,\r
IN EFI_STATUS IoStatus,\r
IN VOID *Context\r
);\r
\r
\r
/**\r
- Start the MTFTP session to download. \r
- \r
- It will first initialize some of the internal states then build and send a RRQ \r
+ Start the MTFTP session to download.\r
+\r
+ It will first initialize some of the internal states then build and send a RRQ\r
reqeuest packet, at last, it will start receive for the downloading.\r
\r
@param Instance The Mtftp session\r
{\r
EFI_MTFTP4_PACKET *Ack;\r
NET_BUF *Packet;\r
+ EFI_STATUS Status;\r
\r
- Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));\r
+ Status = EFI_SUCCESS;\r
\r
+ Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));\r
if (Packet == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
sizeof (EFI_MTFTP4_ACK_HEADER),\r
FALSE\r
);\r
+ ASSERT (Ack != NULL);\r
\r
Ack->Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);\r
Ack->Ack.Block[0] = HTONS (BlkNo);\r
\r
- return Mtftp4SendPacket (Instance, Packet);\r
+ Status = Mtftp4SendPacket (Instance, Packet);\r
+ if (!EFI_ERROR (Status)) {\r
+ Instance->AckedBlock = Instance->TotalBlock;\r
+ }\r
+\r
+ return Status;\r
}\r
\r
\r
UINT16 Block;\r
UINT64 Start;\r
UINT32 DataLen;\r
+ BOOLEAN Completed;\r
\r
- Token = Instance->Token;\r
- Block = NTOHS (Packet->Data.Block);\r
- DataLen = Len - MTFTP4_DATA_HEAD_LEN;\r
+ Completed = FALSE;\r
+ Token = Instance->Token;\r
+ Block = NTOHS (Packet->Data.Block);\r
+ DataLen = Len - MTFTP4_DATA_HEAD_LEN;\r
\r
//\r
// This is the last block, save the block no\r
//\r
if (DataLen < Instance->BlkSize) {\r
+ Completed = TRUE;\r
Instance->LastBlock = Block;\r
Mtftp4SetLastBlockNum (&Instance->Blocks, Block);\r
}\r
//\r
// Remove this block number from the file hole. If Mtftp4RemoveBlockNum\r
// returns EFI_NOT_FOUND, the block has been saved, don't save it again.\r
+ // Note that : For bigger files, allowing the block counter to roll over\r
+ // to accept transfers of unlimited size. So TotalBlock is memorised as\r
+ // continuous block counter.\r
//\r
- Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block);\r
+ Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block, Completed, &Instance->TotalBlock);\r
\r
if (Status == EFI_NOT_FOUND) {\r
return EFI_SUCCESS;\r
}\r
\r
if (Token->Buffer != NULL) {\r
- Start = MultU64x32 (Block - 1, Instance->BlkSize);\r
+ Start = MultU64x32 (Instance->TotalBlock - 1, Instance->BlkSize);\r
\r
if (Start + DataLen <= Token->BufferSize) {\r
CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);\r
//\r
// Update the file size when received the last block\r
//\r
- if (Instance->LastBlock == Block) {\r
+ if ((Instance->LastBlock == Block) && Completed) {\r
Token->BufferSize = Start + DataLen;\r
}\r
\r
\r
\r
/**\r
- Function to process the received data packets. \r
- \r
+ Function to process the received data packets.\r
+\r
It will save the block then send back an ACK if it is active.\r
\r
@param Instance The downloading MTFTP session\r
INTN Expected;\r
\r
*Completed = FALSE;\r
+ Status = EFI_SUCCESS;\r
BlockNum = NTOHS (Packet->Data.Block);\r
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
\r
ASSERT (Expected >= 0);\r
\r
//\r
- // If we are active and received an unexpected packet, retransmit\r
- // the last ACK then restart receiving. If we are passive, save\r
- // the block.\r
+ // If we are active and received an unexpected packet, transmit\r
+ // the ACK for the block we received, then restart receiving the\r
+ // expected one. If we are passive, save the block.\r
//\r
if (Instance->Master && (Expected != BlockNum)) {\r
- Mtftp4Retransmit (Instance);\r
- return EFI_SUCCESS;\r
+ //\r
+ // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).\r
+ //\r
+ return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1));\r
}\r
\r
Status = Mtftp4RrqSaveBlock (Instance, Packet, Len);\r
BlockNum = (UINT16) (Expected - 1);\r
}\r
\r
- Mtftp4RrqSendAck (Instance, BlockNum);\r
+ if (Instance->WindowSize == (Instance->TotalBlock - Instance->AckedBlock) || Expected < 0) {\r
+ Status = Mtftp4RrqSendAck (Instance, BlockNum);\r
+ }\r
+\r
}\r
\r
- return EFI_SUCCESS;\r
+ return Status;\r
}\r
\r
\r
/**\r
Validate whether the options received in the server's OACK packet is valid.\r
- \r
+\r
The options are valid only if:\r
1. The server doesn't include options not requested by us\r
2. The server can only use smaller blksize than that is requested\r
}\r
\r
//\r
- // Server can only specify a smaller block size to be used and\r
+ // Server can only specify a smaller block size and window size to be used and\r
// return the timeout matches that requested.\r
//\r
if ((((Reply->Exist & MTFTP4_BLKSIZE_EXIST) != 0)&& (Reply->BlkSize > Request->BlkSize)) ||\r
- (((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->Timeout))) {\r
+ (((Reply->Exist & MTFTP4_WINDOWSIZE_EXIST) != 0)&& (Reply->WindowSize > Request->WindowSize)) ||\r
+ (((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->Timeout))\r
+ ) {\r
return FALSE;\r
}\r
\r
/**\r
Configure a UDP IO port to receive the multicast.\r
\r
- @param McastIo The UDP IO port to configure\r
+ @param McastIo The UDP IO to configure\r
@param Context The opaque parameter to the function which is the\r
MTFTP session.\r
\r
\r
**/\r
EFI_STATUS\r
+EFIAPI\r
Mtftp4RrqConfigMcastPort (\r
- IN UDP_IO_PORT *McastIo,\r
+ IN UDP_IO *McastIo,\r
IN VOID *Context\r
)\r
{\r
UdpConfig.ReceiveTimeout = 0;\r
UdpConfig.TransmitTimeout = 0;\r
UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;\r
- UdpConfig.StationAddress = Config->StationIp;\r
- UdpConfig.SubnetMask = Config->SubnetMask;\r
+ IP4_COPY_ADDRESS (&UdpConfig.StationAddress, &Config->StationIp);\r
+ IP4_COPY_ADDRESS (&UdpConfig.SubnetMask, &Config->SubnetMask);\r
UdpConfig.StationPort = Instance->McastPort;\r
UdpConfig.RemotePort = 0;\r
\r
Ip = HTONL (Instance->ServerIp);\r
- CopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+ IP4_COPY_ADDRESS (&UdpConfig.RemoteAddress, &Ip);\r
\r
- Status = McastIo->Udp->Configure (McastIo->Udp, &UdpConfig);\r
+ Status = McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, &UdpConfig);\r
\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
- if (!Config->UseDefaultSetting && \r
+ if (!Config->UseDefaultSetting &&\r
!EFI_IP4_EQUAL (&mZeroIp4Addr, &Config->GatewayIp)) {\r
//\r
// The station IP address is manually configured and the Gateway IP is not 0.\r
// Add the default route for this UDP instance.\r
//\r
- Status = McastIo->Udp->Routes (\r
- McastIo->Udp, \r
- FALSE,\r
- &mZeroIp4Addr,\r
- &mZeroIp4Addr,\r
- &Config->GatewayIp\r
- );\r
- \r
+ Status = McastIo->Protocol.Udp4->Routes (\r
+ McastIo->Protocol.Udp4,\r
+ FALSE,\r
+ &mZeroIp4Addr,\r
+ &mZeroIp4Addr,\r
+ &Config->GatewayIp\r
+ );\r
+\r
if (EFI_ERROR (Status)) {\r
- McastIo->Udp->Configure (McastIo->Udp, NULL);\r
+ McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, NULL);\r
return Status;\r
}\r
}\r
// join the multicast group\r
//\r
Ip = HTONL (Instance->McastIp);\r
- CopyMem (&Group, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+ IP4_COPY_ADDRESS (&Group, &Ip);\r
\r
- return McastIo->Udp->Groups (McastIo->Udp, TRUE, &Group);\r
+ return McastIo->Protocol.Udp4->Groups (McastIo->Protocol.Udp4, TRUE, &Group);\r
}\r
\r
\r
/**\r
- Function to process the OACK. \r
- \r
+ Function to process the OACK.\r
+\r
It will first validate the OACK packet, then update the various negotiated parameters.\r
\r
@param Instance The download MTFTP session\r
MTFTP4_OPTION Reply;\r
EFI_STATUS Status;\r
INTN Expected;\r
+ EFI_UDP4_PROTOCOL *Udp4;\r
\r
*Completed = FALSE;\r
\r
//\r
ZeroMem (&Reply, sizeof (MTFTP4_OPTION));\r
\r
- Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);\r
+ Status = Mtftp4ParseOptionOack (Packet, Len, Instance->Operation, &Reply);\r
\r
if (EFI_ERROR (Status) ||\r
!Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) {\r
\r
//\r
// Save the multicast info. Always update the Master, only update the\r
- // multicast IP address, block size, timeoute at the first time. If IP\r
+ // multicast IP address, block size, window size, timeoute at the first time. If IP\r
// address is updated, create a UDP child to receive the multicast.\r
//\r
Instance->Master = Reply.Master;\r
//\r
Instance->McastIp = Reply.McastIp;\r
Instance->McastPort = Reply.McastPort;\r
- Instance->McastUdpPort = UdpIoCreatePort (\r
- Instance->Service->Controller,\r
- Instance->Service->Image,\r
- Mtftp4RrqConfigMcastPort,\r
- Instance\r
- );\r
+ if (Instance->McastUdpPort == NULL) {\r
+ Instance->McastUdpPort = UdpIoCreateIo (\r
+ Instance->Service->Controller,\r
+ Instance->Service->Image,\r
+ Mtftp4RrqConfigMcastPort,\r
+ UDP_IO_UDP4_VERSION,\r
+ Instance\r
+ );\r
+ if (Instance->McastUdpPort != NULL) {\r
+ Status = gBS->OpenProtocol (\r
+ Instance->McastUdpPort->UdpHandle,\r
+ &gEfiUdp4ProtocolGuid,\r
+ (VOID **) &Udp4,\r
+ Instance->Service->Image,\r
+ Instance->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ UdpIoFreeIo (Instance->McastUdpPort);\r
+ Instance->McastUdpPort = NULL;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ }\r
+\r
\r
if (Instance->McastUdpPort == NULL) {\r
return EFI_DEVICE_ERROR;\r
\r
return Status;\r
}\r
- \r
+\r
//\r
// Update the parameters used.\r
//\r
if (Reply.BlkSize != 0) {\r
Instance->BlkSize = Reply.BlkSize;\r
}\r
- \r
+\r
+ if (Reply.WindowSize != 0) {\r
+ Instance->WindowSize = Reply.WindowSize;\r
+ }\r
+\r
if (Reply.Timeout != 0) {\r
Instance->Timeout = Reply.Timeout;\r
- } \r
- } \r
- \r
+ }\r
+ }\r
+\r
} else {\r
Instance->Master = TRUE;\r
- \r
+\r
if (Reply.BlkSize != 0) {\r
Instance->BlkSize = Reply.BlkSize;\r
}\r
\r
+ if (Reply.WindowSize != 0) {\r
+ Instance->WindowSize = Reply.WindowSize;\r
+ }\r
+\r
if (Reply.Timeout != 0) {\r
Instance->Timeout = Reply.Timeout;\r
}\r
}\r
- \r
+\r
//\r
// Send an ACK to (Expected - 1) which is 0 for unicast download,\r
// or tell the server we want to receive the Expected block.\r
The packet process callback for MTFTP download.\r
\r
@param UdpPacket The packet received\r
- @param Points The local/remote access point of the packet\r
+ @param EndPoint The local/remote access point of the packet\r
@param IoStatus The status of the receiving\r
@param Context Opaque parameter, which is the MTFTP session\r
\r
**/\r
VOID\r
+EFIAPI\r
Mtftp4RrqInput (\r
IN NET_BUF *UdpPacket,\r
- IN UDP_POINTS *Points,\r
+ IN UDP_END_POINT *EndPoint,\r
IN EFI_STATUS IoStatus,\r
IN VOID *Context\r
)\r
//\r
// Find the port this packet is from to restart receive correctly.\r
//\r
- Multicast = (BOOLEAN) (Points->LocalAddr == Instance->McastIp);\r
+ Multicast = (BOOLEAN) (EndPoint->LocalAddr.Addr[0] == Instance->McastIp);\r
\r
if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {\r
goto ON_EXIT;\r
// is required to use the same port as RemotePort to multicast the\r
// data.\r
//\r
- if (Points->RemotePort != Instance->ConnectedPort) {\r
+ if (EndPoint->RemotePort != Instance->ConnectedPort) {\r
if (Instance->ConnectedPort != 0) {\r
goto ON_EXIT;\r
} else {\r
- Instance->ConnectedPort = Points->RemotePort;\r
+ Instance->ConnectedPort = EndPoint->RemotePort;\r
}\r
}\r
\r
\r
} else {\r
Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);\r
+ ASSERT (Packet != NULL);\r
}\r
\r
Opcode = NTOHS (Packet->OpCode);\r
case EFI_MTFTP4_OPCODE_ERROR:\r
Status = EFI_TFTP_ERROR;\r
break;\r
- \r
+\r
default:\r
break;\r
}\r
// receive, otherwise end the session.\r
//\r
if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {\r
- gBS->FreePool (Packet);\r
+ FreePool (Packet);\r
}\r
\r
if (UdpPacket != NULL) {\r