Home | History | Annotate | Download | only in Mtftp6Dxe
      1 /** @file
      2   Mtftp6 support functions implementation.
      3 
      4   Copyright (c) 2009 - 2015, 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 
    323       if  (Ip6Mode.IsConfigured) {
    324         //
    325         // Continue to configure the Udp6 instance.
    326         //
    327         Status = Udp6->Configure (Udp6, UdpCfgData);
    328       } else {
    329         Status = EFI_NO_MAPPING;
    330       }
    331     }
    332   }
    333 
    334 ON_EXIT:
    335 
    336   if (Event != NULL) {
    337     gBS->CloseEvent (Event);
    338   }
    339 
    340   return Status;
    341 }
    342 
    343 
    344 /**
    345   The dummy configure routine for create a new Udp6 Io.
    346 
    347   @param[in]  UdpIo                  The pointer to the Udp6 Io.
    348   @param[in]  Context                The pointer to the context.
    349 
    350   @retval EFI_SUCCESS                This value is always returned.
    351 
    352 **/
    353 EFI_STATUS
    354 EFIAPI
    355 Mtftp6ConfigDummyUdpIo (
    356   IN UDP_IO                 *UdpIo,
    357   IN VOID                   *Context
    358   )
    359 {
    360   return EFI_SUCCESS;
    361 }
    362 
    363 
    364 /**
    365   The configure routine for Mtftp6 instance to transmit/receive.
    366 
    367   @param[in]  UdpIo                  The pointer to the Udp6 Io.
    368   @param[in]  ServerIp               The pointer to the server address.
    369   @param[in]  ServerPort             The pointer to the server port.
    370   @param[in]  LocalIp                The pointer to the local address.
    371   @param[in]  LocalPort              The pointer to the local port.
    372 
    373   @retval EFI_SUCCESS            Configured the Udp6 Io for Mtftp6 successfully.
    374   @retval EFI_NO_MAPPING         The corresponding Ip6 instance has not been
    375                                  configured yet.
    376 
    377 **/
    378 EFI_STATUS
    379 Mtftp6ConfigUdpIo (
    380   IN UDP_IO                 *UdpIo,
    381   IN EFI_IPv6_ADDRESS       *ServerIp,
    382   IN UINT16                 ServerPort,
    383   IN EFI_IPv6_ADDRESS       *LocalIp,
    384   IN UINT16                 LocalPort
    385   )
    386 {
    387   EFI_STATUS                Status;
    388   EFI_UDP6_PROTOCOL         *Udp6;
    389   EFI_UDP6_CONFIG_DATA      *Udp6Cfg;
    390 
    391   Udp6    = UdpIo->Protocol.Udp6;
    392   Udp6Cfg = &(UdpIo->Config.Udp6);
    393 
    394   ZeroMem (Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));
    395 
    396   //
    397   // Set the Udp6 Io configure data.
    398   //
    399   Udp6Cfg->AcceptPromiscuous  = FALSE;
    400   Udp6Cfg->AcceptAnyPort      = FALSE;
    401   Udp6Cfg->AllowDuplicatePort = FALSE;
    402   Udp6Cfg->TrafficClass       = 0;
    403   Udp6Cfg->HopLimit           = 128;
    404   Udp6Cfg->ReceiveTimeout     = 0;
    405   Udp6Cfg->TransmitTimeout    = 0;
    406   Udp6Cfg->StationPort        = LocalPort;
    407   Udp6Cfg->RemotePort         = ServerPort;
    408 
    409   CopyMem (
    410     &Udp6Cfg->StationAddress,
    411     LocalIp,
    412     sizeof (EFI_IPv6_ADDRESS)
    413     );
    414 
    415   CopyMem (
    416     &Udp6Cfg->RemoteAddress,
    417     ServerIp,
    418     sizeof (EFI_IPv6_ADDRESS)
    419     );
    420 
    421   //
    422   // Configure the Udp6 instance with current configure data.
    423   //
    424   Status = Udp6->Configure (Udp6, Udp6Cfg);
    425 
    426   if (Status == EFI_NO_MAPPING) {
    427 
    428     return Mtftp6GetMapping (UdpIo, Udp6Cfg);
    429   }
    430 
    431   return Status;
    432 }
    433 
    434 
    435 /**
    436   Build and transmit the request packet for the Mtftp6 instance.
    437 
    438   @param[in]  Instance               The pointer to the Mtftp6 instance.
    439   @param[in]  Operation              The operation code of this packet.
    440 
    441   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory for the request.
    442   @retval EFI_SUCCESS            The request is built and sent.
    443   @retval Others                 Failed to transmit the packet.
    444 
    445 **/
    446 EFI_STATUS
    447 Mtftp6SendRequest (
    448   IN MTFTP6_INSTANCE        *Instance,
    449   IN UINT16                 Operation
    450   )
    451 {
    452   EFI_MTFTP6_PACKET         *Packet;
    453   EFI_MTFTP6_OPTION         *Options;
    454   EFI_MTFTP6_TOKEN          *Token;
    455   RETURN_STATUS             Status;
    456   NET_BUF                   *Nbuf;
    457   UINT8                     *Mode;
    458   UINT8                     *Cur;
    459   UINTN                     Index;
    460   UINT32                    BufferLength;
    461   UINTN                     FileNameLength;
    462   UINTN                     ModeLength;
    463   UINTN                     OptionStrLength;
    464   UINTN                     ValueStrLength;
    465 
    466   Token   = Instance->Token;
    467   Options = Token->OptionList;
    468   Mode    = Token->ModeStr;
    469 
    470   if (Mode == NULL) {
    471     Mode = (UINT8 *) "octet";
    472   }
    473 
    474   //
    475   // The header format of RRQ/WRQ packet is:
    476   //
    477   //   2 bytes     string    1 byte     string   1 byte
    478   //   ------------------------------------------------
    479   //  | Opcode |  Filename  |   0  |    Mode    |   0  |
    480   //   ------------------------------------------------
    481   //
    482   // The common option format is:
    483   //
    484   //    string     1 byte     string   1 byte
    485   //   ---------------------------------------
    486   //  | OptionStr |   0  |  ValueStr  |   0   |
    487   //   ---------------------------------------
    488   //
    489 
    490   //
    491   // Compute the size of new Mtftp6 packet.
    492   //
    493   FileNameLength = AsciiStrLen ((CHAR8 *) Token->Filename);
    494   ModeLength     = AsciiStrLen ((CHAR8 *) Mode);
    495   BufferLength   = (UINT32) FileNameLength + (UINT32) ModeLength + 4;
    496 
    497   for (Index = 0; Index < Token->OptionCount; Index++) {
    498     OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);
    499     ValueStrLength  = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);
    500     BufferLength   += (UINT32) OptionStrLength + (UINT32) ValueStrLength + 2;
    501   }
    502 
    503   //
    504   // Allocate a packet then copy the data.
    505   //
    506   if ((Nbuf = NetbufAlloc (BufferLength)) == NULL) {
    507     return EFI_OUT_OF_RESOURCES;
    508   }
    509 
    510   //
    511   // Copy the opcode, filename and mode into packet.
    512   //
    513   Packet         = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (Nbuf, BufferLength, FALSE);
    514   ASSERT (Packet != NULL);
    515 
    516   Packet->OpCode = HTONS (Operation);
    517   BufferLength  -= sizeof (Packet->OpCode);
    518 
    519   Cur            = Packet->Rrq.Filename;
    520   Status         = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Token->Filename);
    521   ASSERT_EFI_ERROR (Status);
    522   BufferLength  -= (UINT32) (FileNameLength + 1);
    523   Cur           += FileNameLength + 1;
    524   Status         = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Mode);
    525   ASSERT_EFI_ERROR (Status);
    526   BufferLength  -= (UINT32) (ModeLength + 1);
    527   Cur           += ModeLength + 1;
    528 
    529   //
    530   // Copy all the extension options into the packet.
    531   //
    532   for (Index = 0; Index < Token->OptionCount; ++Index) {
    533     OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);
    534     ValueStrLength  = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);
    535 
    536     Status          = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].OptionStr);
    537     ASSERT_EFI_ERROR (Status);
    538     BufferLength   -= (UINT32) (OptionStrLength + 1);
    539     Cur            += OptionStrLength + 1;
    540 
    541     Status          = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].ValueStr);
    542     ASSERT_EFI_ERROR (Status);
    543     BufferLength   -= (UINT32) (ValueStrLength + 1);
    544     Cur            += ValueStrLength + 1;
    545 
    546   }
    547 
    548   //
    549   // Save the packet buf for retransmit
    550   //
    551   if (Instance->LastPacket != NULL) {
    552     NetbufFree (Instance->LastPacket);
    553   }
    554 
    555   Instance->LastPacket = Nbuf;
    556   Instance->CurRetry   = 0;
    557 
    558   return Mtftp6TransmitPacket (Instance, Nbuf);
    559 }
    560 
    561 
    562 /**
    563   Build and send an error packet.
    564 
    565   @param[in]  Instance               The pointer to the Mtftp6 instance.
    566   @param[in]  ErrCode                The error code in the packet.
    567   @param[in]  ErrInfo                The error message in the packet.
    568 
    569   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory for the error packet.
    570   @retval EFI_SUCCESS            The error packet is transmitted.
    571   @retval Others                 Failed to transmit the packet.
    572 
    573 **/
    574 EFI_STATUS
    575 Mtftp6SendError (
    576   IN MTFTP6_INSTANCE        *Instance,
    577   IN UINT16                 ErrCode,
    578   IN UINT8*                 ErrInfo
    579   )
    580 {
    581   NET_BUF                   *Nbuf;
    582   EFI_MTFTP6_PACKET         *TftpError;
    583   UINT32                    Len;
    584 
    585   //
    586   // Allocate a packet then copy the data.
    587   //
    588   Len  = (UINT32) (AsciiStrLen ((CHAR8 *) ErrInfo) + sizeof (EFI_MTFTP6_ERROR_HEADER));
    589   Nbuf = NetbufAlloc (Len);
    590 
    591   if (Nbuf == NULL) {
    592     return EFI_OUT_OF_RESOURCES;
    593   }
    594 
    595   TftpError = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (Nbuf, Len, FALSE);
    596 
    597   if (TftpError == NULL) {
    598     NetbufFree (Nbuf);
    599     return EFI_OUT_OF_RESOURCES;
    600   }
    601 
    602   TftpError->OpCode          = HTONS (EFI_MTFTP6_OPCODE_ERROR);
    603   TftpError->Error.ErrorCode = HTONS (ErrCode);
    604 
    605   AsciiStrCpyS ((CHAR8 *) TftpError->Error.ErrorMessage, AsciiStrLen ((CHAR8 *) ErrInfo) + 1 , (CHAR8 *) ErrInfo);
    606 
    607   //
    608   // Save the packet buf for retransmit
    609   //
    610   if (Instance->LastPacket != NULL) {
    611     NetbufFree (Instance->LastPacket);
    612   }
    613 
    614   Instance->LastPacket = Nbuf;
    615   Instance->CurRetry   = 0;
    616 
    617   return Mtftp6TransmitPacket (Instance, Nbuf);
    618 }
    619 
    620 
    621 /**
    622   The callback function called when the packet is transmitted.
    623 
    624   @param[in]  Packet                 The pointer to the packet.
    625   @param[in]  UdpEpt                 The pointer to the Udp6 access point.
    626   @param[in]  IoStatus               The result of the transmission.
    627   @param[in]  Context                The pointer to the context.
    628 
    629 **/
    630 VOID
    631 EFIAPI
    632 Mtftp6OnPacketSent (
    633   IN NET_BUF                   *Packet,
    634   IN UDP_END_POINT             *UdpEpt,
    635   IN EFI_STATUS                IoStatus,
    636   IN VOID                      *Context
    637   )
    638 {
    639   NetbufFree (Packet);
    640   *(BOOLEAN *) Context = TRUE;
    641 }
    642 
    643 
    644 /**
    645   Send the packet for the Mtftp6 instance.
    646 
    647   @param[in]  Instance               The pointer to the Mtftp6 instance.
    648   @param[in]  Packet                 The pointer to the packet to be sent.
    649 
    650   @retval EFI_SUCCESS            The packet was sent out
    651   @retval Others                 Failed to transmit the packet.
    652 
    653 **/
    654 EFI_STATUS
    655 Mtftp6TransmitPacket (
    656   IN MTFTP6_INSTANCE        *Instance,
    657   IN NET_BUF                *Packet
    658   )
    659 {
    660   EFI_UDP6_PROTOCOL         *Udp6;
    661   EFI_UDP6_CONFIG_DATA      Udp6CfgData;
    662   EFI_STATUS                Status;
    663   UINT16                    *Temp;
    664   UINT16                    Value;
    665   UINT16                    OpCode;
    666 
    667   ZeroMem (&Udp6CfgData, sizeof(EFI_UDP6_CONFIG_DATA));
    668   Udp6 = Instance->UdpIo->Protocol.Udp6;
    669 
    670   //
    671   // Set the live time of the packet.
    672   //
    673   Instance->PacketToLive = Instance->IsMaster ? Instance->Timeout : (Instance->Timeout * 2);
    674 
    675   Temp   = (UINT16 *) NetbufGetByte (Packet, 0, NULL);
    676   ASSERT (Temp != NULL);
    677 
    678   Value  = *Temp;
    679   OpCode = NTOHS (Value);
    680 
    681   if (OpCode == EFI_MTFTP6_OPCODE_RRQ || OpCode == EFI_MTFTP6_OPCODE_DIR || OpCode == EFI_MTFTP6_OPCODE_WRQ) {
    682     //
    683     // For the Rrq, Dir, Wrq requests of the operation, configure the Udp6Io as
    684     // (serverip, 69, localip, localport) to send.
    685     // Usually local address and local port are both default as zero.
    686     //
    687     Status = Udp6->Configure (Udp6, NULL);
    688 
    689     if (EFI_ERROR (Status)) {
    690       return Status;
    691     }
    692 
    693     Status = Mtftp6ConfigUdpIo (
    694                Instance->UdpIo,
    695                &Instance->ServerIp,
    696                Instance->ServerCmdPort,
    697                &Instance->Config->StationIp,
    698                Instance->Config->LocalPort
    699                );
    700 
    701     if (EFI_ERROR (Status)) {
    702       return Status;
    703     }
    704 
    705     //
    706     // Get the current local address and port by get Udp6 mode data.
    707     //
    708     Status = Udp6->GetModeData (Udp6, &Udp6CfgData, NULL, NULL, NULL);
    709     if (EFI_ERROR (Status)) {
    710       return Status;
    711     }
    712 
    713     NET_GET_REF (Packet);
    714 
    715     Instance->IsTransmitted = FALSE;
    716 
    717     Status = UdpIoSendDatagram (
    718                Instance->UdpIo,
    719                Packet,
    720                NULL,
    721                NULL,
    722                Mtftp6OnPacketSent,
    723                &Instance->IsTransmitted
    724                );
    725 
    726     if (EFI_ERROR (Status)) {
    727       NET_PUT_REF (Packet);
    728       return Status;
    729     }
    730 
    731     //
    732     // Poll till the packet sent out from the ip6 queue.
    733     //
    734     gBS->RestoreTPL (Instance->OldTpl);
    735 
    736     while (!Instance->IsTransmitted) {
    737       Udp6->Poll (Udp6);
    738     }
    739 
    740     Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    741 
    742     //
    743     // For the subsequent exchange of such requests, reconfigure the Udp6Io as
    744     // (serverip, 0, localip, localport) to receive.
    745     // Currently local address and local port are specified by Udp6 mode data.
    746     //
    747     Status = Udp6->Configure (Udp6, NULL);
    748 
    749     if (EFI_ERROR (Status)) {
    750       return Status;
    751     }
    752 
    753     Status = Mtftp6ConfigUdpIo (
    754                Instance->UdpIo,
    755                &Instance->ServerIp,
    756                Instance->ServerDataPort,
    757                &Udp6CfgData.StationAddress,
    758                Udp6CfgData.StationPort
    759                );
    760   } else {
    761     //
    762     // For the data exchange, configure the Udp6Io as (serverip, dataport,
    763     // localip, localport) to send/receive.
    764     // Currently local address and local port are specified by Udp6 mode data.
    765     //
    766     Status = Udp6->GetModeData (Udp6, &Udp6CfgData, NULL, NULL, NULL);
    767     if (EFI_ERROR (Status)) {
    768       return Status;
    769     }
    770 
    771     if (Udp6CfgData.RemotePort != Instance->ServerDataPort) {
    772 
    773       Status = Udp6->Configure (Udp6, NULL);
    774 
    775       if (EFI_ERROR (Status)) {
    776         return Status;
    777       }
    778 
    779       Status = Mtftp6ConfigUdpIo (
    780                  Instance->UdpIo,
    781                  &Instance->ServerIp,
    782                  Instance->ServerDataPort,
    783                  &Udp6CfgData.StationAddress,
    784                  Udp6CfgData.StationPort
    785                  );
    786 
    787       if (EFI_ERROR (Status)) {
    788         return Status;
    789       }
    790     }
    791 
    792     NET_GET_REF (Packet);
    793 
    794     Instance->IsTransmitted = FALSE;
    795 
    796     Status = UdpIoSendDatagram (
    797                Instance->UdpIo,
    798                Packet,
    799                NULL,
    800                NULL,
    801                Mtftp6OnPacketSent,
    802                &Instance->IsTransmitted
    803                );
    804 
    805     if (EFI_ERROR (Status)) {
    806       NET_PUT_REF (Packet);
    807     }
    808 
    809     //
    810     // Poll till the packet sent out from the ip6 queue.
    811     //
    812     gBS->RestoreTPL (Instance->OldTpl);
    813 
    814     while (!Instance->IsTransmitted) {
    815       Udp6->Poll (Udp6);
    816     }
    817 
    818     Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    819   }
    820 
    821   return Status;
    822 }
    823 
    824 
    825 /**
    826   Check packet for GetInfo callback routine.
    827 
    828   GetInfo is implemented with EfiMtftp6ReadFile. It's used to inspect
    829   the first packet from server, then abort the session.
    830 
    831   @param[in]  This                   The pointer to the Mtftp6 protocol.
    832   @param[in]  Token                  The pointer to the Mtftp6 token.
    833   @param[in]  PacketLen              The length of the packet.
    834   @param[in]  Packet                 The pointer to the received packet.
    835 
    836   @retval EFI_ABORTED            Abort the Mtftp6 operation.
    837 
    838 **/
    839 EFI_STATUS
    840 EFIAPI
    841 Mtftp6CheckPacket (
    842   IN EFI_MTFTP6_PROTOCOL    *This,
    843   IN EFI_MTFTP6_TOKEN       *Token,
    844   IN UINT16                 PacketLen,
    845   IN EFI_MTFTP6_PACKET      *Packet
    846   )
    847 {
    848   MTFTP6_GETINFO_CONTEXT    *Context;
    849   UINT16                    OpCode;
    850 
    851   Context = (MTFTP6_GETINFO_CONTEXT *) Token->Context;
    852   OpCode  = NTOHS (Packet->OpCode);
    853 
    854   //
    855   // Set the GetInfo's return status according to the OpCode.
    856   //
    857   switch (OpCode) {
    858   case EFI_MTFTP6_OPCODE_ERROR:
    859     Context->Status = EFI_TFTP_ERROR;
    860     break;
    861 
    862   case EFI_MTFTP6_OPCODE_OACK:
    863     Context->Status = EFI_SUCCESS;
    864     break;
    865 
    866   default:
    867     Context->Status = EFI_PROTOCOL_ERROR;
    868   }
    869 
    870   //
    871   // Allocate buffer then copy the packet over. Use gBS->AllocatePool
    872   // in case NetAllocatePool will implements something tricky.
    873   //
    874   *(Context->Packet) = AllocateZeroPool (PacketLen);
    875 
    876   if (*(Context->Packet) == NULL) {
    877     Context->Status = EFI_OUT_OF_RESOURCES;
    878     return EFI_ABORTED;
    879   }
    880 
    881   *(Context->PacketLen) = PacketLen;
    882   CopyMem (*(Context->Packet), Packet, PacketLen);
    883 
    884   return EFI_ABORTED;
    885 }
    886 
    887 
    888 /**
    889   Clean up the current Mtftp6 operation.
    890 
    891   @param[in]  Instance               The pointer to the Mtftp6 instance.
    892   @param[in]  Result                 The result to be returned to the user.
    893 
    894 **/
    895 VOID
    896 Mtftp6OperationClean (
    897   IN MTFTP6_INSTANCE        *Instance,
    898   IN EFI_STATUS             Result
    899   )
    900 {
    901   LIST_ENTRY                *Entry;
    902   LIST_ENTRY                *Next;
    903   MTFTP6_BLOCK_RANGE        *Block;
    904 
    905   //
    906   // Clean up the current token and event.
    907   //
    908   if (Instance->Token != NULL) {
    909     Instance->Token->Status = Result;
    910     if (Instance->Token->Event != NULL) {
    911       gBS->SignalEvent (Instance->Token->Event);
    912     }
    913     Instance->Token = NULL;
    914   }
    915 
    916   //
    917   // Clean up the corresponding Udp6Io.
    918   //
    919   if (Instance->UdpIo != NULL) {
    920     UdpIoCleanIo (Instance->UdpIo);
    921   }
    922 
    923   if (Instance->McastUdpIo != NULL) {
    924     gBS->CloseProtocol (
    925            Instance->McastUdpIo->UdpHandle,
    926            &gEfiUdp6ProtocolGuid,
    927            Instance->McastUdpIo->Image,
    928            Instance->Handle
    929            );
    930     UdpIoFreeIo (Instance->McastUdpIo);
    931     Instance->McastUdpIo = NULL;
    932   }
    933 
    934   //
    935   // Clean up the stored last packet.
    936   //
    937   if (Instance->LastPacket != NULL) {
    938     NetbufFree (Instance->LastPacket);
    939     Instance->LastPacket = NULL;
    940   }
    941 
    942   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Instance->BlkList) {
    943     Block = NET_LIST_USER_STRUCT (Entry, MTFTP6_BLOCK_RANGE, Link);
    944     RemoveEntryList (Entry);
    945     FreePool (Block);
    946   }
    947 
    948   //
    949   // Reinitialize the corresponding fields of the Mtftp6 operation.
    950   //
    951   ZeroMem (&Instance->ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
    952   ZeroMem (&Instance->ServerIp, sizeof (EFI_IPv6_ADDRESS));
    953   ZeroMem (&Instance->McastIp, sizeof (EFI_IPv6_ADDRESS));
    954 
    955   Instance->ServerCmdPort  = 0;
    956   Instance->ServerDataPort = 0;
    957   Instance->McastPort      = 0;
    958   Instance->BlkSize        = 0;
    959   Instance->LastBlk        = 0;
    960   Instance->PacketToLive   = 0;
    961   Instance->MaxRetry       = 0;
    962   Instance->CurRetry       = 0;
    963   Instance->Timeout        = 0;
    964   Instance->IsMaster       = TRUE;
    965 }
    966 
    967 
    968 /**
    969   Start the Mtftp6 instance to perform the operation, such as read file,
    970   write file, and read directory.
    971 
    972   @param[in]  This                   The MTFTP session.
    973   @param[in]  Token                  The token than encapsues the user's request.
    974   @param[in]  OpCode                 The operation to perform.
    975 
    976   @retval EFI_INVALID_PARAMETER  Some of the parameters are invalid.
    977   @retval EFI_NOT_STARTED        The MTFTP session hasn't been configured.
    978   @retval EFI_ALREADY_STARTED    There is pending operation for the session.
    979   @retval EFI_SUCCESS            The operation is successfully started.
    980 
    981 **/
    982 EFI_STATUS
    983 Mtftp6OperationStart (
    984   IN EFI_MTFTP6_PROTOCOL    *This,
    985   IN EFI_MTFTP6_TOKEN       *Token,
    986   IN UINT16                 OpCode
    987   )
    988 {
    989   MTFTP6_INSTANCE           *Instance;
    990   EFI_STATUS                Status;
    991 
    992   if (This == NULL ||
    993       Token == NULL ||
    994       Token->Filename == NULL ||
    995       (Token->OptionCount != 0 && Token->OptionList == NULL) ||
    996       (Token->OverrideData != NULL && !NetIp6IsValidUnicast (&Token->OverrideData->ServerIp))
    997       ) {
    998     return EFI_INVALID_PARAMETER;
    999   }
   1000 
   1001   //
   1002   // At least define one method to collect the data for download.
   1003   //
   1004   if ((OpCode == EFI_MTFTP6_OPCODE_RRQ || OpCode == EFI_MTFTP6_OPCODE_DIR) &&
   1005       Token->Buffer == NULL &&
   1006       Token->CheckPacket == NULL
   1007       ) {
   1008     return EFI_INVALID_PARAMETER;
   1009   }
   1010 
   1011   //
   1012   // At least define one method to provide the data for upload.
   1013   //
   1014   if (OpCode == EFI_MTFTP6_OPCODE_WRQ && Token->Buffer == NULL && Token->PacketNeeded == NULL) {
   1015     return EFI_INVALID_PARAMETER;
   1016   }
   1017 
   1018   Instance = MTFTP6_INSTANCE_FROM_THIS (This);
   1019 
   1020   if (Instance->Config == NULL) {
   1021     return EFI_NOT_STARTED;
   1022   }
   1023 
   1024   if (Instance->Token != NULL) {
   1025     return EFI_ACCESS_DENIED;
   1026   }
   1027 
   1028   Status           = EFI_SUCCESS;
   1029   Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1030 
   1031   //
   1032   // Parse the extension options in the request packet.
   1033   //
   1034   if (Token->OptionCount != 0) {
   1035 
   1036     Status = Mtftp6ParseExtensionOption (
   1037                Token->OptionList,
   1038                Token->OptionCount,
   1039                TRUE,
   1040                &Instance->ExtInfo
   1041                );
   1042 
   1043     if (EFI_ERROR (Status)) {
   1044       goto ON_ERROR;
   1045     }
   1046   }
   1047 
   1048   //
   1049   // Initialize runtime data from config data or override data.
   1050   //
   1051   Instance->Token           = Token;
   1052   Instance->ServerCmdPort   = Instance->Config->InitialServerPort;
   1053   Instance->ServerDataPort  = 0;
   1054   Instance->MaxRetry        = Instance->Config->TryCount;
   1055   Instance->Timeout         = Instance->Config->TimeoutValue;
   1056   Instance->IsMaster        = TRUE;
   1057 
   1058   CopyMem (
   1059     &Instance->ServerIp,
   1060     &Instance->Config->ServerIp,
   1061     sizeof (EFI_IPv6_ADDRESS)
   1062     );
   1063 
   1064   if (Token->OverrideData != NULL) {
   1065     Instance->ServerCmdPort = Token->OverrideData->ServerPort;
   1066     Instance->MaxRetry      = Token->OverrideData->TryCount;
   1067     Instance->Timeout       = Token->OverrideData->TimeoutValue;
   1068 
   1069     CopyMem (
   1070       &Instance->ServerIp,
   1071       &Token->OverrideData->ServerIp,
   1072       sizeof (EFI_IPv6_ADDRESS)
   1073       );
   1074   }
   1075 
   1076   //
   1077   // Set default value for undefined parameters.
   1078   //
   1079   if (Instance->ServerCmdPort == 0) {
   1080     Instance->ServerCmdPort = MTFTP6_DEFAULT_SERVER_CMD_PORT;
   1081   }
   1082   if (Instance->BlkSize == 0) {
   1083     Instance->BlkSize = MTFTP6_DEFAULT_BLK_SIZE;
   1084   }
   1085   if (Instance->MaxRetry == 0) {
   1086     Instance->MaxRetry = MTFTP6_DEFAULT_MAX_RETRY;
   1087   }
   1088   if (Instance->Timeout == 0) {
   1089     Instance->Timeout = MTFTP6_DEFAULT_TIMEOUT;
   1090   }
   1091 
   1092   Token->Status = EFI_NOT_READY;
   1093 
   1094   //
   1095   // Switch the routines by the operation code.
   1096   //
   1097   switch (OpCode) {
   1098   case EFI_MTFTP6_OPCODE_RRQ:
   1099     Status = Mtftp6RrqStart (Instance, OpCode);
   1100     break;
   1101 
   1102   case EFI_MTFTP6_OPCODE_DIR:
   1103     Status = Mtftp6RrqStart (Instance, OpCode);
   1104     break;
   1105 
   1106   case EFI_MTFTP6_OPCODE_WRQ:
   1107     Status = Mtftp6WrqStart (Instance, OpCode);
   1108     break;
   1109 
   1110   default:
   1111     Status = EFI_DEVICE_ERROR;
   1112     goto ON_ERROR;
   1113   }
   1114 
   1115   if (EFI_ERROR (Status)) {
   1116     goto ON_ERROR;
   1117   }
   1118 
   1119   //
   1120   // Return immediately for asynchronous or poll the instance for synchronous.
   1121   //
   1122   gBS->RestoreTPL (Instance->OldTpl);
   1123 
   1124   if (Token->Event == NULL) {
   1125     while (Token->Status == EFI_NOT_READY) {
   1126       This->Poll (This);
   1127     }
   1128     return Token->Status;
   1129   }
   1130 
   1131   return EFI_SUCCESS;
   1132 
   1133 ON_ERROR:
   1134 
   1135   Mtftp6OperationClean (Instance, Status);
   1136   gBS->RestoreTPL (Instance->OldTpl);
   1137 
   1138   return Status;
   1139 }
   1140 
   1141 
   1142 /**
   1143   The timer ticking routine for the Mtftp6 instance.
   1144 
   1145   @param[in]  Event                  The pointer to the ticking event.
   1146   @param[in]  Context                The pointer to the context.
   1147 
   1148 **/
   1149 VOID
   1150 EFIAPI
   1151 Mtftp6OnTimerTick (
   1152   IN EFI_EVENT              Event,
   1153   IN VOID                   *Context
   1154   )
   1155 {
   1156   MTFTP6_SERVICE            *Service;
   1157   MTFTP6_INSTANCE           *Instance;
   1158   LIST_ENTRY                *Entry;
   1159   LIST_ENTRY                *Next;
   1160   EFI_MTFTP6_TOKEN          *Token;
   1161   EFI_STATUS                Status;
   1162 
   1163   Service = (MTFTP6_SERVICE *) Context;
   1164 
   1165   //
   1166   // Iterate through all the children of the Mtftp service instance. Time
   1167   // out the packet. If maximum retries reached, clean the session up.
   1168   //
   1169   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Children) {
   1170 
   1171     Instance = NET_LIST_USER_STRUCT (Entry, MTFTP6_INSTANCE, Link);
   1172 
   1173     if (Instance->Token == NULL) {
   1174       continue;
   1175     }
   1176 
   1177     if (Instance->PacketToLive > 0) {
   1178       Instance->PacketToLive--;
   1179       continue;
   1180     }
   1181 
   1182     Instance->CurRetry++;
   1183     Token = Instance->Token;
   1184 
   1185     if (Token->TimeoutCallback != NULL) {
   1186       //
   1187       // Call the timeout callback routine if has.
   1188       //
   1189       Status = Token->TimeoutCallback (&Instance->Mtftp6, Token);
   1190 
   1191       if (EFI_ERROR (Status)) {
   1192         Mtftp6SendError (
   1193            Instance,
   1194            EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
   1195            (UINT8 *) "User aborted the transfer in time out"
   1196            );
   1197         Mtftp6OperationClean (Instance, EFI_ABORTED);
   1198         continue;
   1199       }
   1200     }
   1201 
   1202     //
   1203     // Retransmit the packet if haven't reach the maxmium retry count,
   1204     // otherwise exit the transfer.
   1205     //
   1206     if (Instance->CurRetry < Instance->MaxRetry) {
   1207       Mtftp6TransmitPacket (Instance, Instance->LastPacket);
   1208     } else {
   1209       Mtftp6OperationClean (Instance, EFI_TIMEOUT);
   1210       continue;
   1211     }
   1212   }
   1213 }
   1214