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