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