+++ /dev/null
-/** @file\r
- Routines to process Rrq (download).\r
-\r
-(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-\r
-#include "Mtftp4Impl.h"\r
-\r
-\r
-/**\r
- The packet process callback for MTFTP download.\r
-\r
- @param UdpPacket The packet received\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_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
- reqeuest packet, at last, it will start receive for the downloading.\r
-\r
- @param Instance The Mtftp session\r
- @param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ\r
- or EFI_MTFTP4_OPCODE_DIR.\r
-\r
- @retval EFI_SUCCESS The mtftp download session is started.\r
- @retval Others Failed to start downloading.\r
-\r
-**/\r
-EFI_STATUS\r
-Mtftp4RrqStart (\r
- IN MTFTP4_PROTOCOL *Instance,\r
- IN UINT16 Operation\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- //\r
- // The valid block number range are [1, 0xffff]. For example:\r
- // the client sends an RRQ request to the server, the server\r
- // transfers the DATA1 block. If option negoitation is ongoing,\r
- // the server will send back an OACK, then client will send ACK0.\r
- //\r
- Status = Mtftp4InitBlockRange (&Instance->Blocks, 1, 0xffff);\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Status = Mtftp4SendRequest (Instance);\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);\r
-}\r
-\r
-\r
-/**\r
- Build and send a ACK packet for the download session.\r
-\r
- @param Instance The Mtftp session\r
- @param BlkNo The BlkNo to ack.\r
-\r
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet\r
- @retval EFI_SUCCESS The ACK has been sent\r
- @retval Others Failed to send the ACK.\r
-\r
-**/\r
-EFI_STATUS\r
-Mtftp4RrqSendAck (\r
- IN MTFTP4_PROTOCOL *Instance,\r
- IN UINT16 BlkNo\r
- )\r
-{\r
- EFI_MTFTP4_PACKET *Ack;\r
- NET_BUF *Packet;\r
- EFI_STATUS Status;\r
-\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
-\r
- Ack = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (\r
- Packet,\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
- Status = Mtftp4SendPacket (Instance, Packet);\r
- if (!EFI_ERROR (Status)) {\r
- Instance->AckedBlock = Instance->TotalBlock;\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Deliver the received data block to the user, which can be saved\r
- in the user provide buffer or through the CheckPacket callback.\r
-\r
- @param Instance The Mtftp session\r
- @param Packet The received data packet\r
- @param Len The packet length\r
-\r
- @retval EFI_SUCCESS The data is saved successfully\r
- @retval EFI_ABORTED The user tells to abort by return an error through\r
- CheckPacket\r
- @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small and buffer length is\r
- updated to the actual buffer size needed.\r
-\r
-**/\r
-EFI_STATUS\r
-Mtftp4RrqSaveBlock (\r
- IN OUT MTFTP4_PROTOCOL *Instance,\r
- IN EFI_MTFTP4_PACKET *Packet,\r
- IN UINT32 Len\r
- )\r
-{\r
- EFI_MTFTP4_TOKEN *Token;\r
- EFI_STATUS Status;\r
- UINT16 Block;\r
- UINT64 Start;\r
- UINT32 DataLen;\r
- UINT64 BlockCounter;\r
- BOOLEAN Completed;\r
-\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
- //\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 BlockCounter is memorised as\r
- // continuous block counter.\r
- //\r
- Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block, Completed, &BlockCounter);\r
-\r
- if (Status == EFI_NOT_FOUND) {\r
- return EFI_SUCCESS;\r
- } else if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- if (Token->CheckPacket != NULL) {\r
- Status = Token->CheckPacket (&Instance->Mtftp4, Token, (UINT16) Len, Packet);\r
-\r
- if (EFI_ERROR (Status)) {\r
- Mtftp4SendError (\r
- Instance,\r
- EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
- (UINT8 *) "User aborted download"\r
- );\r
-\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- if (Token->Buffer != NULL) {\r
- Start = MultU64x32 (BlockCounter - 1, Instance->BlkSize);\r
-\r
- if (Start + DataLen <= Token->BufferSize) {\r
- CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);\r
-\r
- //\r
- // Update the file size when received the last block\r
- //\r
- if ((Instance->LastBlock == Block) && Completed) {\r
- Token->BufferSize = Start + DataLen;\r
- }\r
-\r
- } else if (Instance->LastBlock != 0) {\r
- //\r
- // Don't save the data if the buffer is too small, return\r
- // EFI_BUFFER_TOO_SMALL if received the last packet. This\r
- // will give a accurate file length.\r
- //\r
- Token->BufferSize = Start + DataLen;\r
-\r
- Mtftp4SendError (\r
- Instance,\r
- EFI_MTFTP4_ERRORCODE_DISK_FULL,\r
- (UINT8 *) "User provided memory block is too small"\r
- );\r
-\r
- return EFI_BUFFER_TOO_SMALL;\r
- }\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\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
- @param Packet The packet received\r
- @param Len The length of the packet\r
- @param Multicast Whether this packet is multicast or unicast\r
- @param Completed Return whether the download has completed\r
-\r
- @retval EFI_SUCCESS The data packet is successfully processed\r
- @retval EFI_ABORTED The download is aborted by the user\r
- @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small\r
-\r
-**/\r
-EFI_STATUS\r
-Mtftp4RrqHandleData (\r
- IN MTFTP4_PROTOCOL *Instance,\r
- IN EFI_MTFTP4_PACKET *Packet,\r
- IN UINT32 Len,\r
- IN BOOLEAN Multicast,\r
- OUT BOOLEAN *Completed\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT16 BlockNum;\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 (Master) 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 (Slave), save the block.\r
- //\r
- if (Instance->Master && (Expected != BlockNum)) {\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
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Record the total received and saved block number.\r
- //\r
- Instance->TotalBlock ++;\r
-\r
- //\r
- // Reset the passive client's timer whenever it received a\r
- // valid data packet.\r
- //\r
- if (!Instance->Master) {\r
- Mtftp4SetTimeout (Instance);\r
- }\r
-\r
- //\r
- // Check whether we have received all the blocks. Send the ACK if we\r
- // are active (unicast client or master client for multicast download).\r
- // If we have received all the blocks, send an ACK even if we are passive\r
- // to tell the server that we are done.\r
- //\r
- Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
-\r
- if (Instance->Master || (Expected < 0)) {\r
- if (Expected < 0) {\r
- //\r
- // If we are passive client, then the just received Block maybe\r
- // isn't the last block. We need to send an ACK to the last block\r
- // to inform the server that we are done. If we are active client,\r
- // the Block == Instance->LastBlock.\r
- //\r
- BlockNum = Instance->LastBlock;\r
- *Completed = TRUE;\r
-\r
- } else {\r
- BlockNum = (UINT16) (Expected - 1);\r
- }\r
-\r
- if (Instance->WindowSize == (Instance->TotalBlock - Instance->AckedBlock) || Expected < 0) {\r
- Status = Mtftp4RrqSendAck (Instance, BlockNum);\r
- }\r
-\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Validate whether the options received in the server's OACK packet is valid.\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
- 3. The server can only use the same timeout as requested\r
- 4. The server doesn't change its multicast channel.\r
-\r
- @param This The downloading Mtftp session\r
- @param Reply The options in the OACK packet\r
- @param Request The requested options\r
-\r
- @retval TRUE The options in the OACK is OK.\r
- @retval FALSE The options in the OACK is invalid.\r
-\r
-**/\r
-BOOLEAN\r
-Mtftp4RrqOackValid (\r
- IN MTFTP4_PROTOCOL *This,\r
- IN MTFTP4_OPTION *Reply,\r
- IN MTFTP4_OPTION *Request\r
- )\r
-{\r
-\r
- //\r
- // It is invalid for server to return options we don't request\r
- //\r
- if ((Reply->Exist &~Request->Exist) != 0) {\r
- return FALSE;\r
- }\r
-\r
- //\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_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
- // The server can send ",,master" to client to change its master\r
- // setting. But if it use the specific multicast channel, it can't\r
- // change the setting.\r
- //\r
- if (((Reply->Exist & MTFTP4_MCAST_EXIST) != 0) && (This->McastIp != 0)) {\r
- if ((Reply->McastIp != 0) && (Reply->McastIp != This->McastIp)) {\r
- return FALSE;\r
- }\r
-\r
- if ((Reply->McastPort != 0) && (Reply->McastPort != This->McastPort)) {\r
- return FALSE;\r
- }\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-\r
-/**\r
- Configure a UDP IO port to receive the multicast.\r
-\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
- @retval EFI_SUCCESS The UDP child is successfully configured.\r
- @retval Others Failed to configure the UDP child.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-Mtftp4RrqConfigMcastPort (\r
- IN UDP_IO *McastIo,\r
- IN VOID *Context\r
- )\r
-{\r
- MTFTP4_PROTOCOL *Instance;\r
- EFI_MTFTP4_CONFIG_DATA *Config;\r
- EFI_UDP4_CONFIG_DATA UdpConfig;\r
- EFI_IPv4_ADDRESS Group;\r
- EFI_STATUS Status;\r
- IP4_ADDR Ip;\r
-\r
- Instance = (MTFTP4_PROTOCOL *) Context;\r
- Config = &Instance->Config;\r
-\r
- UdpConfig.AcceptBroadcast = FALSE;\r
- UdpConfig.AcceptPromiscuous = FALSE;\r
- UdpConfig.AcceptAnyPort = FALSE;\r
- UdpConfig.AllowDuplicatePort = FALSE;\r
- UdpConfig.TypeOfService = 0;\r
- UdpConfig.TimeToLive = 64;\r
- UdpConfig.DoNotFragment = FALSE;\r
- UdpConfig.ReceiveTimeout = 0;\r
- UdpConfig.TransmitTimeout = 0;\r
- UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;\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
- IP4_COPY_ADDRESS (&UdpConfig.RemoteAddress, &Ip);\r
-\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
- !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->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->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, NULL);\r
- return Status;\r
- }\r
- }\r
-\r
- //\r
- // join the multicast group\r
- //\r
- Ip = HTONL (Instance->McastIp);\r
- IP4_COPY_ADDRESS (&Group, &Ip);\r
-\r
- return McastIo->Protocol.Udp4->Groups (McastIo->Protocol.Udp4, TRUE, &Group);\r
-}\r
-\r
-\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
- @param Packet The packet received\r
- @param Len The packet length\r
- @param Multicast Whether this packet is received as a multicast\r
- @param Completed Returns whether the download has completed. NOT\r
- used by this function.\r
-\r
- @retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child\r
- @retval EFI_TFTP_ERROR Some error happened during the process\r
- @retval EFI_SUCCESS The OACK is successfully processed.\r
-\r
-**/\r
-EFI_STATUS\r
-Mtftp4RrqHandleOack (\r
- IN OUT MTFTP4_PROTOCOL *Instance,\r
- IN EFI_MTFTP4_PACKET *Packet,\r
- IN UINT32 Len,\r
- IN BOOLEAN Multicast,\r
- OUT BOOLEAN *Completed\r
- )\r
-{\r
- MTFTP4_OPTION Reply;\r
- EFI_STATUS Status;\r
- INTN Expected;\r
- EFI_UDP4_PROTOCOL *Udp4;\r
-\r
- *Completed = FALSE;\r
-\r
- //\r
- // If already started the master download, don't change the\r
- // setting. Master download always succeeds.\r
- //\r
- Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
- ASSERT (Expected != -1);\r
-\r
- if (Instance->Master && (Expected != 1)) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // Parse and validate the options from server\r
- //\r
- ZeroMem (&Reply, sizeof (MTFTP4_OPTION));\r
-\r
- Status = Mtftp4ParseOptionOack (Packet, Len, Instance->Operation, &Reply);\r
-\r
- if (EFI_ERROR (Status) ||\r
- !Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) {\r
- //\r
- // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.\r
- //\r
- if (Status != EFI_OUT_OF_RESOURCES) {\r
- Mtftp4SendError (\r
- Instance,\r
- EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
- (UINT8 *) "Mal-formated OACK packet"\r
- );\r
- }\r
-\r
- return EFI_TFTP_ERROR;\r
- }\r
-\r
- if ((Reply.Exist & MTFTP4_MCAST_EXIST) != 0) {\r
-\r
- //\r
- // Save the multicast info. Always update the Master, only update the\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
- if (Instance->McastIp == 0) {\r
- if ((Reply.McastIp == 0) || (Reply.McastPort == 0)) {\r
- Mtftp4SendError (\r
- Instance,\r
- EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
- (UINT8 *) "Illegal multicast setting"\r
- );\r
-\r
- return EFI_TFTP_ERROR;\r
- }\r
-\r
- //\r
- // Create a UDP child then start receive the multicast from it.\r
- //\r
- Instance->McastIp = Reply.McastIp;\r
- Instance->McastPort = Reply.McastPort;\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
-\r
- Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);\r
-\r
- if (EFI_ERROR (Status)) {\r
- Mtftp4SendError (\r
- Instance,\r
- EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION,\r
- (UINT8 *) "Failed to create socket to receive multicast packet"\r
- );\r
-\r
- return Status;\r
- }\r
-\r
- //\r
- // Update the parameters used.\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
- } else {\r
- Instance->Master = TRUE;\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
- // 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
- //\r
- return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1));\r
-}\r
-\r
-\r
-/**\r
- The packet process callback for MTFTP download.\r
-\r
- @param UdpPacket The packet received\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_END_POINT *EndPoint,\r
- IN EFI_STATUS IoStatus,\r
- IN VOID *Context\r
- )\r
-{\r
- MTFTP4_PROTOCOL *Instance;\r
- EFI_MTFTP4_PACKET *Packet;\r
- BOOLEAN Completed;\r
- BOOLEAN Multicast;\r
- EFI_STATUS Status;\r
- UINT16 Opcode;\r
- UINT32 Len;\r
-\r
- Instance = (MTFTP4_PROTOCOL *) Context;\r
- NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);\r
-\r
- Status = EFI_SUCCESS;\r
- Packet = NULL;\r
- Completed = FALSE;\r
- Multicast = FALSE;\r
-\r
- if (EFI_ERROR (IoStatus)) {\r
- Status = IoStatus;\r
- goto ON_EXIT;\r
- }\r
-\r
- ASSERT (UdpPacket != NULL);\r
-\r
- //\r
- // Find the port this packet is from to restart receive correctly.\r
- //\r
- Multicast = (BOOLEAN) (EndPoint->LocalAddr.Addr[0] == Instance->McastIp);\r
-\r
- if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {\r
- goto ON_EXIT;\r
- }\r
-\r
- //\r
- // Client send initial request to server's listening port. Server\r
- // will select a UDP port to communicate with the client. The server\r
- // is required to use the same port as RemotePort to multicast the\r
- // data.\r
- //\r
- if (EndPoint->RemotePort != Instance->ConnectedPort) {\r
- if (Instance->ConnectedPort != 0) {\r
- goto ON_EXIT;\r
- } else {\r
- Instance->ConnectedPort = EndPoint->RemotePort;\r
- }\r
- }\r
-\r
- //\r
- // Copy the MTFTP packet to a continuous buffer if it isn't already so.\r
- //\r
- Len = UdpPacket->TotalSize;\r
-\r
- if (UdpPacket->BlockOpNum > 1) {\r
- Packet = AllocatePool (Len);\r
-\r
- if (Packet == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);\r
-\r
- } else {\r
- Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);\r
- ASSERT (Packet != NULL);\r
- }\r
-\r
- Opcode = NTOHS (Packet->OpCode);\r
-\r
- //\r
- // Call the user's CheckPacket if provided. Abort the transmission\r
- // if CheckPacket returns an EFI_ERROR code.\r
- //\r
- if ((Instance->Token->CheckPacket != NULL) &&\r
- ((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {\r
-\r
- Status = Instance->Token->CheckPacket (\r
- &Instance->Mtftp4,\r
- Instance->Token,\r
- (UINT16) Len,\r
- Packet\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // Send an error message to the server to inform it\r
- //\r
- if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {\r
- Mtftp4SendError (\r
- Instance,\r
- EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
- (UINT8 *) "User aborted the transfer"\r
- );\r
- }\r
-\r
- Status = EFI_ABORTED;\r
- goto ON_EXIT;\r
- }\r
- }\r
-\r
- switch (Opcode) {\r
- case EFI_MTFTP4_OPCODE_DATA:\r
- if ((Len > (UINT32) (MTFTP4_DATA_HEAD_LEN + Instance->BlkSize)) ||\r
- (Len < (UINT32) MTFTP4_DATA_HEAD_LEN)) {\r
- goto ON_EXIT;\r
- }\r
-\r
- Status = Mtftp4RrqHandleData (Instance, Packet, Len, Multicast, &Completed);\r
- break;\r
-\r
- case EFI_MTFTP4_OPCODE_OACK:\r
- if (Multicast || (Len <= MTFTP4_OPCODE_LEN)) {\r
- goto ON_EXIT;\r
- }\r
-\r
- Status = Mtftp4RrqHandleOack (Instance, Packet, Len, Multicast, &Completed);\r
- break;\r
-\r
- case EFI_MTFTP4_OPCODE_ERROR:\r
- Status = EFI_TFTP_ERROR;\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
-\r
-ON_EXIT:\r
-\r
- //\r
- // Free the resources, then if !EFI_ERROR (Status), restart the\r
- // receive, otherwise end the session.\r
- //\r
- if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {\r
- FreePool (Packet);\r
- }\r
-\r
- if (UdpPacket != NULL) {\r
- NetbufFree (UdpPacket);\r
- }\r
-\r
- if (!EFI_ERROR (Status) && !Completed) {\r
- if (Multicast) {\r
- Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);\r
- } else {\r
- Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);\r
- }\r
- }\r
-\r
- if (EFI_ERROR (Status) || Completed) {\r
- Mtftp4CleanOperation (Instance, Status);\r
- }\r
-}\r