Home | History | Annotate | Download | only in Mtftp6Dxe
      1 /** @file
      2   Mtftp6 Rrq process functions implementation.
      3 
      4   Copyright (c) 2009 - 2014, 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   Build and send a ACK packet for download.
     21 
     22   @param[in]  Instance              The pointer to the Mtftp6 instance.
     23   @param[in]  BlockNum              The block number to be acked.
     24 
     25   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for the packet.
     26   @retval EFI_SUCCESS           The ACK has been sent.
     27   @retval Others                Failed to send the ACK.
     28 
     29 **/
     30 EFI_STATUS
     31 Mtftp6RrqSendAck (
     32   IN MTFTP6_INSTANCE        *Instance,
     33   IN UINT16                 BlockNum
     34   )
     35 {
     36   EFI_MTFTP6_PACKET         *Ack;
     37   NET_BUF                   *Packet;
     38 
     39   //
     40   // Allocate net buffer to create ack packet.
     41   //
     42   Packet = NetbufAlloc (sizeof (EFI_MTFTP6_ACK_HEADER));
     43 
     44   if (Packet == NULL) {
     45     return EFI_OUT_OF_RESOURCES;
     46   }
     47 
     48   Ack = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (
     49                                 Packet,
     50                                 sizeof (EFI_MTFTP6_ACK_HEADER),
     51                                 FALSE
     52                                 );
     53   ASSERT (Ack != NULL);
     54 
     55   Ack->Ack.OpCode    = HTONS (EFI_MTFTP6_OPCODE_ACK);
     56   Ack->Ack.Block[0]  = HTONS (BlockNum);
     57 
     58   //
     59   // Reset current retry count of the instance.
     60   //
     61   Instance->CurRetry = 0;
     62   Instance->LastPacket = Packet;
     63 
     64   return Mtftp6TransmitPacket (Instance, Packet);
     65 }
     66 
     67 
     68 /**
     69   Deliver the received data block to the user, which can be saved
     70   in the user provide buffer or through the CheckPacket callback.
     71 
     72   @param[in]  Instance              The pointer to the Mtftp6 instance.
     73   @param[in]  Packet                The pointer to the received packet.
     74   @param[in]  Len                   The packet length.
     75   @param[out] UdpPacket             The net buf of the received packet.
     76 
     77   @retval EFI_SUCCESS           The data was saved successfully.
     78   @retval EFI_ABORTED           The user tells to abort by return an error through
     79                                 CheckPacket.
     80   @retval EFI_BUFFER_TOO_SMALL  The user's buffer is too small, and buffer length is
     81                                 updated to the actual buffer size needed.
     82 
     83 **/
     84 EFI_STATUS
     85 Mtftp6RrqSaveBlock (
     86   IN  MTFTP6_INSTANCE       *Instance,
     87   IN  EFI_MTFTP6_PACKET     *Packet,
     88   IN  UINT32                Len,
     89   OUT NET_BUF               **UdpPacket
     90   )
     91 {
     92   EFI_MTFTP6_TOKEN          *Token;
     93   EFI_STATUS                Status;
     94   UINT16                    Block;
     95   UINT64                    Start;
     96   UINT32                    DataLen;
     97   UINT64                    TotalBlock;
     98   BOOLEAN                   Completed;
     99 
    100   Completed = FALSE;
    101   Token     = Instance->Token;
    102   Block     = NTOHS (Packet->Data.Block);
    103   DataLen   = Len - MTFTP6_DATA_HEAD_LEN;
    104 
    105   //
    106   // This is the last block, save the block num
    107   //
    108   if (DataLen < Instance->BlkSize) {
    109     Completed = TRUE;
    110     Instance->LastBlk = Block;
    111     Mtftp6SetLastBlockNum (&Instance->BlkList, Block);
    112   }
    113 
    114   //
    115   // Remove this block number from the file hole. If Mtftp6RemoveBlockNum
    116   // returns EFI_NOT_FOUND, the block has been saved, don't save it again.
    117   // Note that : For bigger files, allowing the block counter to roll over
    118   // to accept transfers of unlimited size. So TotalBlock is memorised as
    119   // continuous block counter.
    120   //
    121   Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, &TotalBlock);
    122 
    123   if (Status == EFI_NOT_FOUND) {
    124     return EFI_SUCCESS;
    125   } else if (EFI_ERROR (Status)) {
    126     return Status;
    127   }
    128 
    129   if (Token->CheckPacket != NULL) {
    130     //
    131     // Callback to the check packet routine with the received packet.
    132     //
    133     Status = Token->CheckPacket (&Instance->Mtftp6, Token, (UINT16) Len, Packet);
    134 
    135     if (EFI_ERROR (Status)) {
    136       //
    137       // Free the received packet before send new packet in ReceiveNotify,
    138       // since the Udp6Io might need to be reconfigured.
    139       //
    140       NetbufFree (*UdpPacket);
    141       *UdpPacket = NULL;
    142       //
    143       // Send the Mtftp6 error message if user aborted the current session.
    144       //
    145       Mtftp6SendError (
    146         Instance,
    147         EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
    148         (UINT8 *) "User aborted download"
    149         );
    150 
    151       return EFI_ABORTED;
    152     }
    153   }
    154 
    155   if (Token->Buffer != NULL) {
    156 
    157     Start = MultU64x32 (TotalBlock - 1, Instance->BlkSize);
    158     if (Start + DataLen <= Token->BufferSize) {
    159       CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);
    160       //
    161       // Update the file size when received the last block
    162       //
    163       if ((Instance->LastBlk == Block) && Completed) {
    164         Token->BufferSize = Start + DataLen;
    165       }
    166     } else if (Instance->LastBlk != 0) {
    167       //
    168       // Don't save the data if the buffer is too small, return
    169       // EFI_BUFFER_TOO_SMALL if received the last packet. This
    170       // will give a accurate file length.
    171       //
    172       Token->BufferSize = Start + DataLen;
    173 
    174       //
    175       // Free the received packet before send new packet in ReceiveNotify,
    176       // since the udpio might need to be reconfigured.
    177       //
    178       NetbufFree (*UdpPacket);
    179       *UdpPacket = NULL;
    180       //
    181       // Send the Mtftp6 error message if no enough buffer.
    182       //
    183       Mtftp6SendError (
    184         Instance,
    185         EFI_MTFTP6_ERRORCODE_DISK_FULL,
    186         (UINT8 *) "User provided memory block is too small"
    187         );
    188 
    189       return EFI_BUFFER_TOO_SMALL;
    190     }
    191   }
    192 
    193   return EFI_SUCCESS;
    194 }
    195 
    196 
    197 /**
    198   Process the received data packets. It will save the block
    199   then send back an ACK if it is active.
    200 
    201   @param[in]  Instance              The pointer to the Mtftp6 instance.
    202   @param[in]  Packet                The pointer to the received packet.
    203   @param[in]  Len                   The length of the packet.
    204   @param[out] UdpPacket             The net buf of received packet.
    205   @param[out] IsCompleted           If TRUE, the download has been completed.
    206                                     Otherwise, the download has not been completed.
    207 
    208   @retval EFI_SUCCESS           The data packet was successfully processed.
    209   @retval EFI_ABORTED           The download was aborted by the user.
    210   @retval EFI_BUFFER_TOO_SMALL  The user-provided buffer is too small.
    211 
    212 **/
    213 EFI_STATUS
    214 Mtftp6RrqHandleData (
    215   IN  MTFTP6_INSTANCE       *Instance,
    216   IN  EFI_MTFTP6_PACKET     *Packet,
    217   IN  UINT32                Len,
    218   OUT NET_BUF               **UdpPacket,
    219   OUT BOOLEAN               *IsCompleted
    220   )
    221 {
    222   EFI_STATUS                Status;
    223   UINT16                    BlockNum;
    224   INTN                      Expected;
    225 
    226   *IsCompleted = FALSE;
    227   BlockNum     = NTOHS (Packet->Data.Block);
    228   Expected     = Mtftp6GetNextBlockNum (&Instance->BlkList);
    229 
    230   ASSERT (Expected >= 0);
    231 
    232   //
    233   // If we are active and received an unexpected packet, retransmit
    234   // the last ACK then restart receiving. If we are passive, save
    235   // the block.
    236   //
    237   if (Instance->IsMaster && (Expected != BlockNum)) {
    238     //
    239     // Free the received packet before send new packet in ReceiveNotify,
    240     // since the udpio might need to be reconfigured.
    241     //
    242     NetbufFree (*UdpPacket);
    243     *UdpPacket = NULL;
    244 
    245     Mtftp6TransmitPacket (Instance, Instance->LastPacket);
    246     return EFI_SUCCESS;
    247   }
    248 
    249   Status = Mtftp6RrqSaveBlock (Instance, Packet, Len, UdpPacket);
    250 
    251   if (EFI_ERROR (Status)) {
    252     return Status;
    253   }
    254 
    255   //
    256   // Reset the passive client's timer whenever it received a valid data packet.
    257   //
    258   if (!Instance->IsMaster) {
    259     Instance->PacketToLive = Instance->Timeout * 2;
    260   }
    261 
    262   //
    263   // Check whether we have received all the blocks. Send the ACK if we
    264   // are active (unicast client or master client for multicast download).
    265   // If we have received all the blocks, send an ACK even if we are passive
    266   // to tell the server that we are done.
    267   //
    268   Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
    269 
    270   if (Instance->IsMaster || Expected < 0) {
    271     if (Expected < 0) {
    272       //
    273       // If we are passive client, then the just received Block maybe
    274       // isn't the last block. We need to send an ACK to the last block
    275       // to inform the server that we are done. If we are active client,
    276       // the Block == Instance->LastBlock.
    277       //
    278       BlockNum     = Instance->LastBlk;
    279       *IsCompleted = TRUE;
    280 
    281     } else {
    282       BlockNum     = (UINT16) (Expected - 1);
    283     }
    284     //
    285     // Free the received packet before send new packet in ReceiveNotify,
    286     // since the udpio might need to be reconfigured.
    287     //
    288     NetbufFree (*UdpPacket);
    289     *UdpPacket = NULL;
    290 
    291     Mtftp6RrqSendAck (Instance, BlockNum);
    292   }
    293 
    294   return EFI_SUCCESS;
    295 }
    296 
    297 
    298 /**
    299   Validate whether the options received in the server's OACK packet is valid.
    300   The options are valid only if:
    301   1. The server doesn't include options not requested by us.
    302   2. The server can only use smaller blksize than that is requested.
    303   3. The server can only use the same timeout as requested.
    304   4. The server doesn't change its multicast channel.
    305 
    306   @param[in]  Instance              The pointer to the Mtftp6 instance.
    307   @param[in]  ReplyInfo             The pointer to options information in reply packet.
    308   @param[in]  RequestInfo           The pointer to requested options info.
    309 
    310   @retval     TRUE                  If the option in the OACK is valid.
    311   @retval     FALSE                 If the option is invalid.
    312 
    313 **/
    314 BOOLEAN
    315 Mtftp6RrqOackValid (
    316   IN MTFTP6_INSTANCE           *Instance,
    317   IN MTFTP6_EXT_OPTION_INFO    *ReplyInfo,
    318   IN MTFTP6_EXT_OPTION_INFO    *RequestInfo
    319   )
    320 {
    321   //
    322   // It is invalid for server to return options we don't request
    323   //
    324   if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {
    325     return FALSE;
    326   }
    327 
    328   //
    329   // Server can only specify a smaller block size to be used and
    330   // return the timeout matches that requested.
    331   //
    332   if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
    333       (((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))
    334       ) {
    335     return FALSE;
    336   }
    337 
    338   //
    339   // The server can send ",,master" to client to change its master
    340   // setting. But if it use the specific multicast channel, it can't
    341   // change the setting.
    342   //
    343   if (((ReplyInfo->BitMap & MTFTP6_OPT_MCAST_BIT) != 0) && !NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {
    344 
    345     if (!NetIp6IsUnspecifiedAddr (&ReplyInfo->McastIp) && CompareMem (
    346                                                             &ReplyInfo->McastIp,
    347                                                             &Instance->McastIp,
    348                                                             sizeof (EFI_IPv6_ADDRESS)
    349                                                             ) != 0) {
    350       return FALSE;
    351     }
    352 
    353     if ((ReplyInfo->McastPort != 0) && (ReplyInfo->McastPort != Instance->McastPort)) {
    354       return FALSE;
    355     }
    356   }
    357 
    358   return TRUE;
    359 }
    360 
    361 
    362 /**
    363   Configure Udp6Io to receive a packet from a multicast address.
    364 
    365   @param[in]  McastIo               The pointer to the mcast Udp6Io.
    366   @param[in]  Context               The pointer to the context.
    367 
    368   @retval EFI_SUCCESS           The mcast Udp6Io was successfully configured.
    369   @retval Others                Failed to configure the Udp6Io.
    370 
    371 **/
    372 EFI_STATUS
    373 EFIAPI
    374 Mtftp6RrqConfigMcastUdpIo (
    375   IN UDP_IO                 *McastIo,
    376   IN VOID                   *Context
    377   )
    378 {
    379   EFI_STATUS                Status;
    380   EFI_UDP6_PROTOCOL         *Udp6;
    381   EFI_UDP6_CONFIG_DATA      *Udp6Cfg;
    382   EFI_IPv6_ADDRESS          Group;
    383   MTFTP6_INSTANCE           *Instance;
    384 
    385   Udp6     = McastIo->Protocol.Udp6;
    386   Udp6Cfg  = &(McastIo->Config.Udp6);
    387   Instance = (MTFTP6_INSTANCE *) Context;
    388 
    389   //
    390   // Set the configure data for the mcast Udp6Io.
    391   //
    392   ZeroMem (Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));
    393 
    394   Udp6Cfg->AcceptPromiscuous  = FALSE;
    395   Udp6Cfg->AcceptAnyPort      = FALSE;
    396   Udp6Cfg->AllowDuplicatePort = FALSE;
    397   Udp6Cfg->TrafficClass       = 0;
    398   Udp6Cfg->HopLimit           = 128;
    399   Udp6Cfg->ReceiveTimeout     = 0;
    400   Udp6Cfg->TransmitTimeout    = 0;
    401   Udp6Cfg->StationPort        = Instance->McastPort;
    402   Udp6Cfg->RemotePort         = 0;
    403 
    404   CopyMem (
    405     &Udp6Cfg->RemoteAddress,
    406     &Instance->ServerIp,
    407     sizeof (EFI_IPv6_ADDRESS)
    408     );
    409 
    410   //
    411   // Configure the mcast Udp6Io.
    412   //
    413   Status = Udp6->Configure (Udp6, Udp6Cfg);
    414 
    415   if (EFI_ERROR (Status)) {
    416     return Status;
    417   }
    418 
    419   //
    420   // Join the multicast group
    421   //
    422   CopyMem (&Group, &Instance->McastIp, sizeof (EFI_IPv6_ADDRESS));
    423 
    424   return Udp6->Groups (Udp6, TRUE, &Group);
    425 }
    426 
    427 
    428 /**
    429   Process the OACK packet for Rrq.
    430 
    431   @param[in]  Instance              The pointer to the Mtftp6 instance.
    432   @param[in]  Packet                The pointer to the received packet.
    433   @param[in]  Len                   The length of the packet.
    434   @param[out] UdpPacket             The net buf of received packet.
    435   @param[out] IsCompleted           If TRUE, the download has been completed.
    436                                     Otherwise, the download has not been completed.
    437 
    438   @retval EFI_DEVICE_ERROR      Failed to create/start a multicast Udp6 child.
    439   @retval EFI_TFTP_ERROR        An error happened during the process.
    440   @retval EFI_SUCCESS           The OACK packet successfully processed.
    441 
    442 **/
    443 EFI_STATUS
    444 Mtftp6RrqHandleOack (
    445   IN  MTFTP6_INSTANCE       *Instance,
    446   IN  EFI_MTFTP6_PACKET     *Packet,
    447   IN  UINT32                Len,
    448   OUT NET_BUF               **UdpPacket,
    449   OUT BOOLEAN               *IsCompleted
    450   )
    451 {
    452   EFI_MTFTP6_OPTION         *Options;
    453   UINT32                    Count;
    454   MTFTP6_EXT_OPTION_INFO    ExtInfo;
    455   EFI_STATUS                Status;
    456   INTN                      Expected;
    457   EFI_UDP6_PROTOCOL         *Udp6;
    458 
    459   *IsCompleted = FALSE;
    460   Options = NULL;
    461 
    462   //
    463   // If already started the master download, don't change the
    464   // setting. Master download always succeeds.
    465   //
    466   Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
    467   ASSERT (Expected != -1);
    468 
    469   if (Instance->IsMaster && Expected != 1) {
    470     return EFI_SUCCESS;
    471   }
    472 
    473   ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
    474 
    475   //
    476   // Parse the options in the packet.
    477   //
    478   Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);
    479 
    480   if (EFI_ERROR (Status)) {
    481     return Status;
    482   }
    483   ASSERT (Options != NULL);
    484 
    485   //
    486   // Parse the extensive options in the packet.
    487   //
    488   Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo);
    489 
    490   if (EFI_ERROR (Status) || !Mtftp6RrqOackValid (Instance, &ExtInfo, &Instance->ExtInfo)) {
    491     //
    492     // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
    493     //
    494     if (Status != EFI_OUT_OF_RESOURCES) {
    495       //
    496       // Free the received packet before send new packet in ReceiveNotify,
    497       // since the udpio might need to be reconfigured.
    498       //
    499       NetbufFree (*UdpPacket);
    500       *UdpPacket = NULL;
    501       //
    502       // Send the Mtftp6 error message if invalid packet.
    503       //
    504       Mtftp6SendError (
    505         Instance,
    506         EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
    507         (UINT8 *) "Mal-formated OACK packet"
    508         );
    509     }
    510 
    511     return EFI_TFTP_ERROR;
    512   }
    513 
    514   if ((ExtInfo.BitMap & MTFTP6_OPT_MCAST_BIT) != 0) {
    515 
    516     //
    517     // Save the multicast info. Always update the Master, only update the
    518     // multicast IP address, block size, timeoute at the first time. If IP
    519     // address is updated, create a UDP child to receive the multicast.
    520     //
    521     Instance->IsMaster = ExtInfo.IsMaster;
    522 
    523     if (NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {
    524       if (NetIp6IsUnspecifiedAddr (&ExtInfo.McastIp) || ExtInfo.McastPort == 0) {
    525         //
    526         // Free the received packet before send new packet in ReceiveNotify,
    527         // since the udpio might need to be reconfigured.
    528         //
    529         NetbufFree (*UdpPacket);
    530         *UdpPacket = NULL;
    531         //
    532         // Send the Mtftp6 error message if invalid multi-cast setting.
    533         //
    534         Mtftp6SendError (
    535           Instance,
    536           EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
    537           (UINT8 *) "Illegal multicast setting"
    538           );
    539 
    540         return EFI_TFTP_ERROR;
    541       }
    542 
    543       //
    544       // Create a UDP child then start receive the multicast from it.
    545       //
    546       CopyMem (
    547         &Instance->McastIp,
    548         &ExtInfo.McastIp,
    549         sizeof (EFI_IP_ADDRESS)
    550         );
    551 
    552       Instance->McastPort  = ExtInfo.McastPort;
    553       if (Instance->McastUdpIo == NULL) {
    554         Instance->McastUdpIo = UdpIoCreateIo (
    555                                  Instance->Service->Controller,
    556                                  Instance->Service->Image,
    557                                  Mtftp6RrqConfigMcastUdpIo,
    558                                  UDP_IO_UDP6_VERSION,
    559                                  Instance
    560                                  );
    561         if (Instance->McastUdpIo != NULL) {
    562           Status = gBS->OpenProtocol (
    563                           Instance->McastUdpIo->UdpHandle,
    564                           &gEfiUdp6ProtocolGuid,
    565                           (VOID **) &Udp6,
    566                           Instance->Service->Image,
    567                           Instance->Handle,
    568                           EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    569                           );
    570           if (EFI_ERROR (Status)) {
    571             UdpIoFreeIo (Instance->McastUdpIo);
    572             Instance->McastUdpIo = NULL;
    573             return EFI_DEVICE_ERROR;
    574           }
    575         }
    576       }
    577 
    578       if (Instance->McastUdpIo == NULL) {
    579         return EFI_DEVICE_ERROR;
    580       }
    581 
    582       Status = UdpIoRecvDatagram (
    583                  Instance->McastUdpIo,
    584                  Mtftp6RrqInput,
    585                  Instance,
    586                  0
    587                  );
    588 
    589       if (EFI_ERROR (Status)) {
    590         //
    591         // Free the received packet before send new packet in ReceiveNotify,
    592         // since the udpio might need to be reconfigured.
    593         //
    594         NetbufFree (*UdpPacket);
    595         *UdpPacket = NULL;
    596         //
    597         // Send the Mtftp6 error message if failed to create Udp6Io to receive.
    598         //
    599         Mtftp6SendError (
    600           Instance,
    601           EFI_MTFTP6_ERRORCODE_ACCESS_VIOLATION,
    602           (UINT8 *) "Failed to create socket to receive multicast packet"
    603           );
    604 
    605         return Status;
    606       }
    607 
    608       //
    609       // Update the parameters used.
    610       //
    611       if (ExtInfo.BlkSize != 0) {
    612         Instance->BlkSize = ExtInfo.BlkSize;
    613       }
    614 
    615       if (ExtInfo.Timeout != 0) {
    616         Instance->Timeout = ExtInfo.Timeout;
    617       }
    618     }
    619 
    620   } else {
    621 
    622     Instance->IsMaster = TRUE;
    623 
    624     if (ExtInfo.BlkSize != 0) {
    625       Instance->BlkSize = ExtInfo.BlkSize;
    626     }
    627 
    628     if (ExtInfo.Timeout != 0) {
    629       Instance->Timeout = ExtInfo.Timeout;
    630     }
    631   }
    632 
    633   //
    634   // Free the received packet before send new packet in ReceiveNotify,
    635   // since the udpio might need to be reconfigured.
    636   //
    637   NetbufFree (*UdpPacket);
    638   *UdpPacket = NULL;
    639   //
    640   // Send an ACK to (Expected - 1) which is 0 for unicast download,
    641   // or tell the server we want to receive the Expected block.
    642   //
    643   return Mtftp6RrqSendAck (Instance, (UINT16) (Expected - 1));
    644 }
    645 
    646 
    647 /**
    648   The packet process callback for Mtftp6 download.
    649 
    650   @param[in]  UdpPacket             The pointer to the packet received.
    651   @param[in]  UdpEpt                The pointer to the Udp6 access point.
    652   @param[in]  IoStatus              The status from Udp6 instance.
    653   @param[in]  Context               The pointer to the context.
    654 
    655 **/
    656 VOID
    657 EFIAPI
    658 Mtftp6RrqInput (
    659   IN NET_BUF                *UdpPacket,
    660   IN UDP_END_POINT          *UdpEpt,
    661   IN EFI_STATUS             IoStatus,
    662   IN VOID                   *Context
    663   )
    664 {
    665   MTFTP6_INSTANCE           *Instance;
    666   EFI_MTFTP6_PACKET         *Packet;
    667   BOOLEAN                   IsCompleted;
    668   BOOLEAN                   IsMcast;
    669   EFI_STATUS                Status;
    670   UINT16                    Opcode;
    671   UINT32                    TotalNum;
    672   UINT32                    Len;
    673 
    674   Instance = (MTFTP6_INSTANCE *) Context;
    675 
    676   NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);
    677 
    678   Status      = EFI_SUCCESS;
    679   Packet      = NULL;
    680   IsCompleted = FALSE;
    681   IsMcast     = FALSE;
    682   TotalNum    = 0;
    683 
    684   //
    685   // Return error status if Udp6 instance failed to receive.
    686   //
    687   if (EFI_ERROR (IoStatus)) {
    688     Status = IoStatus;
    689     goto ON_EXIT;
    690   }
    691 
    692   ASSERT (UdpPacket != NULL);
    693 
    694   if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {
    695     goto ON_EXIT;
    696   }
    697 
    698   //
    699   // Find the port this packet is from to restart receive correctly.
    700   //
    701   if (CompareMem (
    702         Ip6Swap128 (&UdpEpt->LocalAddr.v6),
    703         &Instance->McastIp,
    704         sizeof (EFI_IPv6_ADDRESS)
    705         ) == 0) {
    706     IsMcast = TRUE;
    707   } else {
    708     IsMcast = FALSE;
    709   }
    710 
    711   //
    712   // Client send initial request to server's listening port. Server
    713   // will select a UDP port to communicate with the client. The server
    714   // is required to use the same port as RemotePort to multicast the
    715   // data.
    716   //
    717   if (UdpEpt->RemotePort != Instance->ServerDataPort) {
    718     if (Instance->ServerDataPort != 0) {
    719       goto ON_EXIT;
    720     } else {
    721       //
    722       // For the subsequent exchange of requests, reconfigure the udpio as
    723       // (serverip, serverport, localip, localport).
    724       // Ususally, the client set serverport as 0 to receive and reset it
    725       // once the first packet arrives to send ack.
    726       //
    727       Instance->ServerDataPort = UdpEpt->RemotePort;
    728     }
    729   }
    730 
    731   //
    732   // Copy the MTFTP packet to a continuous buffer if it isn't already so.
    733   //
    734   Len      = UdpPacket->TotalSize;
    735   TotalNum = UdpPacket->BlockOpNum;
    736 
    737   if (TotalNum > 1) {
    738     Packet = AllocateZeroPool (Len);
    739 
    740     if (Packet == NULL) {
    741       Status = EFI_OUT_OF_RESOURCES;
    742       goto ON_EXIT;
    743     }
    744 
    745     NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
    746 
    747   } else {
    748     Packet = (EFI_MTFTP6_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
    749     ASSERT (Packet != NULL);
    750   }
    751 
    752   Opcode = NTOHS (Packet->OpCode);
    753 
    754   //
    755   // Callback to the user's CheckPacket if provided. Abort the transmission
    756   // if CheckPacket returns an EFI_ERROR code.
    757   //
    758   if ((Instance->Token->CheckPacket != NULL) &&
    759       (Opcode == EFI_MTFTP6_OPCODE_OACK || Opcode == EFI_MTFTP6_OPCODE_ERROR)
    760       ) {
    761 
    762     Status = Instance->Token->CheckPacket (
    763                                 &Instance->Mtftp6,
    764                                 Instance->Token,
    765                                 (UINT16) Len,
    766                                 Packet
    767                                 );
    768 
    769     if (EFI_ERROR (Status)) {
    770       //
    771       // Send an error message to the server to inform it
    772       //
    773       if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {
    774         //
    775         // Free the received packet before send new packet in ReceiveNotify,
    776         // since the udpio might need to be reconfigured.
    777         //
    778         NetbufFree (UdpPacket);
    779         UdpPacket = NULL;
    780         //
    781         // Send the Mtftp6 error message if user aborted the current session.
    782         //
    783         Mtftp6SendError (
    784           Instance,
    785           EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
    786           (UINT8 *) "User aborted the transfer"
    787           );
    788       }
    789 
    790       Status = EFI_ABORTED;
    791       goto ON_EXIT;
    792     }
    793   }
    794 
    795   //
    796   // Switch the process routines by the operation code.
    797   //
    798   switch (Opcode) {
    799   case EFI_MTFTP6_OPCODE_DATA:
    800     if ((Len > (UINT32) (MTFTP6_DATA_HEAD_LEN + Instance->BlkSize)) || (Len < (UINT32) MTFTP6_DATA_HEAD_LEN)) {
    801       goto ON_EXIT;
    802     }
    803     //
    804     // Handle the data packet of Rrq.
    805     //
    806     Status = Mtftp6RrqHandleData (
    807                Instance,
    808                Packet,
    809                Len,
    810                &UdpPacket,
    811                &IsCompleted
    812                );
    813     break;
    814 
    815   case EFI_MTFTP6_OPCODE_OACK:
    816     if (IsMcast || Len <= MTFTP6_OPCODE_LEN) {
    817       goto ON_EXIT;
    818     }
    819     //
    820     // Handle the Oack packet of Rrq.
    821     //
    822     Status = Mtftp6RrqHandleOack (
    823                Instance,
    824                Packet,
    825                Len,
    826                &UdpPacket,
    827                &IsCompleted
    828                );
    829     break;
    830 
    831   default:
    832     //
    833     // Drop and return eror if received error message.
    834     //
    835     Status = EFI_TFTP_ERROR;
    836     break;
    837   }
    838 
    839 ON_EXIT:
    840   //
    841   // Free the resources, then if !EFI_ERROR (Status), restart the
    842   // receive, otherwise end the session.
    843   //
    844   if (Packet != NULL && TotalNum > 1) {
    845     FreePool (Packet);
    846   }
    847   if (UdpPacket != NULL) {
    848     NetbufFree (UdpPacket);
    849   }
    850   if (!EFI_ERROR (Status) && !IsCompleted) {
    851     if (IsMcast) {
    852       Status = UdpIoRecvDatagram (
    853                  Instance->McastUdpIo,
    854                  Mtftp6RrqInput,
    855                  Instance,
    856                  0
    857                  );
    858     } else {
    859       Status = UdpIoRecvDatagram (
    860                  Instance->UdpIo,
    861                  Mtftp6RrqInput,
    862                  Instance,
    863                  0
    864                  );
    865     }
    866   }
    867   //
    868   // Clean up the current session if failed to continue.
    869   //
    870   if (EFI_ERROR (Status) || IsCompleted) {
    871     Mtftp6OperationClean (Instance, Status);
    872   }
    873 }
    874 
    875 
    876 /**
    877   Start the Mtftp6 instance to download. It first initializes some
    878   of the internal states, then builds and sends an RRQ reqeuest packet.
    879   Finally, it starts receive for the downloading.
    880 
    881   @param[in]  Instance              The pointer to the Mtftp6 instance.
    882   @param[in]  Operation             The operation code of current packet.
    883 
    884   @retval EFI_SUCCESS           The Mtftp6 is started to download.
    885   @retval Others                Failed to start to download.
    886 
    887 **/
    888 EFI_STATUS
    889 Mtftp6RrqStart (
    890   IN MTFTP6_INSTANCE        *Instance,
    891   IN UINT16                 Operation
    892   )
    893 {
    894   EFI_STATUS                Status;
    895 
    896   //
    897   // The valid block number range are [1, 0xffff]. For example:
    898   // the client sends an RRQ request to the server, the server
    899   // transfers the DATA1 block. If option negoitation is ongoing,
    900   // the server will send back an OACK, then client will send ACK0.
    901   //
    902   Status = Mtftp6InitBlockRange (&Instance->BlkList, 1, 0xffff);
    903 
    904   if (EFI_ERROR (Status)) {
    905     return Status;
    906   }
    907 
    908   Status = Mtftp6SendRequest (Instance, Operation);
    909 
    910   if (EFI_ERROR (Status)) {
    911     return Status;
    912   }
    913 
    914   return UdpIoRecvDatagram (
    915            Instance->UdpIo,
    916            Mtftp6RrqInput,
    917            Instance,
    918            0
    919            );
    920 }
    921 
    922