123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804 |
- /** @file
- Routines to process Rrq (download).
- (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
- Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "Mtftp4Impl.h"
- /**
- The packet process callback for MTFTP download.
- @param UdpPacket The packet received
- @param EndPoint The local/remote access point of the packet
- @param IoStatus The status of the receiving
- @param Context Opaque parameter, which is the MTFTP session
- **/
- VOID
- EFIAPI
- Mtftp4RrqInput (
- IN NET_BUF *UdpPacket,
- IN UDP_END_POINT *EndPoint,
- IN EFI_STATUS IoStatus,
- IN VOID *Context
- );
- /**
- Start the MTFTP session to download.
- It will first initialize some of the internal states then build and send a RRQ
- request packet, at last, it will start receive for the downloading.
- @param Instance The Mtftp session
- @param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ
- or EFI_MTFTP4_OPCODE_DIR.
- @retval EFI_SUCCESS The mtftp download session is started.
- @retval Others Failed to start downloading.
- **/
- EFI_STATUS
- Mtftp4RrqStart (
- IN MTFTP4_PROTOCOL *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 = Mtftp4InitBlockRange (&Instance->Blocks, 1, 0xffff);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = Mtftp4SendRequest (Instance);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
- }
- /**
- Build and send a ACK packet for the download session.
- @param Instance The Mtftp session
- @param BlkNo The BlkNo to ack.
- @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
- Mtftp4RrqSendAck (
- IN MTFTP4_PROTOCOL *Instance,
- IN UINT16 BlkNo
- )
- {
- EFI_MTFTP4_PACKET *Ack;
- NET_BUF *Packet;
- EFI_STATUS Status;
- Status = EFI_SUCCESS;
- Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));
- if (Packet == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- Ack = (EFI_MTFTP4_PACKET *)NetbufAllocSpace (
- Packet,
- sizeof (EFI_MTFTP4_ACK_HEADER),
- FALSE
- );
- ASSERT (Ack != NULL);
- Ack->Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);
- Ack->Ack.Block[0] = HTONS (BlkNo);
- Status = Mtftp4SendPacket (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 Instance The Mtftp session
- @param Packet The received data packet
- @param Len The packet length
- @retval EFI_SUCCESS The data is 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
- Mtftp4RrqSaveBlock (
- IN OUT MTFTP4_PROTOCOL *Instance,
- IN EFI_MTFTP4_PACKET *Packet,
- IN UINT32 Len
- )
- {
- EFI_MTFTP4_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 - MTFTP4_DATA_HEAD_LEN;
- //
- // This is the last block, save the block no
- //
- if (DataLen < Instance->BlkSize) {
- Completed = TRUE;
- Instance->LastBlock = Block;
- Mtftp4SetLastBlockNum (&Instance->Blocks, Block);
- }
- //
- // Remove this block number from the file hole. If Mtftp4RemoveBlockNum
- // 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 = Mtftp4RemoveBlockNum (&Instance->Blocks, Block, Completed, &BlockCounter);
- if (Status == EFI_NOT_FOUND) {
- return EFI_SUCCESS;
- } else if (EFI_ERROR (Status)) {
- return Status;
- }
- if (Token->CheckPacket != NULL) {
- Status = Token->CheckPacket (&Instance->Mtftp4, Token, (UINT16)Len, Packet);
- if (EFI_ERROR (Status)) {
- Mtftp4SendError (
- Instance,
- EFI_MTFTP4_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->LastBlock == Block) && Completed) {
- Token->BufferSize = Start + DataLen;
- }
- } else if (Instance->LastBlock != 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;
- Mtftp4SendError (
- Instance,
- EFI_MTFTP4_ERRORCODE_DISK_FULL,
- (UINT8 *)"User provided memory block is too small"
- );
- return EFI_BUFFER_TOO_SMALL;
- }
- }
- return EFI_SUCCESS;
- }
- /**
- Function to process the received data packets.
- It will save the block then send back an ACK if it is active.
- @param Instance The downloading MTFTP session
- @param Packet The packet received
- @param Len The length of the packet
- @param Multicast Whether this packet is multicast or unicast
- @param Completed Return whether the download has completed
- @retval EFI_SUCCESS The data packet is successfully processed
- @retval EFI_ABORTED The download is aborted by the user
- @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
- **/
- EFI_STATUS
- Mtftp4RrqHandleData (
- IN MTFTP4_PROTOCOL *Instance,
- IN EFI_MTFTP4_PACKET *Packet,
- IN UINT32 Len,
- IN BOOLEAN Multicast,
- OUT BOOLEAN *Completed
- )
- {
- EFI_STATUS Status;
- UINT16 BlockNum;
- INTN Expected;
- *Completed = FALSE;
- Status = EFI_SUCCESS;
- BlockNum = NTOHS (Packet->Data.Block);
- Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
- 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->Master && (Expected != BlockNum)) {
- //
- // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).
- //
- return Mtftp4RrqSendAck (Instance, (UINT16)(Expected - 1));
- }
- Status = Mtftp4RrqSaveBlock (Instance, Packet, Len);
- 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->Master) {
- Mtftp4SetTimeout (Instance);
- }
- //
- // 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 = Mtftp4GetNextBlockNum (&Instance->Blocks);
- if (Instance->Master || (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->LastBlock;
- *Completed = TRUE;
- } else {
- BlockNum = (UINT16)(Expected - 1);
- }
- if ((Instance->WindowSize == (Instance->TotalBlock - Instance->AckedBlock)) || (Expected < 0)) {
- Status = Mtftp4RrqSendAck (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 This The downloading Mtftp session
- @param Reply The options in the OACK packet
- @param Request The requested options
- @retval TRUE The options in the OACK is OK.
- @retval FALSE The options in the OACK is invalid.
- **/
- BOOLEAN
- Mtftp4RrqOackValid (
- IN MTFTP4_PROTOCOL *This,
- IN MTFTP4_OPTION *Reply,
- IN MTFTP4_OPTION *Request
- )
- {
- //
- // It is invalid for server to return options we don't request
- //
- if ((Reply->Exist &~Request->Exist) != 0) {
- return FALSE;
- }
- //
- // Server can only specify a smaller block size and window size to be used and
- // return the timeout matches that requested.
- //
- if ((((Reply->Exist & MTFTP4_BLKSIZE_EXIST) != 0) && (Reply->BlkSize > Request->BlkSize)) ||
- (((Reply->Exist & MTFTP4_WINDOWSIZE_EXIST) != 0) && (Reply->WindowSize > Request->WindowSize)) ||
- (((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->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 (((Reply->Exist & MTFTP4_MCAST_EXIST) != 0) && (This->McastIp != 0)) {
- if ((Reply->McastIp != 0) && (Reply->McastIp != This->McastIp)) {
- return FALSE;
- }
- if ((Reply->McastPort != 0) && (Reply->McastPort != This->McastPort)) {
- return FALSE;
- }
- }
- return TRUE;
- }
- /**
- Configure a UDP IO port to receive the multicast.
- @param McastIo The UDP IO to configure
- @param Context The opaque parameter to the function which is the
- MTFTP session.
- @retval EFI_SUCCESS The UDP child is successfully configured.
- @retval Others Failed to configure the UDP child.
- **/
- EFI_STATUS
- EFIAPI
- Mtftp4RrqConfigMcastPort (
- IN UDP_IO *McastIo,
- IN VOID *Context
- )
- {
- MTFTP4_PROTOCOL *Instance;
- EFI_MTFTP4_CONFIG_DATA *Config;
- EFI_UDP4_CONFIG_DATA UdpConfig;
- EFI_IPv4_ADDRESS Group;
- EFI_STATUS Status;
- IP4_ADDR Ip;
- Instance = (MTFTP4_PROTOCOL *)Context;
- Config = &Instance->Config;
- UdpConfig.AcceptBroadcast = FALSE;
- UdpConfig.AcceptPromiscuous = FALSE;
- UdpConfig.AcceptAnyPort = FALSE;
- UdpConfig.AllowDuplicatePort = FALSE;
- UdpConfig.TypeOfService = 0;
- UdpConfig.TimeToLive = 64;
- UdpConfig.DoNotFragment = FALSE;
- UdpConfig.ReceiveTimeout = 0;
- UdpConfig.TransmitTimeout = 0;
- UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;
- IP4_COPY_ADDRESS (&UdpConfig.StationAddress, &Config->StationIp);
- IP4_COPY_ADDRESS (&UdpConfig.SubnetMask, &Config->SubnetMask);
- UdpConfig.StationPort = Instance->McastPort;
- UdpConfig.RemotePort = 0;
- Ip = HTONL (Instance->ServerIp);
- IP4_COPY_ADDRESS (&UdpConfig.RemoteAddress, &Ip);
- Status = McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, &UdpConfig);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (!Config->UseDefaultSetting &&
- !EFI_IP4_EQUAL (&mZeroIp4Addr, &Config->GatewayIp))
- {
- //
- // The station IP address is manually configured and the Gateway IP is not 0.
- // Add the default route for this UDP instance.
- //
- Status = McastIo->Protocol.Udp4->Routes (
- McastIo->Protocol.Udp4,
- FALSE,
- &mZeroIp4Addr,
- &mZeroIp4Addr,
- &Config->GatewayIp
- );
- if (EFI_ERROR (Status)) {
- McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, NULL);
- return Status;
- }
- }
- //
- // join the multicast group
- //
- Ip = HTONL (Instance->McastIp);
- IP4_COPY_ADDRESS (&Group, &Ip);
- return McastIo->Protocol.Udp4->Groups (McastIo->Protocol.Udp4, TRUE, &Group);
- }
- /**
- Function to process the OACK.
- It will first validate the OACK packet, then update the various negotiated parameters.
- @param Instance The download MTFTP session
- @param Packet The packet received
- @param Len The packet length
- @param Multicast Whether this packet is received as a multicast
- @param Completed Returns whether the download has completed. NOT
- used by this function.
- @retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child
- @retval EFI_TFTP_ERROR Some error happened during the process
- @retval EFI_SUCCESS The OACK is successfully processed.
- **/
- EFI_STATUS
- Mtftp4RrqHandleOack (
- IN OUT MTFTP4_PROTOCOL *Instance,
- IN EFI_MTFTP4_PACKET *Packet,
- IN UINT32 Len,
- IN BOOLEAN Multicast,
- OUT BOOLEAN *Completed
- )
- {
- MTFTP4_OPTION Reply;
- EFI_STATUS Status;
- INTN Expected;
- EFI_UDP4_PROTOCOL *Udp4;
- *Completed = FALSE;
- //
- // If already started the master download, don't change the
- // setting. Master download always succeeds.
- //
- Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
- ASSERT (Expected != -1);
- if (Instance->Master && (Expected != 1)) {
- return EFI_SUCCESS;
- }
- //
- // Parse and validate the options from server
- //
- ZeroMem (&Reply, sizeof (MTFTP4_OPTION));
- Status = Mtftp4ParseOptionOack (Packet, Len, Instance->Operation, &Reply);
- if (EFI_ERROR (Status) ||
- !Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption))
- {
- //
- // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
- //
- if (Status != EFI_OUT_OF_RESOURCES) {
- Mtftp4SendError (
- Instance,
- EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
- (UINT8 *)"Malformatted OACK packet"
- );
- }
- return EFI_TFTP_ERROR;
- }
- if ((Reply.Exist & MTFTP4_MCAST_EXIST) != 0) {
- //
- // Save the multicast info. Always update the Master, only update the
- // multicast IP address, block size, window size, timeout at the first time.
- // If IP address is updated, create a UDP child to receive the multicast.
- //
- Instance->Master = Reply.Master;
- if (Instance->McastIp == 0) {
- if ((Reply.McastIp == 0) || (Reply.McastPort == 0)) {
- Mtftp4SendError (
- Instance,
- EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
- (UINT8 *)"Illegal multicast setting"
- );
- return EFI_TFTP_ERROR;
- }
- //
- // Create a UDP child then start receive the multicast from it.
- //
- Instance->McastIp = Reply.McastIp;
- Instance->McastPort = Reply.McastPort;
- if (Instance->McastUdpPort == NULL) {
- Instance->McastUdpPort = UdpIoCreateIo (
- Instance->Service->Controller,
- Instance->Service->Image,
- Mtftp4RrqConfigMcastPort,
- UDP_IO_UDP4_VERSION,
- Instance
- );
- if (Instance->McastUdpPort != NULL) {
- Status = gBS->OpenProtocol (
- Instance->McastUdpPort->UdpHandle,
- &gEfiUdp4ProtocolGuid,
- (VOID **)&Udp4,
- Instance->Service->Image,
- Instance->Handle,
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
- );
- if (EFI_ERROR (Status)) {
- UdpIoFreeIo (Instance->McastUdpPort);
- Instance->McastUdpPort = NULL;
- return EFI_DEVICE_ERROR;
- }
- }
- }
- if (Instance->McastUdpPort == NULL) {
- return EFI_DEVICE_ERROR;
- }
- Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);
- if (EFI_ERROR (Status)) {
- Mtftp4SendError (
- Instance,
- EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION,
- (UINT8 *)"Failed to create socket to receive multicast packet"
- );
- return Status;
- }
- //
- // Update the parameters used.
- //
- if (Reply.BlkSize != 0) {
- Instance->BlkSize = Reply.BlkSize;
- }
- if (Reply.WindowSize != 0) {
- Instance->WindowSize = Reply.WindowSize;
- }
- if (Reply.Timeout != 0) {
- Instance->Timeout = Reply.Timeout;
- }
- }
- } else {
- Instance->Master = TRUE;
- if (Reply.BlkSize != 0) {
- Instance->BlkSize = Reply.BlkSize;
- }
- if (Reply.WindowSize != 0) {
- Instance->WindowSize = Reply.WindowSize;
- }
- if (Reply.Timeout != 0) {
- Instance->Timeout = Reply.Timeout;
- }
- }
- //
- // Send an ACK to (Expected - 1) which is 0 for unicast download,
- // or tell the server we want to receive the Expected block.
- //
- return Mtftp4RrqSendAck (Instance, (UINT16)(Expected - 1));
- }
- /**
- The packet process callback for MTFTP download.
- @param UdpPacket The packet received
- @param EndPoint The local/remote access point of the packet
- @param IoStatus The status of the receiving
- @param Context Opaque parameter, which is the MTFTP session
- **/
- VOID
- EFIAPI
- Mtftp4RrqInput (
- IN NET_BUF *UdpPacket,
- IN UDP_END_POINT *EndPoint,
- IN EFI_STATUS IoStatus,
- IN VOID *Context
- )
- {
- MTFTP4_PROTOCOL *Instance;
- EFI_MTFTP4_PACKET *Packet;
- BOOLEAN Completed;
- BOOLEAN Multicast;
- EFI_STATUS Status;
- UINT16 Opcode;
- UINT32 Len;
- Instance = (MTFTP4_PROTOCOL *)Context;
- NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);
- Status = EFI_SUCCESS;
- Packet = NULL;
- Completed = FALSE;
- Multicast = FALSE;
- if (EFI_ERROR (IoStatus)) {
- Status = IoStatus;
- goto ON_EXIT;
- }
- ASSERT (UdpPacket != NULL);
- //
- // Find the port this packet is from to restart receive correctly.
- //
- Multicast = (BOOLEAN)(EndPoint->LocalAddr.Addr[0] == Instance->McastIp);
- if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {
- goto ON_EXIT;
- }
- //
- // 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 (EndPoint->RemotePort != Instance->ConnectedPort) {
- if (Instance->ConnectedPort != 0) {
- goto ON_EXIT;
- } else {
- Instance->ConnectedPort = EndPoint->RemotePort;
- }
- }
- //
- // Copy the MTFTP packet to a continuous buffer if it isn't already so.
- //
- Len = UdpPacket->TotalSize;
- if (UdpPacket->BlockOpNum > 1) {
- Packet = AllocatePool (Len);
- if (Packet == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
- NetbufCopy (UdpPacket, 0, Len, (UINT8 *)Packet);
- } else {
- Packet = (EFI_MTFTP4_PACKET *)NetbufGetByte (UdpPacket, 0, NULL);
- ASSERT (Packet != NULL);
- }
- Opcode = NTOHS (Packet->OpCode);
- //
- // Call the user's CheckPacket if provided. Abort the transmission
- // if CheckPacket returns an EFI_ERROR code.
- //
- if ((Instance->Token->CheckPacket != NULL) &&
- ((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR)))
- {
- Status = Instance->Token->CheckPacket (
- &Instance->Mtftp4,
- Instance->Token,
- (UINT16)Len,
- Packet
- );
- if (EFI_ERROR (Status)) {
- //
- // Send an error message to the server to inform it
- //
- if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {
- Mtftp4SendError (
- Instance,
- EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
- (UINT8 *)"User aborted the transfer"
- );
- }
- Status = EFI_ABORTED;
- goto ON_EXIT;
- }
- }
- switch (Opcode) {
- case EFI_MTFTP4_OPCODE_DATA:
- if ((Len > (UINT32)(MTFTP4_DATA_HEAD_LEN + Instance->BlkSize)) ||
- (Len < (UINT32)MTFTP4_DATA_HEAD_LEN))
- {
- goto ON_EXIT;
- }
- Status = Mtftp4RrqHandleData (Instance, Packet, Len, Multicast, &Completed);
- break;
- case EFI_MTFTP4_OPCODE_OACK:
- if (Multicast || (Len <= MTFTP4_OPCODE_LEN)) {
- goto ON_EXIT;
- }
- Status = Mtftp4RrqHandleOack (Instance, Packet, Len, Multicast, &Completed);
- break;
- case EFI_MTFTP4_OPCODE_ERROR:
- Status = EFI_TFTP_ERROR;
- break;
- default:
- break;
- }
- ON_EXIT:
- //
- // Free the resources, then if !EFI_ERROR (Status), restart the
- // receive, otherwise end the session.
- //
- if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {
- FreePool (Packet);
- }
- if (UdpPacket != NULL) {
- NetbufFree (UdpPacket);
- }
- if (!EFI_ERROR (Status) && !Completed) {
- if (Multicast) {
- Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);
- } else {
- Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
- }
- }
- if (EFI_ERROR (Status) || Completed) {
- Mtftp4CleanOperation (Instance, Status);
- }
- }
|