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