Home | History | Annotate | Download | only in AndroidFastbootTransportTcpDxe
      1 /** @file
      2 #
      3 #  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
      4 #
      5 #  This program and the accompanying materials
      6 #  are licensed and made available under the terms and conditions of the BSD License
      7 #  which accompanies this distribution. The full text of the license may be found at
      8 #  http://opensource.org/licenses/bsd-license.php
      9 #  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 #  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 #
     12 #
     13 #**/
     14 
     15 #include <Protocol/AndroidFastbootTransport.h>
     16 #include <Protocol/Dhcp4.h>
     17 #include <Protocol/Tcp4.h>
     18 #include <Protocol/ServiceBinding.h>
     19 #include <Protocol/SimpleTextOut.h>
     20 
     21 #include <Library/BaseLib.h>
     22 #include <Library/BaseMemoryLib.h>
     23 #include <Library/DebugLib.h>
     24 #include <Library/MemoryAllocationLib.h>
     25 #include <Library/PrintLib.h>
     26 #include <Library/UefiBootServicesTableLib.h>
     27 #include <Library/UefiDriverEntryPoint.h>
     28 #include <Library/UefiRuntimeServicesTableLib.h>
     29 
     30 #define IP4_ADDR_TO_STRING(IpAddr, IpAddrString) UnicodeSPrint (       \
     31                                                    IpAddrString,       \
     32                                                    16 * 2,             \
     33                                                    L"%d.%d.%d.%d",     \
     34                                                    IpAddr.Addr[0],     \
     35                                                    IpAddr.Addr[1],     \
     36                                                    IpAddr.Addr[2],     \
     37                                                    IpAddr.Addr[3]      \
     38                                                    );
     39 
     40 // Fastboot says max packet size is 512, but FASTBOOT_TRANSPORT_PROTOCOL
     41 // doesn't place a limit on the size of buffers returned by Receive.
     42 // (This isn't actually a packet size - it's just the size of the buffers we
     43 //  pass to the TCP driver to fill with received data.)
     44 // We can achieve much better performance by doing this in larger chunks.
     45 #define RX_FRAGMENT_SIZE 2048
     46 
     47 STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut;
     48 
     49 STATIC EFI_TCP4_PROTOCOL *mTcpConnection;
     50 STATIC EFI_TCP4_PROTOCOL *mTcpListener;
     51 
     52 STATIC EFI_EVENT mReceiveEvent;
     53 
     54 STATIC EFI_SERVICE_BINDING_PROTOCOL *mTcpServiceBinding;
     55 STATIC EFI_HANDLE                    mTcpHandle = NULL;
     56 
     57 // We only ever use one IO token for receive and one for transmit. To save
     58 // repeatedly allocating and freeing, just allocate statically and re-use.
     59 #define NUM_RX_TOKENS 16
     60 #define TOKEN_NEXT(Index) (((Index) + 1) % NUM_RX_TOKENS)
     61 
     62 STATIC UINTN                     mNextSubmitIndex;
     63 STATIC UINTN                     mNextReceiveIndex;
     64 STATIC EFI_TCP4_IO_TOKEN         mReceiveToken[NUM_RX_TOKENS];
     65 STATIC EFI_TCP4_RECEIVE_DATA     mRxData[NUM_RX_TOKENS];
     66 STATIC EFI_TCP4_IO_TOKEN         mTransmitToken;
     67 STATIC EFI_TCP4_TRANSMIT_DATA    mTxData;
     68 // We also reuse the accept token
     69 STATIC EFI_TCP4_LISTEN_TOKEN     mAcceptToken;
     70 // .. and the close token
     71 STATIC EFI_TCP4_CLOSE_TOKEN      mCloseToken;
     72 
     73 // List type for queued received packets
     74 typedef struct _FASTBOOT_TCP_PACKET_LIST {
     75   LIST_ENTRY  Link;
     76   VOID       *Buffer;
     77   UINTN       BufferSize;
     78 } FASTBOOT_TCP_PACKET_LIST;
     79 
     80 STATIC LIST_ENTRY mPacketListHead;
     81 
     82 STATIC
     83 VOID
     84 EFIAPI
     85 DataReceived (
     86   IN EFI_EVENT Event,
     87   IN VOID     *Context
     88   );
     89 
     90 /*
     91   Helper function to set up a receive IO token and call Tcp->Receive
     92 */
     93 STATIC
     94 EFI_STATUS
     95 SubmitRecieveToken (
     96   VOID
     97   )
     98 {
     99   EFI_STATUS             Status;
    100   VOID                  *FragmentBuffer;
    101 
    102   Status = EFI_SUCCESS;
    103 
    104   FragmentBuffer = AllocatePool (RX_FRAGMENT_SIZE);
    105   ASSERT (FragmentBuffer != NULL);
    106   if (FragmentBuffer == NULL) {
    107     DEBUG ((EFI_D_ERROR, "TCP Fastboot out of resources"));
    108     return EFI_OUT_OF_RESOURCES;
    109   }
    110 
    111   mRxData[mNextSubmitIndex].DataLength = RX_FRAGMENT_SIZE;
    112   mRxData[mNextSubmitIndex].FragmentTable[0].FragmentLength = RX_FRAGMENT_SIZE;
    113   mRxData[mNextSubmitIndex].FragmentTable[0].FragmentBuffer = FragmentBuffer;
    114 
    115   Status = mTcpConnection->Receive (mTcpConnection, &mReceiveToken[mNextSubmitIndex]);
    116    if (EFI_ERROR (Status)) {
    117     DEBUG ((EFI_D_ERROR, "TCP Receive: %r\n", Status));
    118     FreePool (FragmentBuffer);
    119   }
    120 
    121   mNextSubmitIndex = TOKEN_NEXT (mNextSubmitIndex);
    122   return Status;
    123 }
    124 
    125 /*
    126   Event notify function for when we have closed our TCP connection.
    127   We can now start listening for another connection.
    128 */
    129 STATIC
    130 VOID
    131 ConnectionClosed (
    132   IN EFI_EVENT  Event,
    133   IN VOID      *Context
    134   )
    135 {
    136   EFI_STATUS Status;
    137 
    138   // Possible bug in EDK2 TCP4 driver: closing a connection doesn't remove its
    139   // PCB from the list of live connections. Subsequent attempts to Configure()
    140   // a TCP instance with the same local port will fail with INVALID_PARAMETER.
    141   // Calling Configure with NULL is a workaround for this issue.
    142   Status = mTcpConnection->Configure (mTcpConnection, NULL);
    143 
    144   mTcpConnection = NULL;
    145 
    146   Status = mTcpListener->Accept (mTcpListener, &mAcceptToken);
    147   if (EFI_ERROR (Status)) {
    148     DEBUG ((EFI_D_ERROR, "TCP Accept: %r\n", Status));
    149   }
    150 }
    151 
    152 STATIC
    153 VOID
    154 CloseReceiveEvents (
    155   VOID
    156   )
    157 {
    158   UINTN Index;
    159 
    160   for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
    161     gBS->CloseEvent (mReceiveToken[Index].CompletionToken.Event);
    162   }
    163 }
    164 
    165 /*
    166   Event notify function to be called when we receive TCP data.
    167 */
    168 STATIC
    169 VOID
    170 EFIAPI
    171 DataReceived (
    172   IN EFI_EVENT Event,
    173   IN VOID     *Context
    174   )
    175 {
    176   EFI_STATUS                 Status;
    177   FASTBOOT_TCP_PACKET_LIST  *NewEntry;
    178   EFI_TCP4_IO_TOKEN         *ReceiveToken;
    179 
    180   ReceiveToken = &mReceiveToken[mNextReceiveIndex];
    181 
    182   Status = ReceiveToken->CompletionToken.Status;
    183 
    184   if (Status == EFI_CONNECTION_FIN) {
    185     //
    186     // Remote host closed connection. Close our end.
    187     //
    188 
    189     CloseReceiveEvents ();
    190 
    191     Status = mTcpConnection->Close (mTcpConnection, &mCloseToken);
    192     ASSERT_EFI_ERROR (Status);
    193 
    194     return;
    195   }
    196 
    197   //
    198   // Add an element to the receive queue
    199   //
    200 
    201   NewEntry = AllocatePool (sizeof (FASTBOOT_TCP_PACKET_LIST));
    202   if (NewEntry == NULL) {
    203     DEBUG ((EFI_D_ERROR, "TCP Fastboot: Out of resources\n"));
    204     return;
    205   }
    206 
    207   mNextReceiveIndex = TOKEN_NEXT (mNextReceiveIndex);
    208 
    209   if (!EFI_ERROR (Status)) {
    210     NewEntry->Buffer
    211       = ReceiveToken->Packet.RxData->FragmentTable[0].FragmentBuffer;
    212     NewEntry->BufferSize
    213       = ReceiveToken->Packet.RxData->FragmentTable[0].FragmentLength;
    214 
    215     // Prepare to receive more data
    216     SubmitRecieveToken();
    217   } else {
    218     // Fatal receive error. Put an entry with NULL in the queue, signifying
    219     // to return EFI_DEVICE_ERROR from TcpFastbootTransportReceive.
    220     NewEntry->Buffer = NULL;
    221     NewEntry->BufferSize = 0;
    222 
    223     DEBUG ((EFI_D_ERROR, "\nTCP Fastboot Receive error: %r\n", Status));
    224   }
    225 
    226   InsertTailList (&mPacketListHead, &NewEntry->Link);
    227 
    228   Status = gBS->SignalEvent (mReceiveEvent);
    229   ASSERT_EFI_ERROR (Status);
    230 }
    231 
    232 
    233 /*
    234   Event notify function to be called when we accept an incoming TCP connection.
    235 */
    236 STATIC
    237 VOID
    238 EFIAPI
    239 ConnectionAccepted (
    240   IN EFI_EVENT Event,
    241   IN VOID     *Context
    242   )
    243 {
    244   EFI_TCP4_LISTEN_TOKEN *AcceptToken;
    245   EFI_STATUS             Status;
    246   UINTN                  Index;
    247 
    248   AcceptToken = (EFI_TCP4_LISTEN_TOKEN *) Context;
    249   Status = AcceptToken->CompletionToken.Status;
    250 
    251   if (EFI_ERROR (Status)) {
    252     DEBUG ((EFI_D_ERROR, "TCP Fastboot: Connection Error: %r\n", Status));
    253     return;
    254   }
    255   DEBUG ((EFI_D_ERROR, "TCP Fastboot: Connection Received.\n"));
    256 
    257   //
    258   // Accepting a new TCP connection creates a new instance of the TCP protocol.
    259   // Open it and prepare to receive on it.
    260   //
    261 
    262   Status = gBS->OpenProtocol (
    263                   AcceptToken->NewChildHandle,
    264                   &gEfiTcp4ProtocolGuid,
    265                   (VOID **) &mTcpConnection,
    266                   gImageHandle,
    267                   NULL,
    268                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    269                   );
    270   if (EFI_ERROR (Status)) {
    271     DEBUG ((EFI_D_ERROR, "Open TCP Connection: %r\n", Status));
    272     return;
    273   }
    274 
    275   mNextSubmitIndex = 0;
    276   mNextReceiveIndex = 0;
    277 
    278   for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
    279     Status = gBS->CreateEvent (
    280                     EVT_NOTIFY_SIGNAL,
    281                     TPL_CALLBACK,
    282                     DataReceived,
    283                     NULL,
    284                     &(mReceiveToken[Index].CompletionToken.Event)
    285                     );
    286     ASSERT_EFI_ERROR (Status);
    287   }
    288 
    289   for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
    290     SubmitRecieveToken();
    291   }
    292 }
    293 
    294 /*
    295   Set up TCP Fastboot transport: Configure the network device via DHCP then
    296   start waiting for a TCP connection on the Fastboot port.
    297 */
    298 EFI_STATUS
    299 TcpFastbootTransportStart (
    300   EFI_EVENT ReceiveEvent
    301   )
    302 {
    303   EFI_STATUS                    Status;
    304   EFI_HANDLE                    NetDeviceHandle;
    305   EFI_HANDLE                   *HandleBuffer;
    306   EFI_IP4_MODE_DATA             Ip4ModeData;
    307   UINTN                         NumHandles;
    308   CHAR16                        IpAddrString[16];
    309   UINTN                         Index;
    310 
    311   EFI_TCP4_CONFIG_DATA TcpConfigData = {
    312     0x00,                                           // IPv4 Type of Service
    313     255,                                            // IPv4 Time to Live
    314     {                                               // AccessPoint:
    315       TRUE,                                         // Use default address
    316       { {0, 0, 0, 0} },                             // IP Address  (ignored - use default)
    317       { {0, 0, 0, 0} },                             // Subnet mask (ignored - use default)
    318       FixedPcdGet32 (PcdAndroidFastbootTcpPort),    // Station port
    319       { {0, 0, 0, 0} },                             // Remote address: accept any
    320       0,                                            // Remote Port: accept any
    321       FALSE                                         // ActiveFlag: be a "server"
    322     },
    323     NULL                                            // Default advanced TCP options
    324   };
    325 
    326   mReceiveEvent = ReceiveEvent;
    327   InitializeListHead (&mPacketListHead);
    328 
    329   mTextOut->OutputString (mTextOut, L"Initialising TCP Fastboot transport...\r\n");
    330 
    331   //
    332   // Open a passive TCP instance
    333   //
    334 
    335   Status = gBS->LocateHandleBuffer (
    336                   ByProtocol,
    337                   &gEfiTcp4ServiceBindingProtocolGuid,
    338                   NULL,
    339                   &NumHandles,
    340                   &HandleBuffer
    341                   );
    342   if (EFI_ERROR (Status)) {
    343     DEBUG ((EFI_D_ERROR, "Find TCP Service Binding: %r\n", Status));
    344     return Status;
    345   }
    346 
    347   // We just use the first network device
    348   NetDeviceHandle = HandleBuffer[0];
    349 
    350   Status =  gBS->OpenProtocol (
    351                     NetDeviceHandle,
    352                     &gEfiTcp4ServiceBindingProtocolGuid,
    353                     (VOID **) &mTcpServiceBinding,
    354                     gImageHandle,
    355                     NULL,
    356                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    357                     );
    358   if (EFI_ERROR (Status)) {
    359     DEBUG ((EFI_D_ERROR, "Open TCP Service Binding: %r\n", Status));
    360     return Status;
    361   }
    362 
    363   Status = mTcpServiceBinding->CreateChild (mTcpServiceBinding, &mTcpHandle);
    364   if (EFI_ERROR (Status)) {
    365     DEBUG ((EFI_D_ERROR, "TCP ServiceBinding Create: %r\n", Status));
    366     return Status;
    367   }
    368 
    369   Status =  gBS->OpenProtocol (
    370                     mTcpHandle,
    371                     &gEfiTcp4ProtocolGuid,
    372                     (VOID **) &mTcpListener,
    373                     gImageHandle,
    374                     NULL,
    375                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    376                     );
    377   if (EFI_ERROR (Status)) {
    378     DEBUG ((EFI_D_ERROR, "Open TCP Protocol: %r\n", Status));
    379   }
    380 
    381   //
    382   // Set up re-usable tokens
    383   //
    384 
    385   for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
    386     mRxData[Index].UrgentFlag = FALSE;
    387     mRxData[Index].FragmentCount = 1;
    388     mReceiveToken[Index].Packet.RxData = &mRxData[Index];
    389   }
    390 
    391   mTxData.Push = TRUE;
    392   mTxData.Urgent = FALSE;
    393   mTxData.FragmentCount = 1;
    394   mTransmitToken.Packet.TxData = &mTxData;
    395 
    396   Status = gBS->CreateEvent (
    397                   EVT_NOTIFY_SIGNAL,
    398                   TPL_CALLBACK,
    399                   ConnectionAccepted,
    400                   &mAcceptToken,
    401                   &mAcceptToken.CompletionToken.Event
    402                   );
    403   ASSERT_EFI_ERROR (Status);
    404 
    405   Status = gBS->CreateEvent (
    406                   EVT_NOTIFY_SIGNAL,
    407                   TPL_CALLBACK,
    408                   ConnectionClosed,
    409                   &mCloseToken,
    410                   &mCloseToken.CompletionToken.Event
    411                   );
    412   ASSERT_EFI_ERROR (Status);
    413 
    414   //
    415   // Configure the TCP instance
    416   //
    417 
    418   Status = mTcpListener->Configure (mTcpListener, &TcpConfigData);
    419   if (Status == EFI_NO_MAPPING) {
    420     // Wait until the IP configuration process (probably DHCP) has finished
    421     do {
    422       Status = mTcpListener->GetModeData (mTcpListener,
    423                                NULL, NULL,
    424                                &Ip4ModeData,
    425                                NULL, NULL
    426                                );
    427       ASSERT_EFI_ERROR (Status);
    428     } while (!Ip4ModeData.IsConfigured);
    429     Status = mTcpListener->Configure (mTcpListener, &TcpConfigData);
    430   } else if (EFI_ERROR (Status)) {
    431     DEBUG ((EFI_D_ERROR, "TCP Configure: %r\n", Status));
    432     return Status;
    433   }
    434 
    435   //
    436   // Tell the user our address and hostname
    437   //
    438   IP4_ADDR_TO_STRING (Ip4ModeData.ConfigData.StationAddress, IpAddrString);
    439 
    440   mTextOut->OutputString (mTextOut, L"TCP Fastboot transport configured.");
    441   mTextOut->OutputString (mTextOut, L"\r\nIP address: ");
    442   mTextOut->OutputString (mTextOut ,IpAddrString);
    443   mTextOut->OutputString (mTextOut, L"\r\n");
    444 
    445   //
    446   // Start listening for a connection
    447   //
    448 
    449   Status = mTcpListener->Accept (mTcpListener, &mAcceptToken);
    450   if (EFI_ERROR (Status)) {
    451     DEBUG ((EFI_D_ERROR, "TCP Accept: %r\n", Status));
    452     return Status;
    453   }
    454 
    455   mTextOut->OutputString (mTextOut, L"TCP Fastboot transport initialised.\r\n");
    456 
    457   FreePool (HandleBuffer);
    458 
    459   return EFI_SUCCESS;
    460 }
    461 
    462 EFI_STATUS
    463 TcpFastbootTransportStop (
    464   VOID
    465   )
    466 {
    467   EFI_TCP4_CLOSE_TOKEN      CloseToken;
    468   EFI_STATUS                Status;
    469   UINTN                     EventIndex;
    470   FASTBOOT_TCP_PACKET_LIST *Entry;
    471   FASTBOOT_TCP_PACKET_LIST *NextEntry;
    472 
    473   // Close any existing TCP connection, blocking until it's done.
    474   if (mTcpConnection != NULL) {
    475     CloseReceiveEvents ();
    476 
    477     CloseToken.AbortOnClose = FALSE;
    478 
    479     Status = gBS->CreateEvent (0, 0, NULL, NULL, &CloseToken.CompletionToken.Event);
    480     ASSERT_EFI_ERROR (Status);
    481 
    482     Status = mTcpConnection->Close (mTcpConnection, &CloseToken);
    483     ASSERT_EFI_ERROR (Status);
    484 
    485     Status = gBS->WaitForEvent (
    486                     1,
    487                     &CloseToken.CompletionToken.Event,
    488                     &EventIndex
    489                     );
    490     ASSERT_EFI_ERROR (Status);
    491 
    492     ASSERT_EFI_ERROR (CloseToken.CompletionToken.Status);
    493 
    494     // Possible bug in EDK2 TCP4 driver: closing a connection doesn't remove its
    495     // PCB from the list of live connections. Subsequent attempts to Configure()
    496     // a TCP instance with the same local port will fail with INVALID_PARAMETER.
    497     // Calling Configure with NULL is a workaround for this issue.
    498     Status = mTcpConnection->Configure (mTcpConnection, NULL);
    499     ASSERT_EFI_ERROR (Status);
    500   }
    501 
    502 
    503   gBS->CloseEvent (mAcceptToken.CompletionToken.Event);
    504 
    505   // Stop listening for connections.
    506   // Ideally we would do this with Cancel, but it isn't implemented by EDK2.
    507   // So we just "reset this TCPv4 instance brutally".
    508   Status = mTcpListener->Configure (mTcpListener, NULL);
    509   ASSERT_EFI_ERROR (Status);
    510 
    511   Status = mTcpServiceBinding->DestroyChild (mTcpServiceBinding, &mTcpHandle);
    512 
    513   // Free any data the user didn't pick up
    514   Entry = (FASTBOOT_TCP_PACKET_LIST *) GetFirstNode (&mPacketListHead);
    515   while (!IsNull (&mPacketListHead, &Entry->Link)) {
    516     NextEntry = (FASTBOOT_TCP_PACKET_LIST *) GetNextNode (&mPacketListHead, &Entry->Link);
    517 
    518     RemoveEntryList (&Entry->Link);
    519     if (Entry->Buffer) {
    520       FreePool (Entry->Buffer);
    521     }
    522     FreePool (Entry);
    523 
    524     Entry = NextEntry;
    525   }
    526 
    527   return EFI_SUCCESS;
    528 }
    529 
    530 /*
    531   Event notify function for when data has been sent. Free resources and report
    532   errors.
    533   Context should point to the transmit IO token passed to
    534   TcpConnection->Transmit.
    535 */
    536 STATIC
    537 VOID
    538 DataSent (
    539   EFI_EVENT Event,
    540   VOID     *Context
    541   )
    542 {
    543   EFI_STATUS           Status;
    544 
    545   Status = mTransmitToken.CompletionToken.Status;
    546   if (EFI_ERROR (Status)) {
    547     DEBUG ((EFI_D_ERROR, "TCP Fastboot transmit result: %r\n", Status));
    548     gBS->SignalEvent (*(EFI_EVENT *) Context);
    549   }
    550 
    551   FreePool (mTransmitToken.Packet.TxData->FragmentTable[0].FragmentBuffer);
    552 }
    553 
    554 EFI_STATUS
    555 TcpFastbootTransportSend (
    556   IN        UINTN      BufferSize,
    557   IN  CONST VOID      *Buffer,
    558   IN        EFI_EVENT *FatalErrorEvent
    559   )
    560 {
    561   EFI_STATUS                Status;
    562 
    563   if (BufferSize > 512) {
    564     return EFI_INVALID_PARAMETER;
    565   }
    566 
    567   //
    568   // Build transmit IO token
    569   //
    570 
    571   // Create an event so we are notified when a transmission is complete.
    572   // We use this to free resources and report errors.
    573   Status = gBS->CreateEvent (
    574                   EVT_NOTIFY_SIGNAL,
    575                   TPL_CALLBACK,
    576                   DataSent,
    577                   FatalErrorEvent,
    578                   &mTransmitToken.CompletionToken.Event
    579                   );
    580   ASSERT_EFI_ERROR (Status);
    581 
    582   mTxData.DataLength = BufferSize;
    583 
    584   mTxData.FragmentTable[0].FragmentLength = BufferSize;
    585   mTxData.FragmentTable[0].FragmentBuffer = AllocateCopyPool (
    586                                              BufferSize,
    587                                              Buffer
    588                                              );
    589 
    590   Status = mTcpConnection->Transmit (mTcpConnection, &mTransmitToken);
    591   if (EFI_ERROR (Status)) {
    592     DEBUG ((EFI_D_ERROR, "TCP Transmit: %r\n", Status));
    593     return Status;
    594   }
    595 
    596   return EFI_SUCCESS;
    597 }
    598 
    599 
    600 EFI_STATUS
    601 TcpFastbootTransportReceive (
    602   OUT UINTN  *BufferSize,
    603   OUT VOID  **Buffer
    604   )
    605 {
    606   FASTBOOT_TCP_PACKET_LIST *Entry;
    607 
    608   if (IsListEmpty (&mPacketListHead)) {
    609     return EFI_NOT_READY;
    610   }
    611 
    612   Entry = (FASTBOOT_TCP_PACKET_LIST *) GetFirstNode (&mPacketListHead);
    613 
    614   if (Entry->Buffer == NULL) {
    615     // There was an error receiving this packet.
    616     return EFI_DEVICE_ERROR;
    617   }
    618 
    619   *Buffer = Entry->Buffer;
    620   *BufferSize = Entry->BufferSize;
    621 
    622   RemoveEntryList (&Entry->Link);
    623   FreePool (Entry);
    624 
    625   return EFI_SUCCESS;
    626 }
    627 
    628 FASTBOOT_TRANSPORT_PROTOCOL mTransportProtocol = {
    629   TcpFastbootTransportStart,
    630   TcpFastbootTransportStop,
    631   TcpFastbootTransportSend,
    632   TcpFastbootTransportReceive
    633 };
    634 
    635 EFI_STATUS
    636 TcpFastbootTransportEntryPoint (
    637   IN EFI_HANDLE        ImageHandle,
    638   IN EFI_SYSTEM_TABLE *SystemTable
    639   )
    640 {
    641   EFI_STATUS Status;
    642 
    643 
    644   Status = gBS->LocateProtocol(
    645     &gEfiSimpleTextOutProtocolGuid,
    646     NULL,
    647     (VOID **) &mTextOut
    648     );
    649   if (EFI_ERROR (Status)) {
    650     DEBUG ((EFI_D_ERROR, "Fastboot: Open Text Output Protocol: %r\n", Status));
    651     return Status;
    652   }
    653 
    654   Status = gBS->InstallProtocolInterface (
    655                   &ImageHandle,
    656                   &gAndroidFastbootTransportProtocolGuid,
    657                   EFI_NATIVE_INTERFACE,
    658                   &mTransportProtocol
    659                   );
    660   if (EFI_ERROR (Status)) {
    661     DEBUG ((EFI_D_ERROR, "Fastboot: Install transport Protocol: %r\n", Status));
    662   }
    663 
    664   return Status;
    665 }
    666