summaryrefslogtreecommitdiff
path: root/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c
diff options
context:
space:
mode:
Diffstat (limited to 'NetworkPkg/Mtftp6Dxe/Mtftp6Support.c')
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Support.c1213
1 files changed, 0 insertions, 1213 deletions
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c
deleted file mode 100644
index c31fc9dc27..0000000000
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c
+++ /dev/null
@@ -1,1213 +0,0 @@
-/** @file
- Mtftp6 support functions implementation.
-
- Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
-
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php.
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "Mtftp6Impl.h"
-
-
-/**
- Allocate a MTFTP block range, then init it to the range of [Start, End].
-
- @param[in] Start The start block number.
- @param[in] End The last block number in the range.
-
- @return Range The range of the allocated block buffer.
-
-**/
-MTFTP6_BLOCK_RANGE *
-Mtftp6AllocateRange (
- IN UINT16 Start,
- IN UINT16 End
- )
-{
- MTFTP6_BLOCK_RANGE *Range;
-
- Range = AllocateZeroPool (sizeof (MTFTP6_BLOCK_RANGE));
-
- if (Range == NULL) {
- return NULL;
- }
-
- InitializeListHead (&Range->Link);
- Range->Start = Start;
- Range->End = End;
- Range->Bound = End;
-
- return Range;
-}
-
-
-/**
- Initialize the block range for either RRQ or WRQ. RRQ and WRQ have
- different requirements for Start and End. For example, during startup,
- WRQ initializes its whole valid block range to [0, 0xffff]. This
- is bacause the server will send an ACK0 to inform the user to start the
- upload. When the client receives an ACK0, it will remove 0 from the range,
- get the next block number, which is 1, then upload the BLOCK1. For RRQ
- without option negotiation, the server will directly send the BLOCK1
- in response to the client's RRQ. When received BLOCK1, the client will
- remove it from the block range and send an ACK. It also works if there
- is option negotiation.
-
- @param[in] Head The block range head to initialize.
- @param[in] Start The Start block number.
- @param[in] End The last block number.
-
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for initial block range.
- @retval EFI_SUCCESS The initial block range is created.
-
-**/
-EFI_STATUS
-Mtftp6InitBlockRange (
- IN LIST_ENTRY *Head,
- IN UINT16 Start,
- IN UINT16 End
- )
-{
- MTFTP6_BLOCK_RANGE *Range;
-
- Range = Mtftp6AllocateRange (Start, End);
-
- if (Range == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- InsertTailList (Head, &Range->Link);
- return EFI_SUCCESS;
-}
-
-
-/**
- Get the first valid block number on the range list.
-
- @param[in] Head The block range head.
-
- @retval ==-1 If the block range is empty.
- @retval >-1 The first valid block number.
-
-**/
-INTN
-Mtftp6GetNextBlockNum (
- IN LIST_ENTRY *Head
- )
-{
- MTFTP6_BLOCK_RANGE *Range;
-
- if (IsListEmpty (Head)) {
- return -1;
- }
-
- Range = NET_LIST_HEAD (Head, MTFTP6_BLOCK_RANGE, Link);
- return Range->Start;
-}
-
-
-/**
- Set the last block number of the block range list. It
- removes all the blocks after the Last. MTFTP initialize the
- block range to the maximum possible range, such as [0, 0xffff]
- for WRQ. When it gets the last block number, it calls
- this function to set the last block number.
-
- @param[in] Head The block range list.
- @param[in] Last The last block number.
-
-**/
-VOID
-Mtftp6SetLastBlockNum (
- IN LIST_ENTRY *Head,
- IN UINT16 Last
- )
-{
- MTFTP6_BLOCK_RANGE *Range;
-
- //
- // Iterate from the tail to head to remove the block number
- // after the last.
- //
- while (!IsListEmpty (Head)) {
- Range = NET_LIST_TAIL (Head, MTFTP6_BLOCK_RANGE, Link);
-
- if (Range->Start > Last) {
- RemoveEntryList (&Range->Link);
- FreePool (Range);
- continue;
- }
-
- if (Range->End > Last) {
- Range->End = Last;
- }
- return ;
- }
-}
-
-
-/**
- Remove the block number from the block range list.
-
- @param[in] Head The block range list to remove from.
- @param[in] Num The block number to remove.
- @param[in] Completed Whether Num is the last block number
- @param[out] TotalBlock The continuous block number in all
-
- @retval EFI_NOT_FOUND The block number isn't in the block range list.
- @retval EFI_SUCCESS The block number has been removed from the list.
- @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
-
-**/
-EFI_STATUS
-Mtftp6RemoveBlockNum (
- IN LIST_ENTRY *Head,
- IN UINT16 Num,
- IN BOOLEAN Completed,
- OUT UINT64 *TotalBlock
- )
-{
- MTFTP6_BLOCK_RANGE *Range;
- MTFTP6_BLOCK_RANGE *NewRange;
- LIST_ENTRY *Entry;
-
- NET_LIST_FOR_EACH (Entry, Head) {
-
- //
- // Each block represents a hole [Start, End] in the file,
- // skip to the first range with End >= Num
- //
- Range = NET_LIST_USER_STRUCT (Entry, MTFTP6_BLOCK_RANGE, Link);
-
- if (Range->End < Num) {
- continue;
- }
-
- //
- // There are three different cases for Start
- // 1. (Start > Num) && (End >= Num):
- // because all the holes before this one has the condition of
- // End < Num, so this block number has been removed.
- //
- // 2. (Start == Num) && (End >= Num):
- // Need to increase the Start by one, and if End == Num, this
- // hole has been removed completely, remove it.
- //
- // 3. (Start < Num) && (End >= Num):
- // if End == Num, only need to decrease the End by one because
- // we have (Start < Num) && (Num == End), so (Start <= End - 1).
- // if (End > Num), the hold is splited into two holes, with
- // [Start, Num - 1] and [Num + 1, End].
- //
- if (Range->Start > Num) {
- return EFI_NOT_FOUND;
-
- } else if (Range->Start == Num) {
- Range->Start++;
-
- //
- // Note that: RFC 1350 does not mention block counter roll-over,
- // but several TFTP hosts implement the roll-over be able to accept
- // transfers of unlimited size. There is no consensus, however, whether
- // the counter should wrap around to zero or to one. Many implementations
- // wrap to zero, because this is the simplest to implement. Here we choose
- // this solution.
- //
- *TotalBlock = Num;
-
- if (Range->Round > 0) {
- *TotalBlock += Range->Bound + MultU64x32 ((UINT64) (Range->Round -1), (UINT32)(Range->Bound + 1)) + 1;
- }
-
- if (Range->Start > Range->Bound) {
- Range->Start = 0;
- Range->Round ++;
- }
-
- if ((Range->Start > Range->End) || Completed) {
- RemoveEntryList (&Range->Link);
- FreePool (Range);
- }
-
- return EFI_SUCCESS;
-
- } else {
- if (Range->End == Num) {
- Range->End--;
- } else {
- NewRange = Mtftp6AllocateRange ((UINT16) (Num + 1), (UINT16) Range->End);
-
- if (NewRange == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Range->End = Num - 1;
- NetListInsertAfter (&Range->Link, &NewRange->Link);
- }
-
- return EFI_SUCCESS;
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-
-/**
- Configure the opened Udp6 instance until the corresponding Ip6 instance
- has been configured.
-
- @param[in] UdpIo The pointer to the Udp6 Io.
- @param[in] UdpCfgData The pointer to the Udp6 configure data.
-
- @retval EFI_SUCCESS Configure the Udp6 instance successfully.
- @retval EFI_NO_MAPPING The corresponding Ip6 instance has not
- been configured yet.
-
-**/
-EFI_STATUS
-Mtftp6GetMapping (
- IN UDP_IO *UdpIo,
- IN EFI_UDP6_CONFIG_DATA *UdpCfgData
- )
-{
- EFI_IP6_MODE_DATA Ip6Mode;
- EFI_UDP6_PROTOCOL *Udp6;
- EFI_STATUS Status;
- EFI_EVENT Event;
-
- Event = NULL;
- Udp6 = UdpIo->Protocol.Udp6;
-
- //
- // Create a timer to check whether the Ip6 instance configured or not.
- //
- Status = gBS->CreateEvent (
- EVT_TIMER,
- TPL_CALLBACK,
- NULL,
- NULL,
- &Event
- );
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
-
- Status = gBS->SetTimer (
- Event,
- TimerRelative,
- MTFTP6_GET_MAPPING_TIMEOUT * MTFTP6_TICK_PER_SECOND
- );
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
-
- //
- // Check the Ip6 mode data till timeout.
- //
- while (EFI_ERROR (gBS->CheckEvent (Event))) {
-
- Udp6->Poll (Udp6);
-
- Status = Udp6->GetModeData (Udp6, NULL, &Ip6Mode, NULL, NULL);
-
- if (!EFI_ERROR (Status)) {
-
- if (Ip6Mode.IsConfigured) {
- //
- // Continue to configure the Udp6 instance.
- //
- Status = Udp6->Configure (Udp6, UdpCfgData);
- } else {
- Status = EFI_NO_MAPPING;
- }
- }
- }
-
-ON_EXIT:
-
- if (Event != NULL) {
- gBS->CloseEvent (Event);
- }
-
- return Status;
-}
-
-
-/**
- The dummy configure routine for create a new Udp6 Io.
-
- @param[in] UdpIo The pointer to the Udp6 Io.
- @param[in] Context The pointer to the context.
-
- @retval EFI_SUCCESS This value is always returned.
-
-**/
-EFI_STATUS
-EFIAPI
-Mtftp6ConfigDummyUdpIo (
- IN UDP_IO *UdpIo,
- IN VOID *Context
- )
-{
- return EFI_SUCCESS;
-}
-
-
-/**
- The configure routine for Mtftp6 instance to transmit/receive.
-
- @param[in] UdpIo The pointer to the Udp6 Io.
- @param[in] ServerIp The pointer to the server address.
- @param[in] ServerPort The pointer to the server port.
- @param[in] LocalIp The pointer to the local address.
- @param[in] LocalPort The pointer to the local port.
-
- @retval EFI_SUCCESS Configured the Udp6 Io for Mtftp6 successfully.
- @retval EFI_NO_MAPPING The corresponding Ip6 instance has not been
- configured yet.
-
-**/
-EFI_STATUS
-Mtftp6ConfigUdpIo (
- IN UDP_IO *UdpIo,
- IN EFI_IPv6_ADDRESS *ServerIp,
- IN UINT16 ServerPort,
- IN EFI_IPv6_ADDRESS *LocalIp,
- IN UINT16 LocalPort
- )
-{
- EFI_STATUS Status;
- EFI_UDP6_PROTOCOL *Udp6;
- EFI_UDP6_CONFIG_DATA *Udp6Cfg;
-
- Udp6 = UdpIo->Protocol.Udp6;
- Udp6Cfg = &(UdpIo->Config.Udp6);
-
- ZeroMem (Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));
-
- //
- // Set the Udp6 Io configure data.
- //
- Udp6Cfg->AcceptPromiscuous = FALSE;
- Udp6Cfg->AcceptAnyPort = FALSE;
- Udp6Cfg->AllowDuplicatePort = FALSE;
- Udp6Cfg->TrafficClass = 0;
- Udp6Cfg->HopLimit = 128;
- Udp6Cfg->ReceiveTimeout = 0;
- Udp6Cfg->TransmitTimeout = 0;
- Udp6Cfg->StationPort = LocalPort;
- Udp6Cfg->RemotePort = ServerPort;
-
- CopyMem (
- &Udp6Cfg->StationAddress,
- LocalIp,
- sizeof (EFI_IPv6_ADDRESS)
- );
-
- CopyMem (
- &Udp6Cfg->RemoteAddress,
- ServerIp,
- sizeof (EFI_IPv6_ADDRESS)
- );
-
- //
- // Configure the Udp6 instance with current configure data.
- //
- Status = Udp6->Configure (Udp6, Udp6Cfg);
-
- if (Status == EFI_NO_MAPPING) {
-
- return Mtftp6GetMapping (UdpIo, Udp6Cfg);
- }
-
- return Status;
-}
-
-
-/**
- Build and transmit the request packet for the Mtftp6 instance.
-
- @param[in] Instance The pointer to the Mtftp6 instance.
- @param[in] Operation The operation code of this packet.
-
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the request.
- @retval EFI_SUCCESS The request is built and sent.
- @retval Others Failed to transmit the packet.
-
-**/
-EFI_STATUS
-Mtftp6SendRequest (
- IN MTFTP6_INSTANCE *Instance,
- IN UINT16 Operation
- )
-{
- EFI_MTFTP6_PACKET *Packet;
- EFI_MTFTP6_OPTION *Options;
- EFI_MTFTP6_TOKEN *Token;
- RETURN_STATUS Status;
- NET_BUF *Nbuf;
- UINT8 *Mode;
- UINT8 *Cur;
- UINTN Index;
- UINT32 BufferLength;
- UINTN FileNameLength;
- UINTN ModeLength;
- UINTN OptionStrLength;
- UINTN ValueStrLength;
-
- Token = Instance->Token;
- Options = Token->OptionList;
- Mode = Token->ModeStr;
-
- if (Mode == NULL) {
- Mode = (UINT8 *) "octet";
- }
-
- //
- // The header format of RRQ/WRQ packet is:
- //
- // 2 bytes string 1 byte string 1 byte
- // ------------------------------------------------
- // | Opcode | Filename | 0 | Mode | 0 |
- // ------------------------------------------------
- //
- // The common option format is:
- //
- // string 1 byte string 1 byte
- // ---------------------------------------
- // | OptionStr | 0 | ValueStr | 0 |
- // ---------------------------------------
- //
-
- //
- // Compute the size of new Mtftp6 packet.
- //
- FileNameLength = AsciiStrLen ((CHAR8 *) Token->Filename);
- ModeLength = AsciiStrLen ((CHAR8 *) Mode);
- BufferLength = (UINT32) FileNameLength + (UINT32) ModeLength + 4;
-
- for (Index = 0; Index < Token->OptionCount; Index++) {
- OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);
- ValueStrLength = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);
- BufferLength += (UINT32) OptionStrLength + (UINT32) ValueStrLength + 2;
- }
-
- //
- // Allocate a packet then copy the data.
- //
- if ((Nbuf = NetbufAlloc (BufferLength)) == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Copy the opcode, filename and mode into packet.
- //
- Packet = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (Nbuf, BufferLength, FALSE);
- ASSERT (Packet != NULL);
-
- Packet->OpCode = HTONS (Operation);
- BufferLength -= sizeof (Packet->OpCode);
-
- Cur = Packet->Rrq.Filename;
- Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Token->Filename);
- ASSERT_EFI_ERROR (Status);
- BufferLength -= (UINT32) (FileNameLength + 1);
- Cur += FileNameLength + 1;
- Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Mode);
- ASSERT_EFI_ERROR (Status);
- BufferLength -= (UINT32) (ModeLength + 1);
- Cur += ModeLength + 1;
-
- //
- // Copy all the extension options into the packet.
- //
- for (Index = 0; Index < Token->OptionCount; ++Index) {
- OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);
- ValueStrLength = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);
-
- Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].OptionStr);
- ASSERT_EFI_ERROR (Status);
- BufferLength -= (UINT32) (OptionStrLength + 1);
- Cur += OptionStrLength + 1;
-
- Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].ValueStr);
- ASSERT_EFI_ERROR (Status);
- BufferLength -= (UINT32) (ValueStrLength + 1);
- Cur += ValueStrLength + 1;
-
- }
-
- //
- // Save the packet buf for retransmit
- //
- if (Instance->LastPacket != NULL) {
- NetbufFree (Instance->LastPacket);
- }
-
- Instance->LastPacket = Nbuf;
- Instance->CurRetry = 0;
-
- return Mtftp6TransmitPacket (Instance, Nbuf);
-}
-
-
-/**
- Build and send an error packet.
-
- @param[in] Instance The pointer to the Mtftp6 instance.
- @param[in] ErrCode The error code in the packet.
- @param[in] ErrInfo The error message in the packet.
-
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet.
- @retval EFI_SUCCESS The error packet is transmitted.
- @retval Others Failed to transmit the packet.
-
-**/
-EFI_STATUS
-Mtftp6SendError (
- IN MTFTP6_INSTANCE *Instance,
- IN UINT16 ErrCode,
- IN UINT8* ErrInfo
- )
-{
- NET_BUF *Nbuf;
- EFI_MTFTP6_PACKET *TftpError;
- UINT32 Len;
-
- //
- // Allocate a packet then copy the data.
- //
- Len = (UINT32) (AsciiStrLen ((CHAR8 *) ErrInfo) + sizeof (EFI_MTFTP6_ERROR_HEADER));
- Nbuf = NetbufAlloc (Len);
-
- if (Nbuf == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- TftpError = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (Nbuf, Len, FALSE);
-
- if (TftpError == NULL) {
- NetbufFree (Nbuf);
- return EFI_OUT_OF_RESOURCES;
- }
-
- TftpError->OpCode = HTONS (EFI_MTFTP6_OPCODE_ERROR);
- TftpError->Error.ErrorCode = HTONS (ErrCode);
-
- AsciiStrCpyS ((CHAR8 *) TftpError->Error.ErrorMessage, AsciiStrLen ((CHAR8 *) ErrInfo) + 1 , (CHAR8 *) ErrInfo);
-
- //
- // Save the packet buf for retransmit
- //
- if (Instance->LastPacket != NULL) {
- NetbufFree (Instance->LastPacket);
- }
-
- Instance->LastPacket = Nbuf;
- Instance->CurRetry = 0;
-
- return Mtftp6TransmitPacket (Instance, Nbuf);
-}
-
-
-/**
- The callback function called when the packet is transmitted.
-
- @param[in] Packet The pointer to the packet.
- @param[in] UdpEpt The pointer to the Udp6 access point.
- @param[in] IoStatus The result of the transmission.
- @param[in] Context The pointer to the context.
-
-**/
-VOID
-EFIAPI
-Mtftp6OnPacketSent (
- IN NET_BUF *Packet,
- IN UDP_END_POINT *UdpEpt,
- IN EFI_STATUS IoStatus,
- IN VOID *Context
- )
-{
- NetbufFree (Packet);
- *(BOOLEAN *) Context = TRUE;
-}
-
-
-/**
- Send the packet for the Mtftp6 instance.
-
- @param[in] Instance The pointer to the Mtftp6 instance.
- @param[in] Packet The pointer to the packet to be sent.
-
- @retval EFI_SUCCESS The packet was sent out
- @retval Others Failed to transmit the packet.
-
-**/
-EFI_STATUS
-Mtftp6TransmitPacket (
- IN MTFTP6_INSTANCE *Instance,
- IN NET_BUF *Packet
- )
-{
- EFI_UDP6_PROTOCOL *Udp6;
- EFI_UDP6_CONFIG_DATA Udp6CfgData;
- EFI_STATUS Status;
- UINT16 *Temp;
- UINT16 Value;
- UINT16 OpCode;
-
- ZeroMem (&Udp6CfgData, sizeof(EFI_UDP6_CONFIG_DATA));
- Udp6 = Instance->UdpIo->Protocol.Udp6;
-
- //
- // Set the live time of the packet.
- //
- Instance->PacketToLive = Instance->IsMaster ? Instance->Timeout : (Instance->Timeout * 2);
-
- Temp = (UINT16 *) NetbufGetByte (Packet, 0, NULL);
- ASSERT (Temp != NULL);
-
- Value = *Temp;
- OpCode = NTOHS (Value);
-
- if (OpCode == EFI_MTFTP6_OPCODE_RRQ || OpCode == EFI_MTFTP6_OPCODE_DIR || OpCode == EFI_MTFTP6_OPCODE_WRQ) {
- //
- // For the Rrq, Dir, Wrq requests of the operation, configure the Udp6Io as
- // (serverip, 69, localip, localport) to send.
- // Usually local address and local port are both default as zero.
- //
- Status = Udp6->Configure (Udp6, NULL);
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = Mtftp6ConfigUdpIo (
- Instance->UdpIo,
- &Instance->ServerIp,
- Instance->ServerCmdPort,
- &Instance->Config->StationIp,
- Instance->Config->LocalPort
- );
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Get the current local address and port by get Udp6 mode data.
- //
- Status = Udp6->GetModeData (Udp6, &Udp6CfgData, NULL, NULL, NULL);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- NET_GET_REF (Packet);
-
- Instance->IsTransmitted = FALSE;
-
- Status = UdpIoSendDatagram (
- Instance->UdpIo,
- Packet,
- NULL,
- NULL,
- Mtftp6OnPacketSent,
- &Instance->IsTransmitted
- );
-
- if (EFI_ERROR (Status)) {
- NET_PUT_REF (Packet);
- return Status;
- }
-
- //
- // Poll till the packet sent out from the ip6 queue.
- //
- gBS->RestoreTPL (Instance->OldTpl);
-
- while (!Instance->IsTransmitted) {
- Udp6->Poll (Udp6);
- }
-
- Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
-
- //
- // For the subsequent exchange of such requests, reconfigure the Udp6Io as
- // (serverip, 0, localip, localport) to receive.
- // Currently local address and local port are specified by Udp6 mode data.
- //
- Status = Udp6->Configure (Udp6, NULL);
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = Mtftp6ConfigUdpIo (
- Instance->UdpIo,
- &Instance->ServerIp,
- Instance->ServerDataPort,
- &Udp6CfgData.StationAddress,
- Udp6CfgData.StationPort
- );
- } else {
- //
- // For the data exchange, configure the Udp6Io as (serverip, dataport,
- // localip, localport) to send/receive.
- // Currently local address and local port are specified by Udp6 mode data.
- //
- Status = Udp6->GetModeData (Udp6, &Udp6CfgData, NULL, NULL, NULL);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Udp6CfgData.RemotePort != Instance->ServerDataPort) {
-
- Status = Udp6->Configure (Udp6, NULL);
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = Mtftp6ConfigUdpIo (
- Instance->UdpIo,
- &Instance->ServerIp,
- Instance->ServerDataPort,
- &Udp6CfgData.StationAddress,
- Udp6CfgData.StationPort
- );
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- NET_GET_REF (Packet);
-
- Instance->IsTransmitted = FALSE;
-
- Status = UdpIoSendDatagram (
- Instance->UdpIo,
- Packet,
- NULL,
- NULL,
- Mtftp6OnPacketSent,
- &Instance->IsTransmitted
- );
-
- if (EFI_ERROR (Status)) {
- NET_PUT_REF (Packet);
- }
-
- //
- // Poll till the packet sent out from the ip6 queue.
- //
- gBS->RestoreTPL (Instance->OldTpl);
-
- while (!Instance->IsTransmitted) {
- Udp6->Poll (Udp6);
- }
-
- Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- }
-
- return Status;
-}
-
-
-/**
- Check packet for GetInfo callback routine.
-
- GetInfo is implemented with EfiMtftp6ReadFile. It's used to inspect
- the first packet from server, then abort the session.
-
- @param[in] This The pointer to the Mtftp6 protocol.
- @param[in] Token The pointer to the Mtftp6 token.
- @param[in] PacketLen The length of the packet.
- @param[in] Packet The pointer to the received packet.
-
- @retval EFI_ABORTED Abort the Mtftp6 operation.
-
-**/
-EFI_STATUS
-EFIAPI
-Mtftp6CheckPacket (
- IN EFI_MTFTP6_PROTOCOL *This,
- IN EFI_MTFTP6_TOKEN *Token,
- IN UINT16 PacketLen,
- IN EFI_MTFTP6_PACKET *Packet
- )
-{
- MTFTP6_GETINFO_CONTEXT *Context;
- UINT16 OpCode;
-
- Context = (MTFTP6_GETINFO_CONTEXT *) Token->Context;
- OpCode = NTOHS (Packet->OpCode);
-
- //
- // Set the GetInfo's return status according to the OpCode.
- //
- switch (OpCode) {
- case EFI_MTFTP6_OPCODE_ERROR:
- Context->Status = EFI_TFTP_ERROR;
- break;
-
- case EFI_MTFTP6_OPCODE_OACK:
- Context->Status = EFI_SUCCESS;
- break;
-
- default:
- Context->Status = EFI_PROTOCOL_ERROR;
- }
-
- //
- // Allocate buffer then copy the packet over. Use gBS->AllocatePool
- // in case NetAllocatePool will implements something tricky.
- //
- *(Context->Packet) = AllocateZeroPool (PacketLen);
-
- if (*(Context->Packet) == NULL) {
- Context->Status = EFI_OUT_OF_RESOURCES;
- return EFI_ABORTED;
- }
-
- *(Context->PacketLen) = PacketLen;
- CopyMem (*(Context->Packet), Packet, PacketLen);
-
- return EFI_ABORTED;
-}
-
-
-/**
- Clean up the current Mtftp6 operation.
-
- @param[in] Instance The pointer to the Mtftp6 instance.
- @param[in] Result The result to be returned to the user.
-
-**/
-VOID
-Mtftp6OperationClean (
- IN MTFTP6_INSTANCE *Instance,
- IN EFI_STATUS Result
- )
-{
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- MTFTP6_BLOCK_RANGE *Block;
-
- //
- // Clean up the current token and event.
- //
- if (Instance->Token != NULL) {
- Instance->Token->Status = Result;
- if (Instance->Token->Event != NULL) {
- gBS->SignalEvent (Instance->Token->Event);
- }
- Instance->Token = NULL;
- }
-
- //
- // Clean up the corresponding Udp6Io.
- //
- if (Instance->UdpIo != NULL) {
- UdpIoCleanIo (Instance->UdpIo);
- }
-
- if (Instance->McastUdpIo != NULL) {
- gBS->CloseProtocol (
- Instance->McastUdpIo->UdpHandle,
- &gEfiUdp6ProtocolGuid,
- Instance->McastUdpIo->Image,
- Instance->Handle
- );
- UdpIoFreeIo (Instance->McastUdpIo);
- Instance->McastUdpIo = NULL;
- }
-
- //
- // Clean up the stored last packet.
- //
- if (Instance->LastPacket != NULL) {
- NetbufFree (Instance->LastPacket);
- Instance->LastPacket = NULL;
- }
-
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &Instance->BlkList) {
- Block = NET_LIST_USER_STRUCT (Entry, MTFTP6_BLOCK_RANGE, Link);
- RemoveEntryList (Entry);
- FreePool (Block);
- }
-
- //
- // Reinitialize the corresponding fields of the Mtftp6 operation.
- //
- ZeroMem (&Instance->ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
- ZeroMem (&Instance->ServerIp, sizeof (EFI_IPv6_ADDRESS));
- ZeroMem (&Instance->McastIp, sizeof (EFI_IPv6_ADDRESS));
-
- Instance->ServerCmdPort = 0;
- Instance->ServerDataPort = 0;
- Instance->McastPort = 0;
- Instance->BlkSize = 0;
- Instance->LastBlk = 0;
- Instance->PacketToLive = 0;
- Instance->MaxRetry = 0;
- Instance->CurRetry = 0;
- Instance->Timeout = 0;
- Instance->IsMaster = TRUE;
-}
-
-
-/**
- Start the Mtftp6 instance to perform the operation, such as read file,
- write file, and read directory.
-
- @param[in] This The MTFTP session.
- @param[in] Token The token than encapsues the user's request.
- @param[in] OpCode The operation to perform.
-
- @retval EFI_INVALID_PARAMETER Some of the parameters are invalid.
- @retval EFI_NOT_STARTED The MTFTP session hasn't been configured.
- @retval EFI_ALREADY_STARTED There is pending operation for the session.
- @retval EFI_SUCCESS The operation is successfully started.
-
-**/
-EFI_STATUS
-Mtftp6OperationStart (
- IN EFI_MTFTP6_PROTOCOL *This,
- IN EFI_MTFTP6_TOKEN *Token,
- IN UINT16 OpCode
- )
-{
- MTFTP6_INSTANCE *Instance;
- EFI_STATUS Status;
-
- if (This == NULL ||
- Token == NULL ||
- Token->Filename == NULL ||
- (Token->OptionCount != 0 && Token->OptionList == NULL) ||
- (Token->OverrideData != NULL && !NetIp6IsValidUnicast (&Token->OverrideData->ServerIp))
- ) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // At least define one method to collect the data for download.
- //
- if ((OpCode == EFI_MTFTP6_OPCODE_RRQ || OpCode == EFI_MTFTP6_OPCODE_DIR) &&
- Token->Buffer == NULL &&
- Token->CheckPacket == NULL
- ) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // At least define one method to provide the data for upload.
- //
- if (OpCode == EFI_MTFTP6_OPCODE_WRQ && Token->Buffer == NULL && Token->PacketNeeded == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- Instance = MTFTP6_INSTANCE_FROM_THIS (This);
-
- if (Instance->Config == NULL) {
- return EFI_NOT_STARTED;
- }
-
- if (Instance->Token != NULL) {
- return EFI_ACCESS_DENIED;
- }
-
- Status = EFI_SUCCESS;
- Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
-
- //
- // Parse the extension options in the request packet.
- //
- if (Token->OptionCount != 0) {
-
- Status = Mtftp6ParseExtensionOption (
- Token->OptionList,
- Token->OptionCount,
- TRUE,
- &Instance->ExtInfo
- );
-
- if (EFI_ERROR (Status)) {
- goto ON_ERROR;
- }
- }
-
- //
- // Initialize runtime data from config data or override data.
- //
- Instance->Token = Token;
- Instance->ServerCmdPort = Instance->Config->InitialServerPort;
- Instance->ServerDataPort = 0;
- Instance->MaxRetry = Instance->Config->TryCount;
- Instance->Timeout = Instance->Config->TimeoutValue;
- Instance->IsMaster = TRUE;
-
- CopyMem (
- &Instance->ServerIp,
- &Instance->Config->ServerIp,
- sizeof (EFI_IPv6_ADDRESS)
- );
-
- if (Token->OverrideData != NULL) {
- Instance->ServerCmdPort = Token->OverrideData->ServerPort;
- Instance->MaxRetry = Token->OverrideData->TryCount;
- Instance->Timeout = Token->OverrideData->TimeoutValue;
-
- CopyMem (
- &Instance->ServerIp,
- &Token->OverrideData->ServerIp,
- sizeof (EFI_IPv6_ADDRESS)
- );
- }
-
- //
- // Set default value for undefined parameters.
- //
- if (Instance->ServerCmdPort == 0) {
- Instance->ServerCmdPort = MTFTP6_DEFAULT_SERVER_CMD_PORT;
- }
- if (Instance->BlkSize == 0) {
- Instance->BlkSize = MTFTP6_DEFAULT_BLK_SIZE;
- }
- if (Instance->MaxRetry == 0) {
- Instance->MaxRetry = MTFTP6_DEFAULT_MAX_RETRY;
- }
- if (Instance->Timeout == 0) {
- Instance->Timeout = MTFTP6_DEFAULT_TIMEOUT;
- }
-
- Token->Status = EFI_NOT_READY;
-
- //
- // Switch the routines by the operation code.
- //
- switch (OpCode) {
- case EFI_MTFTP6_OPCODE_RRQ:
- Status = Mtftp6RrqStart (Instance, OpCode);
- break;
-
- case EFI_MTFTP6_OPCODE_DIR:
- Status = Mtftp6RrqStart (Instance, OpCode);
- break;
-
- case EFI_MTFTP6_OPCODE_WRQ:
- Status = Mtftp6WrqStart (Instance, OpCode);
- break;
-
- default:
- Status = EFI_DEVICE_ERROR;
- goto ON_ERROR;
- }
-
- if (EFI_ERROR (Status)) {
- goto ON_ERROR;
- }
-
- //
- // Return immediately for asynchronous or poll the instance for synchronous.
- //
- gBS->RestoreTPL (Instance->OldTpl);
-
- if (Token->Event == NULL) {
- while (Token->Status == EFI_NOT_READY) {
- This->Poll (This);
- }
- return Token->Status;
- }
-
- return EFI_SUCCESS;
-
-ON_ERROR:
-
- Mtftp6OperationClean (Instance, Status);
- gBS->RestoreTPL (Instance->OldTpl);
-
- return Status;
-}
-
-
-/**
- The timer ticking routine for the Mtftp6 instance.
-
- @param[in] Event The pointer to the ticking event.
- @param[in] Context The pointer to the context.
-
-**/
-VOID
-EFIAPI
-Mtftp6OnTimerTick (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- MTFTP6_SERVICE *Service;
- MTFTP6_INSTANCE *Instance;
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- EFI_MTFTP6_TOKEN *Token;
- EFI_STATUS Status;
-
- Service = (MTFTP6_SERVICE *) Context;
-
- //
- // Iterate through all the children of the Mtftp service instance. Time
- // out the packet. If maximum retries reached, clean the session up.
- //
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Children) {
-
- Instance = NET_LIST_USER_STRUCT (Entry, MTFTP6_INSTANCE, Link);
-
- if (Instance->Token == NULL) {
- continue;
- }
-
- if (Instance->PacketToLive > 0) {
- Instance->PacketToLive--;
- continue;
- }
-
- Instance->CurRetry++;
- Token = Instance->Token;
-
- if (Token->TimeoutCallback != NULL) {
- //
- // Call the timeout callback routine if has.
- //
- Status = Token->TimeoutCallback (&Instance->Mtftp6, Token);
-
- if (EFI_ERROR (Status)) {
- Mtftp6SendError (
- Instance,
- EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
- (UINT8 *) "User aborted the transfer in time out"
- );
- Mtftp6OperationClean (Instance, EFI_ABORTED);
- continue;
- }
- }
-
- //
- // Retransmit the packet if haven't reach the maxmium retry count,
- // otherwise exit the transfer.
- //
- if (Instance->CurRetry < Instance->MaxRetry) {
- Mtftp6TransmitPacket (Instance, Instance->LastPacket);
- } else {
- Mtftp6OperationClean (Instance, EFI_TIMEOUT);
- continue;
- }
- }
-}