123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936 |
- /** @file
- Mtftp6 Rrq process functions implementation.
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "Mtftp6Impl.h"
- /**
- Build and send a ACK packet for download.
- @param[in] Instance The pointer to the Mtftp6 instance.
- @param[in] BlockNum The block number to be acked.
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.
- @retval EFI_SUCCESS The ACK has been sent.
- @retval Others Failed to send the ACK.
- **/
- EFI_STATUS
- Mtftp6RrqSendAck (
- IN MTFTP6_INSTANCE *Instance,
- IN UINT16 BlockNum
- )
- {
- EFI_MTFTP6_PACKET *Ack;
- NET_BUF *Packet;
- EFI_STATUS Status;
- Status = EFI_SUCCESS;
- //
- // Allocate net buffer to create ack packet.
- //
- Packet = NetbufAlloc (sizeof (EFI_MTFTP6_ACK_HEADER));
- if (Packet == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- Ack = (EFI_MTFTP6_PACKET *)NetbufAllocSpace (
- Packet,
- sizeof (EFI_MTFTP6_ACK_HEADER),
- FALSE
- );
- ASSERT (Ack != NULL);
- Ack->Ack.OpCode = HTONS (EFI_MTFTP6_OPCODE_ACK);
- Ack->Ack.Block[0] = HTONS (BlockNum);
- //
- // Reset current retry count of the instance.
- //
- Instance->CurRetry = 0;
- Instance->LastPacket = Packet;
- Status = Mtftp6TransmitPacket (Instance, Packet);
- if (!EFI_ERROR (Status)) {
- Instance->AckedBlock = Instance->TotalBlock;
- }
- return Status;
- }
- /**
- Deliver the received data block to the user, which can be saved
- in the user provide buffer or through the CheckPacket callback.
- @param[in] Instance The pointer to the Mtftp6 instance.
- @param[in] Packet The pointer to the received packet.
- @param[in] Len The packet length.
- @param[out] UdpPacket The net buf of the received packet.
- @retval EFI_SUCCESS The data was saved successfully.
- @retval EFI_ABORTED The user tells to abort by return an error through
- CheckPacket.
- @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small, and buffer length is
- updated to the actual buffer size needed.
- **/
- EFI_STATUS
- Mtftp6RrqSaveBlock (
- IN MTFTP6_INSTANCE *Instance,
- IN EFI_MTFTP6_PACKET *Packet,
- IN UINT32 Len,
- OUT NET_BUF **UdpPacket
- )
- {
- EFI_MTFTP6_TOKEN *Token;
- EFI_STATUS Status;
- UINT16 Block;
- UINT64 Start;
- UINT32 DataLen;
- UINT64 BlockCounter;
- BOOLEAN Completed;
- Completed = FALSE;
- Token = Instance->Token;
- Block = NTOHS (Packet->Data.Block);
- DataLen = Len - MTFTP6_DATA_HEAD_LEN;
- //
- // This is the last block, save the block num
- //
- if (DataLen < Instance->BlkSize) {
- Completed = TRUE;
- Instance->LastBlk = Block;
- Mtftp6SetLastBlockNum (&Instance->BlkList, Block);
- }
- //
- // Remove this block number from the file hole. If Mtftp6RemoveBlockNum
- // returns EFI_NOT_FOUND, the block has been saved, don't save it again.
- // Note that : For bigger files, allowing the block counter to roll over
- // to accept transfers of unlimited size. So BlockCounter is memorised as
- // continuous block counter.
- //
- Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, &BlockCounter);
- if (Status == EFI_NOT_FOUND) {
- return EFI_SUCCESS;
- } else if (EFI_ERROR (Status)) {
- return Status;
- }
- if (Token->CheckPacket != NULL) {
- //
- // Callback to the check packet routine with the received packet.
- //
- Status = Token->CheckPacket (&Instance->Mtftp6, Token, (UINT16)Len, Packet);
- if (EFI_ERROR (Status)) {
- //
- // Free the received packet before send new packet in ReceiveNotify,
- // since the Udp6Io might need to be reconfigured.
- //
- NetbufFree (*UdpPacket);
- *UdpPacket = NULL;
- //
- // Send the Mtftp6 error message if user aborted the current session.
- //
- Mtftp6SendError (
- Instance,
- EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
- (UINT8 *)"User aborted download"
- );
- return EFI_ABORTED;
- }
- }
- if (Token->Buffer != NULL) {
- Start = MultU64x32 (BlockCounter - 1, Instance->BlkSize);
- if (Start + DataLen <= Token->BufferSize) {
- CopyMem ((UINT8 *)Token->Buffer + Start, Packet->Data.Data, DataLen);
- //
- // Update the file size when received the last block
- //
- if ((Instance->LastBlk == Block) && Completed) {
- Token->BufferSize = Start + DataLen;
- }
- } else if (Instance->LastBlk != 0) {
- //
- // Don't save the data if the buffer is too small, return
- // EFI_BUFFER_TOO_SMALL if received the last packet. This
- // will give a accurate file length.
- //
- Token->BufferSize = Start + DataLen;
- //
- // Free the received packet before send new packet in ReceiveNotify,
- // since the udpio might need to be reconfigured.
- //
- NetbufFree (*UdpPacket);
- *UdpPacket = NULL;
- //
- // Send the Mtftp6 error message if no enough buffer.
- //
- Mtftp6SendError (
- Instance,
- EFI_MTFTP6_ERRORCODE_DISK_FULL,
- (UINT8 *)"User provided memory block is too small"
- );
- return EFI_BUFFER_TOO_SMALL;
- }
- }
- return EFI_SUCCESS;
- }
- /**
- Process the received data packets. It will save the block
- then send back an ACK if it is active.
- @param[in] Instance The pointer to the Mtftp6 instance.
- @param[in] Packet The pointer to the received packet.
- @param[in] Len The length of the packet.
- @param[out] UdpPacket The net buf of received packet.
- @param[out] IsCompleted If TRUE, the download has been completed.
- Otherwise, the download has not been completed.
- @retval EFI_SUCCESS The data packet was successfully processed.
- @retval EFI_ABORTED The download was aborted by the user.
- @retval EFI_BUFFER_TOO_SMALL The user-provided buffer is too small.
- **/
- EFI_STATUS
- Mtftp6RrqHandleData (
- IN MTFTP6_INSTANCE *Instance,
- IN EFI_MTFTP6_PACKET *Packet,
- IN UINT32 Len,
- OUT NET_BUF **UdpPacket,
- OUT BOOLEAN *IsCompleted
- )
- {
- EFI_STATUS Status;
- UINT16 BlockNum;
- INTN Expected;
- *IsCompleted = FALSE;
- Status = EFI_SUCCESS;
- BlockNum = NTOHS (Packet->Data.Block);
- Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
- ASSERT (Expected >= 0);
- //
- // If we are active (Master) and received an unexpected packet, transmit
- // the ACK for the block we received, then restart receiving the
- // expected one. If we are passive (Slave), save the block.
- //
- if (Instance->IsMaster && (Expected != BlockNum)) {
- //
- // Free the received packet before send new packet in ReceiveNotify,
- // since the udpio might need to be reconfigured.
- //
- NetbufFree (*UdpPacket);
- *UdpPacket = NULL;
- //
- // 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);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Record the total received and saved block number.
- //
- Instance->TotalBlock++;
- //
- // Reset the passive client's timer whenever it received a valid data packet.
- //
- if (!Instance->IsMaster) {
- Instance->PacketToLive = Instance->Timeout * 2;
- }
- //
- // Check whether we have received all the blocks. Send the ACK if we
- // are active (unicast client or master client for multicast download).
- // If we have received all the blocks, send an ACK even if we are passive
- // to tell the server that we are done.
- //
- Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
- if (Instance->IsMaster || (Expected < 0)) {
- if (Expected < 0) {
- //
- // If we are passive client, then the just received Block maybe
- // isn't the last block. We need to send an ACK to the last block
- // to inform the server that we are done. If we are active client,
- // the Block == Instance->LastBlock.
- //
- BlockNum = Instance->LastBlk;
- *IsCompleted = TRUE;
- } else {
- BlockNum = (UINT16)(Expected - 1);
- }
- //
- // Free the received packet before send new packet in ReceiveNotify,
- // since the udpio might need to be reconfigured.
- //
- NetbufFree (*UdpPacket);
- *UdpPacket = NULL;
- if ((Instance->WindowSize == (Instance->TotalBlock - Instance->AckedBlock)) || (Expected < 0)) {
- Status = Mtftp6RrqSendAck (Instance, BlockNum);
- }
- }
- return Status;
- }
- /**
- Validate whether the options received in the server's OACK packet is valid.
- The options are valid only if:
- 1. The server doesn't include options not requested by us.
- 2. The server can only use smaller blksize than that is requested.
- 3. The server can only use the same timeout as requested.
- 4. The server doesn't change its multicast channel.
- @param[in] Instance The pointer to the Mtftp6 instance.
- @param[in] ReplyInfo The pointer to options information in reply packet.
- @param[in] RequestInfo The pointer to requested options info.
- @retval TRUE If the option in the OACK is valid.
- @retval FALSE If the option is invalid.
- **/
- BOOLEAN
- Mtftp6RrqOackValid (
- IN MTFTP6_INSTANCE *Instance,
- IN MTFTP6_EXT_OPTION_INFO *ReplyInfo,
- IN MTFTP6_EXT_OPTION_INFO *RequestInfo
- )
- {
- //
- // It is invalid for server to return options we don't request
- //
- if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {
- return FALSE;
- }
- //
- // Server can only specify a smaller block size and windowsize to be used and
- // return the timeout matches that requested.
- //
- 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))
- )
- {
- return FALSE;
- }
- //
- // The server can send ",,master" to client to change its master
- // setting. But if it use the specific multicast channel, it can't
- // change the setting.
- //
- if (((ReplyInfo->BitMap & MTFTP6_OPT_MCAST_BIT) != 0) && !NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {
- if (!NetIp6IsUnspecifiedAddr (&ReplyInfo->McastIp) && (CompareMem (
- &ReplyInfo->McastIp,
- &Instance->McastIp,
- sizeof (EFI_IPv6_ADDRESS)
- ) != 0))
- {
- return FALSE;
- }
- if ((ReplyInfo->McastPort != 0) && (ReplyInfo->McastPort != Instance->McastPort)) {
- return FALSE;
- }
- }
- return TRUE;
- }
- /**
- Configure Udp6Io to receive a packet from a multicast address.
- @param[in] McastIo The pointer to the mcast Udp6Io.
- @param[in] Context The pointer to the context.
- @retval EFI_SUCCESS The mcast Udp6Io was successfully configured.
- @retval Others Failed to configure the Udp6Io.
- **/
- EFI_STATUS
- EFIAPI
- Mtftp6RrqConfigMcastUdpIo (
- IN UDP_IO *McastIo,
- IN VOID *Context
- )
- {
- EFI_STATUS Status;
- EFI_UDP6_PROTOCOL *Udp6;
- EFI_UDP6_CONFIG_DATA *Udp6Cfg;
- EFI_IPv6_ADDRESS Group;
- MTFTP6_INSTANCE *Instance;
- Udp6 = McastIo->Protocol.Udp6;
- Udp6Cfg = &(McastIo->Config.Udp6);
- Instance = (MTFTP6_INSTANCE *)Context;
- //
- // Set the configure data for the mcast Udp6Io.
- //
- ZeroMem (Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));
- Udp6Cfg->AcceptPromiscuous = FALSE;
- Udp6Cfg->AcceptAnyPort = FALSE;
- Udp6Cfg->AllowDuplicatePort = FALSE;
- Udp6Cfg->TrafficClass = 0;
- Udp6Cfg->HopLimit = 128;
- Udp6Cfg->ReceiveTimeout = 0;
- Udp6Cfg->TransmitTimeout = 0;
- Udp6Cfg->StationPort = Instance->McastPort;
- Udp6Cfg->RemotePort = 0;
- CopyMem (
- &Udp6Cfg->RemoteAddress,
- &Instance->ServerIp,
- sizeof (EFI_IPv6_ADDRESS)
- );
- //
- // Configure the mcast Udp6Io.
- //
- Status = Udp6->Configure (Udp6, Udp6Cfg);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Join the multicast group
- //
- CopyMem (&Group, &Instance->McastIp, sizeof (EFI_IPv6_ADDRESS));
- return Udp6->Groups (Udp6, TRUE, &Group);
- }
- /**
- Process the OACK packet for Rrq.
- @param[in] Instance The pointer to the Mtftp6 instance.
- @param[in] Packet The pointer to the received packet.
- @param[in] Len The length of the packet.
- @param[out] UdpPacket The net buf of received packet.
- @param[out] IsCompleted If TRUE, the download has been completed.
- Otherwise, the download has not been completed.
- @retval EFI_DEVICE_ERROR Failed to create/start a multicast Udp6 child.
- @retval EFI_TFTP_ERROR An error happened during the process.
- @retval EFI_SUCCESS The OACK packet successfully processed.
- **/
- EFI_STATUS
- Mtftp6RrqHandleOack (
- IN MTFTP6_INSTANCE *Instance,
- IN EFI_MTFTP6_PACKET *Packet,
- IN UINT32 Len,
- OUT NET_BUF **UdpPacket,
- OUT BOOLEAN *IsCompleted
- )
- {
- EFI_MTFTP6_OPTION *Options;
- UINT32 Count;
- MTFTP6_EXT_OPTION_INFO ExtInfo;
- EFI_STATUS Status;
- INTN Expected;
- EFI_UDP6_PROTOCOL *Udp6;
- *IsCompleted = FALSE;
- Options = NULL;
- //
- // If already started the master download, don't change the
- // setting. Master download always succeeds.
- //
- Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
- ASSERT (Expected != -1);
- if (Instance->IsMaster && (Expected != 1)) {
- return EFI_SUCCESS;
- }
- ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
- //
- // Parse the options in the packet.
- //
- Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- ASSERT (Options != NULL);
- //
- // Parse the extensive options in the packet.
- //
- Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, Instance->Operation, &ExtInfo);
- if (EFI_ERROR (Status) || !Mtftp6RrqOackValid (Instance, &ExtInfo, &Instance->ExtInfo)) {
- //
- // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
- //
- if (Status != EFI_OUT_OF_RESOURCES) {
- //
- // Free the received packet before send new packet in ReceiveNotify,
- // since the udpio might need to be reconfigured.
- //
- NetbufFree (*UdpPacket);
- *UdpPacket = NULL;
- //
- // Send the Mtftp6 error message if invalid packet.
- //
- Mtftp6SendError (
- Instance,
- EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
- (UINT8 *)"Malformatted OACK packet"
- );
- }
- return EFI_TFTP_ERROR;
- }
- if ((ExtInfo.BitMap & MTFTP6_OPT_MCAST_BIT) != 0) {
- //
- // Save the multicast info. Always update the Master, only update the
- // 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.
- //
- Instance->IsMaster = ExtInfo.IsMaster;
- if (NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {
- if (NetIp6IsUnspecifiedAddr (&ExtInfo.McastIp) || (ExtInfo.McastPort == 0)) {
- //
- // Free the received packet before send new packet in ReceiveNotify,
- // since the udpio might need to be reconfigured.
- //
- NetbufFree (*UdpPacket);
- *UdpPacket = NULL;
- //
- // Send the Mtftp6 error message if invalid multi-cast setting.
- //
- Mtftp6SendError (
- Instance,
- EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
- (UINT8 *)"Illegal multicast setting"
- );
- return EFI_TFTP_ERROR;
- }
- //
- // Create a UDP child then start receive the multicast from it.
- //
- CopyMem (
- &Instance->McastIp,
- &ExtInfo.McastIp,
- sizeof (EFI_IP_ADDRESS)
- );
- Instance->McastPort = ExtInfo.McastPort;
- if (Instance->McastUdpIo == NULL) {
- Instance->McastUdpIo = UdpIoCreateIo (
- Instance->Service->Controller,
- Instance->Service->Image,
- Mtftp6RrqConfigMcastUdpIo,
- UDP_IO_UDP6_VERSION,
- Instance
- );
- if (Instance->McastUdpIo != NULL) {
- Status = gBS->OpenProtocol (
- Instance->McastUdpIo->UdpHandle,
- &gEfiUdp6ProtocolGuid,
- (VOID **)&Udp6,
- Instance->Service->Image,
- Instance->Handle,
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
- );
- if (EFI_ERROR (Status)) {
- UdpIoFreeIo (Instance->McastUdpIo);
- Instance->McastUdpIo = NULL;
- return EFI_DEVICE_ERROR;
- }
- }
- }
- if (Instance->McastUdpIo == NULL) {
- return EFI_DEVICE_ERROR;
- }
- Status = UdpIoRecvDatagram (
- Instance->McastUdpIo,
- Mtftp6RrqInput,
- Instance,
- 0
- );
- if (EFI_ERROR (Status)) {
- //
- // Free the received packet before send new packet in ReceiveNotify,
- // since the udpio might need to be reconfigured.
- //
- NetbufFree (*UdpPacket);
- *UdpPacket = NULL;
- //
- // Send the Mtftp6 error message if failed to create Udp6Io to receive.
- //
- Mtftp6SendError (
- Instance,
- EFI_MTFTP6_ERRORCODE_ACCESS_VIOLATION,
- (UINT8 *)"Failed to create socket to receive multicast packet"
- );
- return Status;
- }
- //
- // Update the parameters used.
- //
- if (ExtInfo.BlkSize != 0) {
- Instance->BlkSize = ExtInfo.BlkSize;
- }
- if (ExtInfo.WindowSize != 0) {
- Instance->WindowSize = ExtInfo.WindowSize;
- }
- if (ExtInfo.Timeout != 0) {
- Instance->Timeout = ExtInfo.Timeout;
- }
- }
- } else {
- Instance->IsMaster = TRUE;
- if (ExtInfo.BlkSize != 0) {
- Instance->BlkSize = ExtInfo.BlkSize;
- }
- if (ExtInfo.WindowSize != 0) {
- Instance->WindowSize = ExtInfo.WindowSize;
- }
- if (ExtInfo.Timeout != 0) {
- Instance->Timeout = ExtInfo.Timeout;
- }
- }
- //
- // Free the received packet before send new packet in ReceiveNotify,
- // since the udpio might need to be reconfigured.
- //
- NetbufFree (*UdpPacket);
- *UdpPacket = NULL;
- //
- // Send an ACK to (Expected - 1) which is 0 for unicast download,
- // or tell the server we want to receive the Expected block.
- //
- return Mtftp6RrqSendAck (Instance, (UINT16)(Expected - 1));
- }
- /**
- The packet process callback for Mtftp6 download.
- @param[in] UdpPacket The pointer to the packet received.
- @param[in] UdpEpt The pointer to the Udp6 access point.
- @param[in] IoStatus The status from Udp6 instance.
- @param[in] Context The pointer to the context.
- **/
- VOID
- EFIAPI
- Mtftp6RrqInput (
- IN NET_BUF *UdpPacket,
- IN UDP_END_POINT *UdpEpt,
- IN EFI_STATUS IoStatus,
- IN VOID *Context
- )
- {
- MTFTP6_INSTANCE *Instance;
- EFI_MTFTP6_PACKET *Packet;
- BOOLEAN IsCompleted;
- BOOLEAN IsMcast;
- EFI_STATUS Status;
- UINT16 Opcode;
- UINT32 TotalNum;
- UINT32 Len;
- Instance = (MTFTP6_INSTANCE *)Context;
- NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);
- Status = EFI_SUCCESS;
- Packet = NULL;
- IsCompleted = FALSE;
- IsMcast = FALSE;
- TotalNum = 0;
- //
- // Return error status if Udp6 instance failed to receive.
- //
- if (EFI_ERROR (IoStatus)) {
- Status = IoStatus;
- goto ON_EXIT;
- }
- ASSERT (UdpPacket != NULL);
- if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {
- goto ON_EXIT;
- }
- //
- // Find the port this packet is from to restart receive correctly.
- //
- if (CompareMem (
- Ip6Swap128 (&UdpEpt->LocalAddr.v6),
- &Instance->McastIp,
- sizeof (EFI_IPv6_ADDRESS)
- ) == 0)
- {
- IsMcast = TRUE;
- } else {
- IsMcast = FALSE;
- }
- //
- // Client send initial request to server's listening port. Server
- // will select a UDP port to communicate with the client. The server
- // is required to use the same port as RemotePort to multicast the
- // data.
- //
- if (UdpEpt->RemotePort != Instance->ServerDataPort) {
- if (Instance->ServerDataPort != 0) {
- goto ON_EXIT;
- } else {
- //
- // For the subsequent exchange of requests, reconfigure the udpio as
- // (serverip, serverport, localip, localport).
- // Usually, the client set serverport as 0 to receive and reset it
- // once the first packet arrives to send ack.
- //
- Instance->ServerDataPort = UdpEpt->RemotePort;
- }
- }
- //
- // Copy the MTFTP packet to a continuous buffer if it isn't already so.
- //
- Len = UdpPacket->TotalSize;
- TotalNum = UdpPacket->BlockOpNum;
- if (TotalNum > 1) {
- Packet = AllocateZeroPool (Len);
- if (Packet == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
- NetbufCopy (UdpPacket, 0, Len, (UINT8 *)Packet);
- } else {
- Packet = (EFI_MTFTP6_PACKET *)NetbufGetByte (UdpPacket, 0, NULL);
- ASSERT (Packet != NULL);
- }
- Opcode = NTOHS (Packet->OpCode);
- //
- // Callback to the user's CheckPacket if provided. Abort the transmission
- // if CheckPacket returns an EFI_ERROR code.
- //
- if ((Instance->Token->CheckPacket != NULL) &&
- ((Opcode == EFI_MTFTP6_OPCODE_OACK) || (Opcode == EFI_MTFTP6_OPCODE_ERROR))
- )
- {
- Status = Instance->Token->CheckPacket (
- &Instance->Mtftp6,
- Instance->Token,
- (UINT16)Len,
- Packet
- );
- if (EFI_ERROR (Status)) {
- //
- // Send an error message to the server to inform it
- //
- if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {
- //
- // Free the received packet before send new packet in ReceiveNotify,
- // since the udpio might need to be reconfigured.
- //
- NetbufFree (UdpPacket);
- UdpPacket = NULL;
- //
- // Send the Mtftp6 error message if user aborted the current session.
- //
- Mtftp6SendError (
- Instance,
- EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
- (UINT8 *)"User aborted the transfer"
- );
- }
- Status = EFI_ABORTED;
- goto ON_EXIT;
- }
- }
- //
- // Switch the process routines by the operation code.
- //
- switch (Opcode) {
- case EFI_MTFTP6_OPCODE_DATA:
- if ((Len > (UINT32)(MTFTP6_DATA_HEAD_LEN + Instance->BlkSize)) || (Len < (UINT32)MTFTP6_DATA_HEAD_LEN)) {
- goto ON_EXIT;
- }
- //
- // Handle the data packet of Rrq.
- //
- Status = Mtftp6RrqHandleData (
- Instance,
- Packet,
- Len,
- &UdpPacket,
- &IsCompleted
- );
- break;
- case EFI_MTFTP6_OPCODE_OACK:
- if (IsMcast || (Len <= MTFTP6_OPCODE_LEN)) {
- goto ON_EXIT;
- }
- //
- // Handle the Oack packet of Rrq.
- //
- Status = Mtftp6RrqHandleOack (
- Instance,
- Packet,
- Len,
- &UdpPacket,
- &IsCompleted
- );
- break;
- default:
- //
- // Drop and return error if received error message.
- //
- Status = EFI_TFTP_ERROR;
- break;
- }
- ON_EXIT:
- //
- // Free the resources, then if !EFI_ERROR (Status), restart the
- // receive, otherwise end the session.
- //
- if ((Packet != NULL) && (TotalNum > 1)) {
- FreePool (Packet);
- }
- if (UdpPacket != NULL) {
- NetbufFree (UdpPacket);
- }
- if (!EFI_ERROR (Status) && !IsCompleted) {
- if (IsMcast) {
- Status = UdpIoRecvDatagram (
- Instance->McastUdpIo,
- Mtftp6RrqInput,
- Instance,
- 0
- );
- } else {
- Status = UdpIoRecvDatagram (
- Instance->UdpIo,
- Mtftp6RrqInput,
- Instance,
- 0
- );
- }
- }
- //
- // Clean up the current session if failed to continue.
- //
- if (EFI_ERROR (Status) || IsCompleted) {
- Mtftp6OperationClean (Instance, Status);
- }
- }
- /**
- Start the Mtftp6 instance to download. It first initializes some
- of the internal states, then builds and sends an RRQ request packet.
- Finally, it starts receive for the downloading.
- @param[in] Instance The pointer to the Mtftp6 instance.
- @param[in] Operation The operation code of current packet.
- @retval EFI_SUCCESS The Mtftp6 is started to download.
- @retval Others Failed to start to download.
- **/
- EFI_STATUS
- Mtftp6RrqStart (
- IN MTFTP6_INSTANCE *Instance,
- IN UINT16 Operation
- )
- {
- EFI_STATUS Status;
- //
- // The valid block number range are [1, 0xffff]. For example:
- // the client sends an RRQ request to the server, the server
- // transfers the DATA1 block. If option negotiation is ongoing,
- // the server will send back an OACK, then client will send ACK0.
- //
- Status = Mtftp6InitBlockRange (&Instance->BlkList, 1, 0xffff);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = Mtftp6SendRequest (Instance, Operation);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- return UdpIoRecvDatagram (
- Instance->UdpIo,
- Mtftp6RrqInput,
- Instance,
- 0
- );
- }
|