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
SubmitRecieveToken(VOID)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
ConnectionClosed(IN EFI_EVENT Event,IN VOID * Context)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
CloseReceiveEvents(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
DataReceived(IN EFI_EVENT Event,IN VOID * Context)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
ConnectionAccepted(IN EFI_EVENT Event,IN VOID * Context)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
TcpFastbootTransportStart(EFI_EVENT ReceiveEvent)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
TcpFastbootTransportStop(VOID)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
DataSent(EFI_EVENT Event,VOID * Context)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
TcpFastbootTransportSend(IN UINTN BufferSize,IN CONST VOID * Buffer,IN EFI_EVENT * FatalErrorEvent)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
TcpFastbootTransportReceive(OUT UINTN * BufferSize,OUT VOID ** Buffer)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
TcpFastbootTransportEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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