Home | History | Annotate | Download | only in Mtftp6Dxe
      1 /** @file
      2   Mtftp6 support functions implementation.
      3 
      4   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "Mtftp6Impl.h"
     17 
     18 
     19 /**
     20   Allocate a MTFTP block range, then init it to the range of [Start, End].
     21 
     22   @param[in]  Start                  The start block number.
     23   @param[in]  End                    The last block number in the range.
     24 
     25   @return Range                      The range of the allocated block buffer.
     26 
     27 **/
     28 MTFTP6_BLOCK_RANGE *
     29 Mtftp6AllocateRange (
     30   IN UINT16                 Start,
     31   IN UINT16                 End
     32   )
     33 {
     34   MTFTP6_BLOCK_RANGE        *Range;
     35 
     36   Range = AllocateZeroPool (sizeof (MTFTP6_BLOCK_RANGE));
     37 
     38   if (Range == NULL) {
     39     return NULL;
     40   }
     41 
     42   InitializeListHead (&Range->Link);
     43   Range->Start  = Start;
     44   Range->End    = End;
     45   Range->Bound  = End;
     46 
     47   return Range;
     48 }
     49 
     50 
     51 /**
     52   Initialize the block range for either RRQ or WRQ. RRQ and WRQ have
     53   different requirements for Start and End. For example, during startup,
     54   WRQ initializes its whole valid block range to [0, 0xffff]. This
     55   is bacause the server will send an ACK0 to inform the user to start the
     56   upload. When the client receives an ACK0, it will remove 0 from the range,
     57   get the next block number, which is 1, then upload the BLOCK1. For RRQ
     58   without option negotiation, the server will directly send the BLOCK1
     59   in response to the client's RRQ. When received BLOCK1, the client will
     60   remove it from the block range and send an ACK. It also works if there
     61   is option negotiation.
     62 
     63   @param[in]  Head                   The block range head to initialize.
     64   @param[in]  Start                  The Start block number.
     65   @param[in]  End                    The last block number.
     66 
     67   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory for initial block range.
     68   @retval EFI_SUCCESS            The initial block range is created.
     69 
     70 **/
     71 EFI_STATUS
     72 Mtftp6InitBlockRange (
     73   IN LIST_ENTRY             *Head,
     74   IN UINT16                 Start,
     75   IN UINT16                 End
     76   )
     77 {
     78   MTFTP6_BLOCK_RANGE        *Range;
     79 
     80   Range = Mtftp6AllocateRange (Start, End);
     81 
     82   if (Range == NULL) {
     83     return EFI_OUT_OF_RESOURCES;
     84   }
     85 
     86   InsertTailList (Head, &Range->Link);
     87   return EFI_SUCCESS;
     88 }
     89 
     90 
     91 /**
     92   Get the first valid block number on the range list.
     93 
     94   @param[in]  Head                   The block range head.
     95 
     96   @retval     ==-1                   If the block range is empty.
     97   @retval     >-1                    The first valid block number.
     98 
     99 **/
    100 INTN
    101 Mtftp6GetNextBlockNum (
    102   IN LIST_ENTRY              *Head
    103   )
    104 {
    105   MTFTP6_BLOCK_RANGE  *Range;
    106 
    107   if (IsListEmpty (Head)) {
    108     return -1;
    109   }
    110 
    111   Range = NET_LIST_HEAD (Head, MTFTP6_BLOCK_RANGE, Link);
    112   return Range->Start;
    113 }
    114 
    115 
    116 /**
    117   Set the last block number of the block range list. It
    118   removes all the blocks after the Last. MTFTP initialize the
    119   block range to the maximum possible range, such as [0, 0xffff]
    120   for WRQ. When it gets the last block number, it calls
    121   this function to set the last block number.
    122 
    123   @param[in]  Head                   The block range list.
    124   @param[in]  Last                   The last block number.
    125 
    126 **/
    127 VOID
    128 Mtftp6SetLastBlockNum (
    129   IN LIST_ENTRY             *Head,
    130   IN UINT16                 Last
    131   )
    132 {
    133   MTFTP6_BLOCK_RANGE        *Range;
    134 
    135   //
    136   // Iterate from the tail to head to remove the block number
    137   // after the last.
    138   //
    139   while (!IsListEmpty (Head)) {
    140     Range = NET_LIST_TAIL (Head, MTFTP6_BLOCK_RANGE, Link);
    141 
    142     if (Range->Start > Last) {
    143       RemoveEntryList (&Range->Link);
    144       FreePool (Range);
    145       continue;
    146     }
    147 
    148     if (Range->End > Last) {
    149       Range->End = Last;
    150     }
    151     return ;
    152   }
    153 }
    154 
    155 
    156 /**
    157   Remove the block number from the block range list.
    158 
    159   @param[in]  Head                   The block range list to remove from.
    160   @param[in]  Num                    The block number to remove.
    161   @param[in]  Completed              Whether Num is the last block number
    162   @param[out] TotalBlock             The continuous block number in all
    163 
    164   @retval EFI_NOT_FOUND          The block number isn't in the block range list.
    165   @retval EFI_SUCCESS            The block number has been removed from the list.
    166   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.
    167 
    168 **/
    169 EFI_STATUS
    170 Mtftp6RemoveBlockNum (
    171   IN LIST_ENTRY             *Head,
    172   IN UINT16                 Num,
    173   IN BOOLEAN                Completed,
    174   OUT UINT64                *TotalBlock
    175   )
    176 {
    177   MTFTP6_BLOCK_RANGE        *Range;
    178   MTFTP6_BLOCK_RANGE        *NewRange;
    179   LIST_ENTRY                *Entry;
    180 
    181   NET_LIST_FOR_EACH (Entry, Head) {
    182 
    183     //
    184     // Each block represents a hole [Start, End] in the file,
    185     // skip to the first range with End >= Num
    186     //
    187     Range = NET_LIST_USER_STRUCT (Entry, MTFTP6_BLOCK_RANGE, Link);
    188 
    189     if (Range->End < Num) {
    190       continue;
    191     }
    192 
    193     //
    194     // There are three different cases for Start
    195     // 1. (Start > Num) && (End >= Num):
    196     //    because all the holes before this one has the condition of
    197     //    End < Num, so this block number has been removed.
    198     //
    199     // 2. (Start == Num) && (End >= Num):
    200     //    Need to increase the Start by one, and if End == Num, this
    201     //    hole has been removed completely, remove it.
    202     //
    203     // 3. (Start < Num) && (End >= Num):
    204     //    if End == Num, only need to decrease the End by one because
    205     //    we have (Start < Num) && (Num == End), so (Start <= End - 1).
    206     //    if (End > Num), the hold is splited into two holes, with
    207     //    [Start, Num - 1] and [Num + 1, End].
    208     //
    209     if (Range->Start > Num) {
    210       return EFI_NOT_FOUND;
    211 
    212     } else if (Range->Start == Num) {
    213       Range->Start++;
    214 
    215       //
    216       // Note that: RFC 1350 does not mention block counter roll-over,
    217       // but several TFTP hosts implement the roll-over be able to accept
    218       // transfers of unlimited size. There is no consensus, however, whether
    219       // the counter should wrap around to zero or to one. Many implementations
    220       // wrap to zero, because this is the simplest to implement. Here we choose
    221       // this solution.
    222       //
    223       *TotalBlock  = Num;
    224 
    225       if (Range->Round > 0) {
    226         *TotalBlock += Range->Bound +  MultU64x32 ((UINT64) (Range->Round -1), (UINT32)(Range->Bound + 1)) + 1;
    227       }
    228 
    229       if (Range->Start > Range->Bound) {
    230         Range->Start = 0;
    231         Range->Round ++;
    232       }
    233 
    234       if ((Range->Start > Range->End) || Completed) {
    235         RemoveEntryList (&Range->Link);
    236         FreePool (Range);
    237       }
    238 
    239       return EFI_SUCCESS;
    240 
    241     } else {
    242       if (Range->End == Num) {
    243         Range->End--;
    244       } else {
    245         NewRange = Mtftp6AllocateRange ((UINT16) (Num + 1), (UINT16) Range->End);
    246 
    247         if (NewRange == NULL) {
    248           return EFI_OUT_OF_RESOURCES;
    249         }
    250 
    251         Range->End = Num - 1;
    252         NetListInsertAfter (&Range->Link, &NewRange->Link);
    253       }
    254 
    255       return EFI_SUCCESS;
    256     }
    257   }
    258 
    259   return EFI_NOT_FOUND;
    260 }
    261 
    262 
    263 /**
    264   Configure the opened Udp6 instance until the corresponding Ip6 instance
    265   has been configured.
    266 
    267   @param[in]  UdpIo                  The pointer to the Udp6 Io.
    268   @param[in]  UdpCfgData             The pointer to the Udp6 configure data.
    269 
    270   @retval EFI_SUCCESS            Configure the Udp6 instance successfully.
    271   @retval EFI_NO_MAPPING         The corresponding Ip6 instance has not
    272                                  been configured yet.
    273 
    274 **/
    275 EFI_STATUS
    276 Mtftp6GetMapping (
    277   IN UDP_IO                 *UdpIo,
    278   IN EFI_UDP6_CONFIG_DATA   *UdpCfgData
    279   )
    280 {
    281   EFI_IP6_MODE_DATA         Ip6Mode;
    282   EFI_UDP6_PROTOCOL         *Udp6;
    283   EFI_STATUS                Status;
    284   EFI_EVENT                 Event;
    285 
    286   Event  = NULL;
    287   Udp6   = UdpIo->Protocol.Udp6;
    288 
    289   //
    290   // Create a timer to check whether the Ip6 instance configured or not.
    291   //
    292   Status = gBS->CreateEvent (
    293                   EVT_TIMER,
    294                   TPL_CALLBACK,
    295                   NULL,
    296                   NULL,
    297                   &Event
    298                   );
    299   if (EFI_ERROR (Status)) {
    300     goto ON_EXIT;
    301   }
    302 
    303   Status = gBS->SetTimer (
    304                   Event,
    305                   TimerRelative,
    306                   MTFTP6_GET_MAPPING_TIMEOUT * MTFTP6_TICK_PER_SECOND
    307                   );
    308   if (EFI_ERROR (Status)) {
    309     goto ON_EXIT;
    310   }
    311 
    312   //
    313   // Check the Ip6 mode data till timeout.
    314   //
    315   while (EFI_ERROR (gBS->CheckEvent (Event))) {
    316 
    317     Udp6->Poll (Udp6);
    318 
    319     Status = Udp6->GetModeData (Udp6, NULL, &Ip6Mode, NULL, NULL);
    320 
    321     if (!EFI_ERROR (Status)) {
    322       if (Ip6Mode.AddressList != NULL) {
    323         FreePool (Ip6Mode.AddressList);
    324       }
    325 
    326       if (Ip6Mode.GroupTable != NULL) {
    327         FreePool (Ip6Mode.GroupTable);
    328       }
    329 
    330       if (Ip6Mode.RouteTable != NULL) {
    331         FreePool (Ip6Mode.RouteTable);
    332       }
    333 
    334       if (Ip6Mode.NeighborCache != NULL) {
    335         FreePool (Ip6Mode.NeighborCache);
    336       }
    337 
    338       if (Ip6Mode.PrefixTable != NULL) {
    339         FreePool (Ip6Mode.PrefixTable);
    340       }
    341 
    342       if (Ip6Mode.IcmpTypeList != NULL) {
    343         FreePool (Ip6Mode.IcmpTypeList);
    344       }
    345 
    346       if  (Ip6Mode.IsConfigured) {
    347         //
    348         // Continue to configure the Udp6 instance.
    349         //
    350         Status = Udp6->Configure (Udp6, UdpCfgData);
    351       } else {
    352         Status = EFI_NO_MAPPING;
    353       }
    354     }
    355   }
    356 
    357 ON_EXIT:
    358 
    359   if (Event != NULL) {
    360     gBS->CloseEvent (Event);
    361   }
    362 
    363   return Status;
    364 }
    365 
    366 
    367 /**
    368   The dummy configure routine for create a new Udp6 Io.
    369 
    370   @param[in]  UdpIo                  The pointer to the Udp6 Io.
    371   @param[in]  Context                The pointer to the context.
    372 
    373   @retval EFI_SUCCESS                This value is always returned.
    374 
    375 **/
    376 EFI_STATUS
    377 EFIAPI
    378 Mtftp6ConfigDummyUdpIo (
    379   IN UDP_IO                 *UdpIo,
    380   IN VOID                   *Context
    381   )
    382 {
    383   return EFI_SUCCESS;
    384 }
    385 
    386 
    387 /**
    388   The configure routine for Mtftp6 instance to transmit/receive.
    389 
    390   @param[in]  UdpIo                  The pointer to the Udp6 Io.
    391   @param[in]  ServerIp               The pointer to the server address.
    392   @param[in]  ServerPort             The pointer to the server port.
    393   @param[in]  LocalIp                The pointer to the local address.
    394   @param[in]  LocalPort              The pointer to the local port.
    395 
    396   @retval EFI_SUCCESS            Configured the Udp6 Io for Mtftp6 successfully.
    397   @retval EFI_NO_MAPPING         The corresponding Ip6 instance has not been
    398                                  configured yet.
    399 
    400 **/
    401 EFI_STATUS
    402 Mtftp6ConfigUdpIo (
    403   IN UDP_IO                 *UdpIo,
    404   IN EFI_IPv6_ADDRESS       *ServerIp,
    405   IN UINT16                 ServerPort,
    406   IN EFI_IPv6_ADDRESS       *LocalIp,
    407   IN UINT16                 LocalPort
    408   )
    409 {
    410   EFI_STATUS                Status;
    411   EFI_UDP6_PROTOCOL         *Udp6;
    412   EFI_UDP6_CONFIG_DATA      *Udp6Cfg;
    413 
    414   Udp6    = UdpIo->Protocol.Udp6;
    415   Udp6Cfg = &(UdpIo->Config.Udp6);
    416 
    417   ZeroMem (Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));
    418 
    419   //
    420   // Set the Udp6 Io configure data.
    421   //
    422   Udp6Cfg->AcceptPromiscuous  = FALSE;
    423   Udp6Cfg->AcceptAnyPort      = FALSE;
    424   Udp6Cfg->AllowDuplicatePort = FALSE;
    425   Udp6Cfg->TrafficClass       = 0;
    426   Udp6Cfg->HopLimit           = 128;
    427   Udp6Cfg->ReceiveTimeout     = 0;
    428   Udp6Cfg->TransmitTimeout    = 0;
    429   Udp6Cfg->StationPort        = LocalPort;
    430   Udp6Cfg->RemotePort         = ServerPort;
    431 
    432   CopyMem (
    433     &Udp6Cfg->StationAddress,
    434     LocalIp,
    435     sizeof (EFI_IPv6_ADDRESS)
    436     );
    437 
    438   CopyMem (
    439     &Udp6Cfg->RemoteAddress,
    440     ServerIp,
    441     sizeof (EFI_IPv6_ADDRESS)
    442     );
    443 
    444   //
    445   // Configure the Udp6 instance with current configure data.
    446   //
    447   Status = Udp6->Configure (Udp6, Udp6Cfg);
    448 
    449   if (Status == EFI_NO_MAPPING) {
    450 
    451     return Mtftp6GetMapping (UdpIo, Udp6Cfg);
    452   }
    453 
    454   return Status;
    455 }
    456 
    457 
    458 /**
    459   Build and transmit the request packet for the Mtftp6 instance.
    460 
    461   @param[in]  Instance               The pointer to the Mtftp6 instance.
    462   @param[in]  Operation              The operation code of this packet.
    463 
    464   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory for the request.
    465   @retval EFI_SUCCESS            The request is built and sent.
    466   @retval Others                 Failed to transmit the packet.
    467 
    468 **/
    469 EFI_STATUS
    470 Mtftp6SendRequest (
    471   IN MTFTP6_INSTANCE        *Instance,
    472   IN UINT16                 Operation
    473   )
    474 {
    475   EFI_MTFTP6_PACKET         *Packet;
    476   EFI_MTFTP6_OPTION         *Options;
    477   EFI_MTFTP6_TOKEN          *Token;
    478   RETURN_STATUS             Status;
    479   NET_BUF                   *Nbuf;
    480   UINT8                     *Mode;
    481   UINT8                     *Cur;
    482   UINTN                     Index;
    483   UINT32                    BufferLength;
    484   UINTN                     FileNameLength;
    485   UINTN                     ModeLength;
    486   UINTN                     OptionStrLength;
    487   UINTN                     ValueStrLength;
    488 
    489   Token   = Instance->Token;
    490   Options = Token->OptionList;
    491   Mode    = Token->ModeStr;
    492 
    493   if (Mode == NULL) {
    494     Mode = (UINT8 *) "octet";
    495   }
    496 
    497   //
    498   // The header format of RRQ/WRQ packet is:
    499   //
    500   //   2 bytes     string    1 byte     string   1 byte
    501   //   ------------------------------------------------
    502   //  | Opcode |  Filename  |   0  |    Mode    |   0  |
    503   //   ------------------------------------------------
    504   //
    505   // The common option format is:
    506   //
    507   //    string     1 byte     string   1 byte
    508   //   ---------------------------------------
    509   //  | OptionStr |   0  |  ValueStr  |   0   |
    510   //   ---------------------------------------
    511   //
    512 
    513   //
    514   // Compute the size of new Mtftp6 packet.
    515   //
    516   FileNameLength = AsciiStrLen ((CHAR8 *) Token->Filename);
    517   ModeLength     = AsciiStrLen ((CHAR8 *) Mode);
    518   BufferLength   = (UINT32) FileNameLength + (UINT32) ModeLength + 4;
    519 
    520   for (Index = 0; Index < Token->OptionCount; Index++) {
    521     OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);
    522     ValueStrLength  = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);
    523     BufferLength   += (UINT32) OptionStrLength + (UINT32) ValueStrLength + 2;
    524   }
    525 
    526   //
    527   // Allocate a packet then copy the data.
    528   //
    529   if ((Nbuf = NetbufAlloc (BufferLength)) == NULL) {
    530     return EFI_OUT_OF_RESOURCES;
    531   }
    532 
    533   //
    534   // Copy the opcode, filename and mode into packet.
    535   //
    536   Packet         = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (Nbuf, BufferLength, FALSE);
    537   ASSERT (Packet != NULL);
    538 
    539   Packet->OpCode = HTONS (Operation);
    540   BufferLength  -= sizeof (Packet->OpCode);
    541 
    542   Cur            = Packet->Rrq.Filename;
    543   Status         = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Token->Filename);
    544   ASSERT_EFI_ERROR (Status);
    545   BufferLength  -= (UINT32) (FileNameLength + 1);
    546   Cur           += FileNameLength + 1;
    547   Status         = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Mode);
    548   ASSERT_EFI_ERROR (Status);
    549   BufferLength  -= (UINT32) (ModeLength + 1);
    550   Cur           += ModeLength + 1;
    551 
    552   //
    553   // Copy all the extension options into the packet.
    554   //
    555   for (Index = 0; Index < Token->OptionCount; ++Index) {
    556     OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);
    557     ValueStrLength  = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);
    558 
    559     Status          = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].OptionStr);
    560     ASSERT_EFI_ERROR (Status);
    561     BufferLength   -= (UINT32) (OptionStrLength + 1);
    562     Cur            += OptionStrLength + 1;
    563 
    564     Status          = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].ValueStr);
    565     ASSERT_EFI_ERROR (Status);
    566     BufferLength   -= (UINT32) (ValueStrLength + 1);
    567     Cur            += ValueStrLength + 1;
    568 
    569   }
    570 
    571   //
    572   // Save the packet buf for retransmit
    573   //
    574   if (Instance->LastPacket != NULL) {
    575     NetbufFree (Instance->LastPacket);
    576   }
    577 
    578   Instance->LastPacket = Nbuf;
    579   Instance->CurRetry   = 0;
    580 
    581   return Mtftp6TransmitPacket (Instance, Nbuf);
    582 }
    583 
    584 
    585 /**
    586   Build and send an error packet.
    587 
    588   @param[in]  Instance               The pointer to the Mtftp6 instance.
    589   @param[in]  ErrCode                The error code in the packet.
    590   @param[in]  ErrInfo                The error message in the packet.
    591 
    592   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory for the error packet.
    593   @retval EFI_SUCCESS            The error packet is transmitted.
    594   @retval Others                 Failed to transmit the packet.
    595 
    596 **/
    597 EFI_STATUS
    598 Mtftp6SendError (
    599   IN MTFTP6_INSTANCE        *Instance,
    600   IN UINT16                 ErrCode,
    601   IN UINT8*                 ErrInfo
    602   )
    603 {
    604   NET_BUF                   *Nbuf;
    605   EFI_MTFTP6_PACKET         *TftpError;
    606   UINT32                    Len;
    607 
    608   //
    609   // Allocate a packet then copy the data.
    610   //
    611   Len  = (UINT32) (AsciiStrLen ((CHAR8 *) ErrInfo) + sizeof (EFI_MTFTP6_ERROR_HEADER));
    612   Nbuf = NetbufAlloc (Len);
    613 
    614   if (Nbuf == NULL) {
    615     return EFI_OUT_OF_RESOURCES;
    616   }
    617 
    618   TftpError = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (Nbuf, Len, FALSE);
    619 
    620   if (TftpError == NULL) {
    621     NetbufFree (Nbuf);
    622     return EFI_OUT_OF_RESOURCES;
    623   }
    624 
    625   TftpError->OpCode          = HTONS (EFI_MTFTP6_OPCODE_ERROR);
    626   TftpError->Error.ErrorCode = HTONS (ErrCode);
    627 
    628   AsciiStrCpyS ((CHAR8 *) TftpError->Error.ErrorMessage, AsciiStrLen ((CHAR8 *) ErrInfo) + 1 , (CHAR8 *) ErrInfo);
    629 
    630   //
    631   // Save the packet buf for retransmit
    632   //
    633   if (Instance->LastPacket != NULL) {
    634     NetbufFree (Instance->LastPacket);
    635   }
    636 
    637   Instance->LastPacket = Nbuf;
    638   Instance->CurRetry   = 0;
    639 
    640   return Mtftp6TransmitPacket (Instance, Nbuf);
    641 }
    642 
    643 
    644 /**
    645   The callback function called when the packet is transmitted.
    646 
    647   @param[in]  Packet                 The pointer to the packet.
    648   @param[in]  UdpEpt                 The pointer to the Udp6 access point.
    649   @param[in]  IoStatus               The result of the transmission.
    650   @param[in]  Context                The pointer to the context.
    651 
    652 **/
    653 VOID
    654 EFIAPI
    655 Mtftp6OnPacketSent (
    656   IN NET_BUF                   *Packet,
    657   IN UDP_END_POINT             *UdpEpt,
    658   IN EFI_STATUS                IoStatus,
    659   IN VOID                      *Context
    660   )
    661 {
    662   NetbufFree (Packet);
    663   *(BOOLEAN *) Context = TRUE;
    664 }
    665 
    666 
    667 /**
    668   Send the packet for the Mtftp6 instance.
    669 
    670   @param[in]  Instance               The pointer to the Mtftp6 instance.
    671   @param[in]  Packet                 The pointer to the packet to be sent.
    672 
    673   @retval EFI_SUCCESS            The packet was sent out
    674   @retval Others                 Failed to transmit the packet.
    675 
    676 **/
    677 EFI_STATUS
    678 Mtftp6TransmitPacket (
    679   IN MTFTP6_INSTANCE        *Instance,
    680   IN NET_BUF                *Packet
    681   )
    682 {
    683   EFI_UDP6_PROTOCOL         *Udp6;
    684   EFI_UDP6_CONFIG_DATA      Udp6CfgData;
    685   EFI_STATUS                Status;
    686   UINT16                    *Temp;
    687   UINT16                    Value;
    688   UINT16                    OpCode;
    689 
    690   ZeroMem (&Udp6CfgData, sizeof(EFI_UDP6_CONFIG_DATA));
    691   Udp6 = Instance->UdpIo->Protocol.Udp6;
    692 
    693   //
    694   // Set the live time of the packet.
    695   //
    696   Instance->PacketToLive = Instance->IsMaster ? Instance->Timeout : (Instance->Timeout * 2);
    697 
    698   Temp   = (UINT16 *) NetbufGetByte (Packet, 0, NULL);
    699   ASSERT (Temp != NULL);
    700 
    701   Value  = *Temp;
    702   OpCode = NTOHS (Value);
    703 
    704   if (OpCode == EFI_MTFTP6_OPCODE_RRQ || OpCode == EFI_MTFTP6_OPCODE_DIR || OpCode == EFI_MTFTP6_OPCODE_WRQ) {
    705     //
    706     // For the Rrq, Dir, Wrq requests of the operation, configure the Udp6Io as
    707     // (serverip, 69, localip, localport) to send.
    708     // Usually local address and local port are both default as zero.
    709     //
    710     Status = Udp6->Configure (Udp6, NULL);
    711 
    712     if (EFI_ERROR (Status)) {
    713       return Status;
    714     }
    715 
    716     Status = Mtftp6ConfigUdpIo (
    717                Instance->UdpIo,
    718                &Instance->ServerIp,
    719                Instance->ServerCmdPort,
    720                &Instance->Config->StationIp,
    721                Instance->Config->LocalPort
    722                );
    723 
    724     if (EFI_ERROR (Status)) {
    725       return Status;
    726     }
    727 
    728     //
    729     // Get the current local address and port by get Udp6 mode data.
    730     //
    731     Status = Udp6->GetModeData (Udp6, &Udp6CfgData, NULL, NULL, NULL);
    732     if (EFI_ERROR (Status)) {
    733       return Status;
    734     }
    735 
    736     NET_GET_REF (Packet);
    737 
    738     Instance->IsTransmitted = FALSE;
    739 
    740     Status = UdpIoSendDatagram (
    741                Instance->UdpIo,
    742                Packet,
    743                NULL,
    744                NULL,
    745                Mtftp6OnPacketSent,
    746                &Instance->IsTransmitted
    747                );
    748 
    749     if (EFI_ERROR (Status)) {
    750       NET_PUT_REF (Packet);
    751       return Status;
    752     }
    753 
    754     //
    755     // Poll till the packet sent out from the ip6 queue.
    756     //
    757     gBS->RestoreTPL (Instance->OldTpl);
    758 
    759     while (!Instance->IsTransmitted) {
    760       Udp6->Poll (Udp6);
    761     }
    762 
    763     Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    764 
    765     //
    766     // For the subsequent exchange of such requests, reconfigure the Udp6Io as
    767     // (serverip, 0, localip, localport) to receive.
    768     // Currently local address and local port are specified by Udp6 mode data.
    769     //
    770     Status = Udp6->Configure (Udp6, NULL);
    771 
    772     if (EFI_ERROR (Status)) {
    773       return Status;
    774     }
    775 
    776     Status = Mtftp6ConfigUdpIo (
    777                Instance->UdpIo,
    778                &Instance->ServerIp,
    779                Instance->ServerDataPort,
    780                &Udp6CfgData.StationAddress,
    781                Udp6CfgData.StationPort
    782                );
    783   } else {
    784     //
    785     // For the data exchange, configure the Udp6Io as (serverip, dataport,
    786     // localip, localport) to send/receive.
    787     // Currently local address and local port are specified by Udp6 mode data.
    788     //
    789     Status = Udp6->GetModeData (Udp6, &Udp6CfgData, NULL, NULL, NULL);
    790     if (EFI_ERROR (Status)) {
    791       return Status;
    792     }
    793 
    794     if (Udp6CfgData.RemotePort != Instance->ServerDataPort) {
    795 
    796       Status = Udp6->Configure (Udp6, NULL);
    797 
    798       if (EFI_ERROR (Status)) {
    799         return Status;
    800       }
    801 
    802       Status = Mtftp6ConfigUdpIo (
    803                  Instance->UdpIo,
    804                  &Instance->ServerIp,
    805                  Instance->ServerDataPort,
    806                  &Udp6CfgData.StationAddress,
    807                  Udp6CfgData.StationPort
    808                  );
    809 
    810       if (EFI_ERROR (Status)) {
    811         return Status;
    812       }
    813     }
    814 
    815     NET_GET_REF (Packet);
    816 
    817     Instance->IsTransmitted = FALSE;
    818 
    819     Status = UdpIoSendDatagram (
    820                Instance->UdpIo,
    821                Packet,
    822                NULL,
    823                NULL,
    824                Mtftp6OnPacketSent,
    825                &Instance->IsTransmitted
    826                );
    827 
    828     if (EFI_ERROR (Status)) {
    829       NET_PUT_REF (Packet);
    830     }
    831 
    832     //
    833     // Poll till the packet sent out from the ip6 queue.
    834     //
    835     gBS->RestoreTPL (Instance->OldTpl);
    836 
    837     while (!Instance->IsTransmitted) {
    838       Udp6->Poll (Udp6);
    839     }
    840 
    841     Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    842   }
    843 
    844   return Status;
    845 }
    846 
    847 
    848 /**
    849   Check packet for GetInfo callback routine.
    850 
    851   GetInfo is implemented with EfiMtftp6ReadFile. It's used to inspect
    852   the first packet from server, then abort the session.
    853 
    854   @param[in]  This                   The pointer to the Mtftp6 protocol.
    855   @param[in]  Token                  The pointer to the Mtftp6 token.
    856   @param[in]  PacketLen              The length of the packet.
    857   @param[in]  Packet                 The pointer to the received packet.
    858 
    859   @retval EFI_ABORTED            Abort the Mtftp6 operation.
    860 
    861 **/
    862 EFI_STATUS
    863 EFIAPI
    864 Mtftp6CheckPacket (
    865   IN EFI_MTFTP6_PROTOCOL    *This,
    866   IN EFI_MTFTP6_TOKEN       *Token,
    867   IN UINT16                 PacketLen,
    868   IN EFI_MTFTP6_PACKET      *Packet
    869   )
    870 {
    871   MTFTP6_GETINFO_CONTEXT    *Context;
    872   UINT16                    OpCode;
    873 
    874   Context = (MTFTP6_GETINFO_CONTEXT *) Token->Context;
    875   OpCode  = NTOHS (Packet->OpCode);
    876 
    877   //
    878   // Set the GetInfo's return status according to the OpCode.
    879   //
    880   switch (OpCode) {
    881   case EFI_MTFTP6_OPCODE_ERROR:
    882     Context->Status = EFI_TFTP_ERROR;
    883     break;
    884 
    885   case EFI_MTFTP6_OPCODE_OACK:
    886     Context->Status = EFI_SUCCESS;
    887     break;
    888 
    889   default:
    890     Context->Status = EFI_PROTOCOL_ERROR;
    891   }
    892 
    893   //
    894   // Allocate buffer then copy the packet over. Use gBS->AllocatePool
    895   // in case NetAllocatePool will implements something tricky.
    896   //
    897   *(Context->Packet) = AllocateZeroPool (PacketLen);
    898 
    899   if (*(Context->Packet) == NULL) {
    900     Context->Status = EFI_OUT_OF_RESOURCES;
    901     return EFI_ABORTED;
    902   }
    903 
    904   *(Context->PacketLen) = PacketLen;
    905   CopyMem (*(Context->Packet), Packet, PacketLen);
    906 
    907   return EFI_ABORTED;
    908 }
    909 
    910 
    911 /**
    912   Clean up the current Mtftp6 operation.
    913 
    914   @param[in]  Instance               The pointer to the Mtftp6 instance.
    915   @param[in]  Result                 The result to be returned to the user.
    916 
    917 **/
    918 VOID
    919 Mtftp6OperationClean (
    920   IN MTFTP6_INSTANCE        *Instance,
    921   IN EFI_STATUS             Result
    922   )
    923 {
    924   LIST_ENTRY                *Entry;
    925   LIST_ENTRY                *Next;
    926   MTFTP6_BLOCK_RANGE        *Block;
    927 
    928   //
    929   // Clean up the current token and event.
    930   //
    931   if (Instance->Token != NULL) {
    932     Instance->Token->Status = Result;
    933     if (Instance->Token->Event != NULL) {
    934       gBS->SignalEvent (Instance->Token->Event);
    935     }
    936     Instance->Token = NULL;
    937   }
    938 
    939   //
    940   // Clean up the corresponding Udp6Io.
    941   //
    942   if (Instance->UdpIo != NULL) {
    943     UdpIoCleanIo (Instance->UdpIo);
    944   }
    945 
    946   if (Instance->McastUdpIo != NULL) {
    947     gBS->CloseProtocol (
    948            Instance->McastUdpIo->UdpHandle,
    949            &gEfiUdp6ProtocolGuid,
    950            Instance->McastUdpIo->Image,
    951            Instance->Handle
    952            );
    953     UdpIoFreeIo (Instance->McastUdpIo);
    954     Instance->McastUdpIo = NULL;
    955   }
    956 
    957   //
    958   // Clean up the stored last packet.
    959   //
    960   if (Instance->LastPacket != NULL) {
    961     NetbufFree (Instance->LastPacket);
    962     Instance->LastPacket = NULL;
    963   }
    964 
    965   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Instance->BlkList) {
    966     Block = NET_LIST_USER_STRUCT (Entry, MTFTP6_BLOCK_RANGE, Link);
    967     RemoveEntryList (Entry);
    968     FreePool (Block);
    969   }
    970 
    971   //
    972   // Reinitialize the corresponding fields of the Mtftp6 operation.
    973   //
    974   ZeroMem (&Instance->ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
    975   ZeroMem (&Instance->ServerIp, sizeof (EFI_IPv6_ADDRESS));
    976   ZeroMem (&Instance->McastIp, sizeof (EFI_IPv6_ADDRESS));
    977 
    978   Instance->ServerCmdPort  = 0;
    979   Instance->ServerDataPort = 0;
    980   Instance->McastPort      = 0;
    981   Instance->BlkSize        = 0;
    982   Instance->LastBlk        = 0;
    983   Instance->PacketToLive   = 0;
    984   Instance->MaxRetry       = 0;
    985   Instance->CurRetry       = 0;
    986   Instance->Timeout        = 0;
    987   Instance->IsMaster       = TRUE;
    988 }
    989 
    990 
    991 /**
    992   Start the Mtftp6 instance to perform the operation, such as read file,
    993   write file, and read directory.
    994 
    995   @param[in]  This                   The MTFTP session.
    996   @param[in]  Token                  The token than encapsues the user's request.
    997   @param[in]  OpCode                 The operation to perform.
    998 
    999   @retval EFI_INVALID_PARAMETER  Some of the parameters are invalid.
   1000   @retval EFI_NOT_STARTED        The MTFTP session hasn't been configured.
   1001   @retval EFI_ALREADY_STARTED    There is pending operation for the session.
   1002   @retval EFI_SUCCESS            The operation is successfully started.
   1003 
   1004 **/
   1005 EFI_STATUS
   1006 Mtftp6OperationStart (
   1007   IN EFI_MTFTP6_PROTOCOL    *This,
   1008   IN EFI_MTFTP6_TOKEN       *Token,
   1009   IN UINT16                 OpCode
   1010   )
   1011 {
   1012   MTFTP6_INSTANCE           *Instance;
   1013   EFI_STATUS                Status;
   1014 
   1015   if (This == NULL ||
   1016       Token == NULL ||
   1017       Token->Filename == NULL ||
   1018       (Token->OptionCount != 0 && Token->OptionList == NULL) ||
   1019       (Token->OverrideData != NULL && !NetIp6IsValidUnicast (&Token->OverrideData->ServerIp))
   1020       ) {
   1021     return EFI_INVALID_PARAMETER;
   1022   }
   1023 
   1024   //
   1025   // At least define one method to collect the data for download.
   1026   //
   1027   if ((OpCode == EFI_MTFTP6_OPCODE_RRQ || OpCode == EFI_MTFTP6_OPCODE_DIR) &&
   1028       Token->Buffer == NULL &&
   1029       Token->CheckPacket == NULL
   1030       ) {
   1031     return EFI_INVALID_PARAMETER;
   1032   }
   1033 
   1034   //
   1035   // At least define one method to provide the data for upload.
   1036   //
   1037   if (OpCode == EFI_MTFTP6_OPCODE_WRQ && Token->Buffer == NULL && Token->PacketNeeded == NULL) {
   1038     return EFI_INVALID_PARAMETER;
   1039   }
   1040 
   1041   Instance = MTFTP6_INSTANCE_FROM_THIS (This);
   1042 
   1043   if (Instance->Config == NULL) {
   1044     return EFI_NOT_STARTED;
   1045   }
   1046 
   1047   if (Instance->Token != NULL) {
   1048     return EFI_ACCESS_DENIED;
   1049   }
   1050 
   1051   Status           = EFI_SUCCESS;
   1052   Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1053 
   1054   //
   1055   // Parse the extension options in the request packet.
   1056   //
   1057   if (Token->OptionCount != 0) {
   1058 
   1059     Status = Mtftp6ParseExtensionOption (
   1060                Token->OptionList,
   1061                Token->OptionCount,
   1062                TRUE,
   1063                &Instance->ExtInfo
   1064                );
   1065 
   1066     if (EFI_ERROR (Status)) {
   1067       goto ON_ERROR;
   1068     }
   1069   }
   1070 
   1071   //
   1072   // Initialize runtime data from config data or override data.
   1073   //
   1074   Instance->Token           = Token;
   1075   Instance->ServerCmdPort   = Instance->Config->InitialServerPort;
   1076   Instance->ServerDataPort  = 0;
   1077   Instance->MaxRetry        = Instance->Config->TryCount;
   1078   Instance->Timeout         = Instance->Config->TimeoutValue;
   1079   Instance->IsMaster        = TRUE;
   1080 
   1081   CopyMem (
   1082     &Instance->ServerIp,
   1083     &Instance->Config->ServerIp,
   1084     sizeof (EFI_IPv6_ADDRESS)
   1085     );
   1086 
   1087   if (Token->OverrideData != NULL) {
   1088     Instance->ServerCmdPort = Token->OverrideData->ServerPort;
   1089     Instance->MaxRetry      = Token->OverrideData->TryCount;
   1090     Instance->Timeout       = Token->OverrideData->TimeoutValue;
   1091 
   1092     CopyMem (
   1093       &Instance->ServerIp,
   1094       &Token->OverrideData->ServerIp,
   1095       sizeof (EFI_IPv6_ADDRESS)
   1096       );
   1097   }
   1098 
   1099   //
   1100   // Set default value for undefined parameters.
   1101   //
   1102   if (Instance->ServerCmdPort == 0) {
   1103     Instance->ServerCmdPort = MTFTP6_DEFAULT_SERVER_CMD_PORT;
   1104   }
   1105   if (Instance->BlkSize == 0) {
   1106     Instance->BlkSize = MTFTP6_DEFAULT_BLK_SIZE;
   1107   }
   1108   if (Instance->MaxRetry == 0) {
   1109     Instance->MaxRetry = MTFTP6_DEFAULT_MAX_RETRY;
   1110   }
   1111   if (Instance->Timeout == 0) {
   1112     Instance->Timeout = MTFTP6_DEFAULT_TIMEOUT;
   1113   }
   1114 
   1115   Token->Status = EFI_NOT_READY;
   1116 
   1117   //
   1118   // Switch the routines by the operation code.
   1119   //
   1120   switch (OpCode) {
   1121   case EFI_MTFTP6_OPCODE_RRQ:
   1122     Status = Mtftp6RrqStart (Instance, OpCode);
   1123     break;
   1124 
   1125   case EFI_MTFTP6_OPCODE_DIR:
   1126     Status = Mtftp6RrqStart (Instance, OpCode);
   1127     break;
   1128 
   1129   case EFI_MTFTP6_OPCODE_WRQ:
   1130     Status = Mtftp6WrqStart (Instance, OpCode);
   1131     break;
   1132 
   1133   default:
   1134     Status = EFI_DEVICE_ERROR;
   1135     goto ON_ERROR;
   1136   }
   1137 
   1138   if (EFI_ERROR (Status)) {
   1139     goto ON_ERROR;
   1140   }
   1141 
   1142   //
   1143   // Return immediately for asynchronous or poll the instance for synchronous.
   1144   //
   1145   gBS->RestoreTPL (Instance->OldTpl);
   1146 
   1147   if (Token->Event == NULL) {
   1148     while (Token->Status == EFI_NOT_READY) {
   1149       This->Poll (This);
   1150     }
   1151     return Token->Status;
   1152   }
   1153 
   1154   return EFI_SUCCESS;
   1155 
   1156 ON_ERROR:
   1157 
   1158   Mtftp6OperationClean (Instance, Status);
   1159   gBS->RestoreTPL (Instance->OldTpl);
   1160 
   1161   return Status;
   1162 }
   1163 
   1164 
   1165 /**
   1166   The timer ticking routine for the Mtftp6 instance.
   1167 
   1168   @param[in]  Event                  The pointer to the ticking event.
   1169   @param[in]  Context                The pointer to the context.
   1170 
   1171 **/
   1172 VOID
   1173 EFIAPI
   1174 Mtftp6OnTimerTick (
   1175   IN EFI_EVENT              Event,
   1176   IN VOID                   *Context
   1177   )
   1178 {
   1179   MTFTP6_SERVICE            *Service;
   1180   MTFTP6_INSTANCE           *Instance;
   1181   LIST_ENTRY                *Entry;
   1182   LIST_ENTRY                *Next;
   1183   EFI_MTFTP6_TOKEN          *Token;
   1184   EFI_STATUS                Status;
   1185 
   1186   Service = (MTFTP6_SERVICE *) Context;
   1187 
   1188   //
   1189   // Iterate through all the children of the Mtftp service instance. Time
   1190   // out the packet. If maximum retries reached, clean the session up.
   1191   //
   1192   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Children) {
   1193 
   1194     Instance = NET_LIST_USER_STRUCT (Entry, MTFTP6_INSTANCE, Link);
   1195 
   1196     if (Instance->Token == NULL) {
   1197       continue;
   1198     }
   1199 
   1200     if (Instance->PacketToLive > 0) {
   1201       Instance->PacketToLive--;
   1202       continue;
   1203     }
   1204 
   1205     Instance->CurRetry++;
   1206     Token = Instance->Token;
   1207 
   1208     if (Token->TimeoutCallback != NULL) {
   1209       //
   1210       // Call the timeout callback routine if has.
   1211       //
   1212       Status = Token->TimeoutCallback (&Instance->Mtftp6, Token);
   1213 
   1214       if (EFI_ERROR (Status)) {
   1215         Mtftp6SendError (
   1216            Instance,
   1217            EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
   1218            (UINT8 *) "User aborted the transfer in time out"
   1219            );
   1220         Mtftp6OperationClean (Instance, EFI_ABORTED);
   1221         continue;
   1222       }
   1223     }
   1224 
   1225     //
   1226     // Retransmit the packet if haven't reach the maxmium retry count,
   1227     // otherwise exit the transfer.
   1228     //
   1229     if (Instance->CurRetry < Instance->MaxRetry) {
   1230       Mtftp6TransmitPacket (Instance, Instance->LastPacket);
   1231     } else {
   1232       Mtftp6OperationClean (Instance, EFI_TIMEOUT);
   1233       continue;
   1234     }
   1235   }
   1236 }
   1237