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