]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c
MdeModulePkg UsbBusPei: Fix wrong buffer length used to read hub desc
[mirror_edk2.git] / MdeModulePkg / Library / DxeTcpIoLib / DxeTcpIoLib.c
CommitLineData
4bad9ada 1/** @file\r
2 This library is used to share code between UEFI network stack modules.\r
3 It provides the helper routines to access TCP service.\r
4\r
b5035efa 5Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>\r
4bad9ada 6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at<BR>\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <Uefi.h>\r
17\r
18#include <Library/TcpIoLib.h>\r
19#include <Library/BaseLib.h>\r
20#include <Library/DebugLib.h>\r
21#include <Library/UefiBootServicesTableLib.h>\r
22#include <Library/MemoryAllocationLib.h>\r
23#include <Library/BaseMemoryLib.h>\r
24\r
4b738c76 25/**\r
4bad9ada 26 The common notify function associated with various TcpIo events. \r
4b738c76
HT
27\r
28 @param[in] Event The event signaled.\r
29 @param[in] Context The context.\r
30\r
31**/\r
32VOID\r
33EFIAPI\r
4bad9ada 34TcpIoCommonNotify (\r
4b738c76
HT
35 IN EFI_EVENT Event,\r
36 IN VOID *Context\r
37 )\r
4bad9ada 38{\r
39 if ((Event == NULL) || (Context == NULL)) {\r
40 return ;\r
41 }\r
42\r
4b738c76 43 *((BOOLEAN *) Context) = TRUE;\r
4bad9ada 44}\r
45\r
4b738c76 46/**\r
4bad9ada 47 The internal function for delay configuring TCP6 when IP6 driver is still in DAD.\r
4b738c76
HT
48\r
49 @param[in] Tcp6 The EFI_TCP6_PROTOCOL protocol instance.\r
50 @param[in] Tcp6ConfigData The Tcp6 configuration data.\r
51\r
52 @retval EFI_SUCCESS The operational settings successfully\r
53 completed.\r
4bad9ada 54 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
55 @retval Others Failed to finish the operation.\r
56\r
4b738c76
HT
57**/\r
58EFI_STATUS\r
4bad9ada 59TcpIoGetMapping (\r
4b738c76
HT
60 IN EFI_TCP6_PROTOCOL *Tcp6,\r
61 IN EFI_TCP6_CONFIG_DATA *Tcp6ConfigData\r
62 )\r
63{\r
64 EFI_STATUS Status;\r
65 EFI_EVENT Event;\r
4bad9ada 66\r
67 if ((Tcp6 == NULL) || (Tcp6ConfigData == NULL)) {\r
68 return EFI_INVALID_PARAMETER;\r
69 }\r
70\r
4b738c76
HT
71 Event = NULL;\r
72 Status = gBS->CreateEvent (\r
73 EVT_TIMER,\r
74 TPL_CALLBACK,\r
75 NULL,\r
76 NULL,\r
77 &Event\r
78 );\r
79 if (EFI_ERROR (Status)) {\r
80 goto ON_EXIT;\r
81 }\r
82\r
83 Status = gBS->SetTimer (\r
84 Event,\r
85 TimerRelative,\r
4bad9ada 86 TCP_GET_MAPPING_TIMEOUT\r
4b738c76
HT
87 );\r
88\r
89 if (EFI_ERROR (Status)) {\r
90 goto ON_EXIT;\r
91 }\r
92\r
93 while (EFI_ERROR (gBS->CheckEvent (Event))) {\r
94\r
95 Tcp6->Poll (Tcp6);\r
96\r
97 Status = Tcp6->Configure (Tcp6, Tcp6ConfigData);\r
98\r
99 if (!EFI_ERROR (Status)) {\r
100 break;\r
101 }\r
102 }\r
103\r
104ON_EXIT:\r
105\r
106 if (Event != NULL) {\r
107 gBS->CloseEvent (Event);\r
108 }\r
109\r
110 return Status;\r
4bad9ada 111}\r
112\r
113/**\r
114 Create a TCP socket with the specified configuration data. \r
115\r
116 @param[in] Image The handle of the driver image.\r
117 @param[in] Controller The handle of the controller.\r
118 @param[in] TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6.\r
119 @param[in] ConfigData The Tcp configuration data.\r
120 @param[out] TcpIo The TcpIo.\r
121 \r
122 @retval EFI_SUCCESS The TCP socket is created and configured.\r
123 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
4b738c76 124 @retval EFI_UNSUPPORTED One or more of the control options are not\r
4bad9ada 125 supported in the implementation.\r
8322eb77 126 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
4bad9ada 127 @retval Others Failed to create the TCP socket or configure it.\r
128\r
129**/\r
130EFI_STATUS\r
131EFIAPI\r
132TcpIoCreateSocket (\r
133 IN EFI_HANDLE Image,\r
134 IN EFI_HANDLE Controller,\r
135 IN UINT8 TcpVersion,\r
136 IN TCP_IO_CONFIG_DATA *ConfigData,\r
137 OUT TCP_IO *TcpIo\r
138 )\r
139{\r
140 EFI_STATUS Status;\r
141 EFI_EVENT Event;\r
142 EFI_GUID *ServiceBindingGuid;\r
143 EFI_GUID *ProtocolGuid;\r
144 VOID **Interface;\r
145 EFI_TCP4_OPTION ControlOption;\r
146 EFI_TCP4_CONFIG_DATA Tcp4ConfigData;\r
147 EFI_TCP4_ACCESS_POINT *AccessPoint4;\r
148 EFI_TCP4_PROTOCOL *Tcp4;\r
149 EFI_TCP6_CONFIG_DATA Tcp6ConfigData;\r
150 EFI_TCP6_ACCESS_POINT *AccessPoint6;\r
151 EFI_TCP6_PROTOCOL *Tcp6;\r
8322eb77 152 EFI_TCP4_RECEIVE_DATA *RxData;\r
4bad9ada 153\r
154 if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (TcpIo == NULL)) {\r
155 return EFI_INVALID_PARAMETER;\r
156 }\r
157\r
158 Tcp4 = NULL;\r
159 Tcp6 = NULL;\r
160\r
161 ZeroMem (TcpIo, sizeof (TCP_IO));\r
162\r
163 if (TcpVersion == TCP_VERSION_4) {\r
164 ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
165 ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
166 Interface = (VOID **) (&TcpIo->Tcp.Tcp4);\r
167 } else if (TcpVersion == TCP_VERSION_6) {\r
168 ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
169 ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
170 Interface = (VOID **) (&TcpIo->Tcp.Tcp6);\r
171 } else {\r
172 return EFI_UNSUPPORTED;\r
173 }\r
174\r
175 TcpIo->TcpVersion = TcpVersion;\r
176\r
177 //\r
178 // Create the TCP child instance and get the TCP protocol.\r
179 // \r
4b738c76
HT
180 Status = NetLibCreateServiceChild (\r
181 Controller,\r
182 Image,\r
4bad9ada 183 ServiceBindingGuid,\r
184 &TcpIo->Handle\r
4b738c76
HT
185 );\r
186 if (EFI_ERROR (Status)) {\r
187 return Status;\r
188 }\r
189\r
190 Status = gBS->OpenProtocol (\r
4bad9ada 191 TcpIo->Handle,\r
192 ProtocolGuid,\r
193 Interface,\r
4b738c76
HT
194 Image,\r
195 Controller,\r
196 EFI_OPEN_PROTOCOL_BY_DRIVER\r
197 );\r
4bad9ada 198 if (EFI_ERROR (Status) || (*Interface == NULL)) {\r
4b738c76 199 goto ON_ERROR;\r
4bad9ada 200 }\r
201\r
202 if (TcpVersion == TCP_VERSION_4) {\r
203 Tcp4 = TcpIo->Tcp.Tcp4;\r
204 } else {\r
205 Tcp6 = TcpIo->Tcp.Tcp6;\r
206 }\r
4b738c76 207\r
4bad9ada 208 TcpIo->Image = Image;\r
209 TcpIo->Controller = Controller;\r
4b738c76
HT
210\r
211 //\r
212 // Set the configuration parameters.\r
213 //\r
214 ControlOption.ReceiveBufferSize = 0x200000;\r
215 ControlOption.SendBufferSize = 0x200000;\r
216 ControlOption.MaxSynBackLog = 0;\r
217 ControlOption.ConnectionTimeout = 0;\r
218 ControlOption.DataRetries = 6;\r
219 ControlOption.FinTimeout = 0;\r
220 ControlOption.TimeWaitTimeout = 0;\r
221 ControlOption.KeepAliveProbes = 4;\r
222 ControlOption.KeepAliveTime = 0;\r
223 ControlOption.KeepAliveInterval = 0;\r
224 ControlOption.EnableNagle = FALSE;\r
225 ControlOption.EnableTimeStamp = FALSE;\r
226 ControlOption.EnableWindowScaling = TRUE;\r
227 ControlOption.EnableSelectiveAck = FALSE;\r
228 ControlOption.EnablePathMtuDiscovery = FALSE;\r
4bad9ada 229\r
230 if (TcpVersion == TCP_VERSION_4) {\r
231 Tcp4ConfigData.TypeOfService = 8;\r
232 Tcp4ConfigData.TimeToLive = 255;\r
233 Tcp4ConfigData.ControlOption = &ControlOption;\r
234\r
235 AccessPoint4 = &Tcp4ConfigData.AccessPoint;\r
236\r
237 ZeroMem (AccessPoint4, sizeof (EFI_TCP4_ACCESS_POINT));\r
238 AccessPoint4->StationPort = ConfigData->Tcp4IoConfigData.StationPort;\r
239 AccessPoint4->RemotePort = ConfigData->Tcp4IoConfigData.RemotePort;\r
240 AccessPoint4->ActiveFlag = ConfigData->Tcp4IoConfigData.ActiveFlag;\r
241\r
242 CopyMem (\r
243 &AccessPoint4->StationAddress,\r
244 &ConfigData->Tcp4IoConfigData.LocalIp,\r
245 sizeof (EFI_IPv4_ADDRESS)\r
246 );\r
247 CopyMem (\r
248 &AccessPoint4->SubnetMask,\r
249 &ConfigData->Tcp4IoConfigData.SubnetMask,\r
250 sizeof (EFI_IPv4_ADDRESS)\r
251 );\r
252 CopyMem (\r
253 &AccessPoint4->RemoteAddress,\r
254 &ConfigData->Tcp4IoConfigData.RemoteIp,\r
255 sizeof (EFI_IPv4_ADDRESS)\r
256 );\r
257\r
258 ASSERT (Tcp4 != NULL);\r
259\r
260 //\r
261 // Configure the TCP4 protocol.\r
262 //\r
263 Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData);\r
264 if (EFI_ERROR (Status)) {\r
265 goto ON_ERROR;\r
266 }\r
267\r
268 if (!EFI_IP4_EQUAL (&ConfigData->Tcp4IoConfigData.Gateway, &mZeroIp4Addr)) {\r
269 //\r
270 // The gateway is not zero. Add the default route manually.\r
271 //\r
272 Status = Tcp4->Routes (\r
273 Tcp4,\r
274 FALSE,\r
275 &mZeroIp4Addr,\r
276 &mZeroIp4Addr,\r
277 &ConfigData->Tcp4IoConfigData.Gateway\r
278 );\r
279 if (EFI_ERROR (Status)) {\r
280 goto ON_ERROR;\r
281 }\r
282 }\r
283 } else {\r
284 Tcp6ConfigData.TrafficClass = 0;\r
285 Tcp6ConfigData.HopLimit = 255;\r
286 Tcp6ConfigData.ControlOption = (EFI_TCP6_OPTION *) &ControlOption;\r
287\r
288 AccessPoint6 = &Tcp6ConfigData.AccessPoint;\r
289\r
290 ZeroMem (AccessPoint6, sizeof (EFI_TCP6_ACCESS_POINT));\r
291 AccessPoint6->StationPort = ConfigData->Tcp6IoConfigData.StationPort;\r
292 AccessPoint6->RemotePort = ConfigData->Tcp6IoConfigData.RemotePort;\r
293 AccessPoint6->ActiveFlag = ConfigData->Tcp6IoConfigData.ActiveFlag;\r
294\r
295 IP6_COPY_ADDRESS (&AccessPoint6->RemoteAddress, &ConfigData->Tcp6IoConfigData.RemoteIp);\r
296\r
297\r
298 ASSERT (Tcp6 != NULL);\r
299 //\r
300 // Configure the TCP6 protocol.\r
301 //\r
302 Status = Tcp6->Configure (Tcp6, &Tcp6ConfigData);\r
303 if (Status == EFI_NO_MAPPING) {\r
304 Status = TcpIoGetMapping (Tcp6, &Tcp6ConfigData);\r
305 }\r
306\r
307 if (EFI_ERROR (Status)) {\r
308 goto ON_ERROR;\r
309 }\r
310 }\r
311\r
4b738c76
HT
312 //\r
313 // Create events for variuos asynchronous operations.\r
4bad9ada 314 //\r
315 Status = gBS->CreateEvent (\r
4b738c76
HT
316 EVT_NOTIFY_SIGNAL,\r
317 TPL_NOTIFY,\r
4bad9ada 318 TcpIoCommonNotify,\r
319 &TcpIo->IsConnDone,\r
320 &Event\r
4b738c76
HT
321 );\r
322 if (EFI_ERROR (Status)) {\r
323 goto ON_ERROR;\r
4bad9ada 324 }\r
325\r
326 TcpIo->ConnToken.Tcp4Token.CompletionToken.Event = Event;\r
327\r
4b738c76
HT
328 Status = gBS->CreateEvent (\r
329 EVT_NOTIFY_SIGNAL,\r
330 TPL_NOTIFY,\r
4bad9ada 331 TcpIoCommonNotify,\r
332 &TcpIo->IsListenDone,\r
333 &Event\r
4b738c76
HT
334 );\r
335 if (EFI_ERROR (Status)) {\r
336 goto ON_ERROR;\r
4bad9ada 337 }\r
338\r
339 TcpIo->ListenToken.Tcp4Token.CompletionToken.Event = Event;\r
340\r
4b738c76
HT
341 Status = gBS->CreateEvent (\r
342 EVT_NOTIFY_SIGNAL,\r
343 TPL_NOTIFY,\r
4bad9ada 344 TcpIoCommonNotify,\r
345 &TcpIo->IsTxDone,\r
346 &Event\r
4b738c76
HT
347 );\r
348 if (EFI_ERROR (Status)) {\r
349 goto ON_ERROR;\r
350 }\r
4bad9ada 351\r
352 TcpIo->TxToken.Tcp4Token.CompletionToken.Event = Event;\r
353\r
354\r
4b738c76
HT
355 Status = gBS->CreateEvent (\r
356 EVT_NOTIFY_SIGNAL,\r
357 TPL_NOTIFY,\r
4bad9ada 358 TcpIoCommonNotify,\r
359 &TcpIo->IsRxDone,\r
360 &Event\r
4b738c76
HT
361 );\r
362 if (EFI_ERROR (Status)) {\r
363 goto ON_ERROR;\r
364 }\r
4bad9ada 365\r
366 TcpIo->RxToken.Tcp4Token.CompletionToken.Event = Event;\r
367\r
8322eb77 368 RxData = (EFI_TCP4_RECEIVE_DATA *) AllocateZeroPool (sizeof (EFI_TCP4_RECEIVE_DATA));\r
369 if (RxData == NULL) {\r
370 Status = EFI_OUT_OF_RESOURCES;\r
371 goto ON_ERROR;\r
372 }\r
373\r
374 TcpIo->RxToken.Tcp4Token.Packet.RxData = RxData;\r
375\r
4b738c76
HT
376 Status = gBS->CreateEvent (\r
377 EVT_NOTIFY_SIGNAL,\r
378 TPL_NOTIFY,\r
4bad9ada 379 TcpIoCommonNotify,\r
380 &TcpIo->IsCloseDone,\r
381 &Event\r
4b738c76
HT
382 );\r
383 if (EFI_ERROR (Status)) {\r
384 goto ON_ERROR;\r
385 }\r
4bad9ada 386\r
387 TcpIo->CloseToken.Tcp4Token.CompletionToken.Event = Event;\r
388\r
389\r
390 return EFI_SUCCESS;\r
4b738c76
HT
391\r
392ON_ERROR:\r
4bad9ada 393\r
394 TcpIoDestroySocket (TcpIo);\r
4b738c76 395\r
4bad9ada 396 return Status;\r
397}\r
398 \r
399/**\r
400 Destroy the socket. \r
401\r
402 @param[in] TcpIo The TcpIo which wraps the socket to be destroyed.\r
403\r
404**/\r
405VOID\r
406EFIAPI\r
407TcpIoDestroySocket (\r
408 IN TCP_IO *TcpIo\r
409 )\r
410{\r
411 EFI_EVENT Event;\r
412 EFI_TCP4_PROTOCOL *Tcp4;\r
413 EFI_TCP6_PROTOCOL *Tcp6;\r
414 UINT8 TcpVersion;\r
415 EFI_GUID *ServiceBindingGuid;\r
416 EFI_GUID *ProtocolGuid;\r
417 EFI_HANDLE ChildHandle;\r
418\r
419 if (TcpIo == NULL) {\r
420 return ;\r
421 }\r
422\r
423 TcpVersion = TcpIo->TcpVersion;\r
424\r
425 if ((TcpVersion != TCP_VERSION_4) && (TcpVersion != TCP_VERSION_6)) {\r
426 return ;\r
427 }\r
428\r
429 Event = TcpIo->ConnToken.Tcp4Token.CompletionToken.Event;\r
430\r
431 if (Event != NULL) {\r
432 gBS->CloseEvent (Event);\r
433 }\r
434\r
435 Event = TcpIo->ListenToken.Tcp4Token.CompletionToken.Event;\r
436\r
437 if (Event != NULL) {\r
438 gBS->CloseEvent (Event);\r
439 }\r
440\r
441 Event = TcpIo->TxToken.Tcp4Token.CompletionToken.Event;\r
442\r
443 if (Event != NULL) {\r
444 gBS->CloseEvent (Event);\r
445 }\r
446\r
447 Event = TcpIo->RxToken.Tcp4Token.CompletionToken.Event;\r
448\r
449 if (Event != NULL) {\r
450 gBS->CloseEvent (Event);\r
451 }\r
452\r
453 Event = TcpIo->CloseToken.Tcp4Token.CompletionToken.Event;\r
454\r
455 if (Event != NULL) {\r
456 gBS->CloseEvent (Event);\r
457 }\r
458\r
8322eb77 459 if (TcpIo->RxToken.Tcp4Token.Packet.RxData != NULL) {\r
460 FreePool (TcpIo->RxToken.Tcp4Token.Packet.RxData);\r
461 }\r
462\r
4bad9ada 463 Tcp4 = NULL;\r
464 Tcp6 = NULL;\r
465\r
466\r
467 if (TcpVersion == TCP_VERSION_4) {\r
468 ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
469 ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
470 Tcp4 = TcpIo->Tcp.Tcp4;\r
471 if (Tcp4 != NULL) {\r
472 Tcp4->Configure (Tcp4, NULL);\r
473 }\r
474 } else {\r
475 ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
476 ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
477 Tcp6 = TcpIo->Tcp.Tcp6;\r
478 if (Tcp6 != NULL) {\r
479 Tcp6->Configure (Tcp6, NULL);\r
480 }\r
481 }\r
482\r
483 if ((Tcp4 != NULL) || (Tcp6 != NULL)) {\r
484\r
4b738c76 485 gBS->CloseProtocol (\r
4bad9ada 486 TcpIo->Handle,\r
487 ProtocolGuid,\r
488 TcpIo->Image,\r
489 TcpIo->Controller\r
490 );\r
491 }\r
492\r
493 ChildHandle = NULL;\r
494\r
495 if (TcpIo->IsListenDone) {\r
496 if (TcpVersion == TCP_VERSION_4) {\r
497 Tcp4 = TcpIo->NewTcp.Tcp4;\r
498 if (Tcp4 != NULL) {\r
499 Tcp4->Configure (Tcp4, NULL);\r
500 ChildHandle = TcpIo->ListenToken.Tcp4Token.NewChildHandle;\r
501 }\r
502 } else {\r
503 Tcp6 = TcpIo->NewTcp.Tcp6;\r
504 if (Tcp6 != NULL) {\r
505 Tcp6->Configure (Tcp6, NULL);\r
506 ChildHandle = TcpIo->ListenToken.Tcp6Token.NewChildHandle;\r
507 }\r
508 }\r
509\r
510 if (ChildHandle != NULL) {\r
511\r
512 gBS->CloseProtocol (\r
513 ChildHandle,\r
514 ProtocolGuid,\r
515 TcpIo->Image,\r
516 TcpIo->Controller\r
517 );\r
518 }\r
519 }\r
520\r
4b738c76 521 NetLibDestroyServiceChild (\r
4bad9ada 522 TcpIo->Controller,\r
523 TcpIo->Image,\r
524 ServiceBindingGuid,\r
525 TcpIo->Handle\r
526 );\r
527}\r
528\r
529/**\r
530 Connect to the other endpoint of the TCP socket.\r
531\r
532 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.\r
b5035efa 533 @param[in] Timeout The time to wait for connection done. Set to NULL for infinite wait.\r
4bad9ada 534 \r
535 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket\r
536 successfully.\r
537 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the\r
538 TCP socket in the specified time period.\r
539 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
540 @retval EFI_UNSUPPORTED One or more of the control options are not\r
541 supported in the implementation.\r
542 @retval Others Other errors as indicated.\r
543\r
544**/\r
545EFI_STATUS\r
546EFIAPI\r
547TcpIoConnect (\r
548 IN OUT TCP_IO *TcpIo,\r
b5035efa 549 IN EFI_EVENT Timeout OPTIONAL\r
4bad9ada 550 )\r
551{\r
552 EFI_TCP4_PROTOCOL *Tcp4;\r
553 EFI_TCP6_PROTOCOL *Tcp6;\r
554 EFI_STATUS Status;\r
555\r
556 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {\r
557 return EFI_INVALID_PARAMETER;\r
558 }\r
559\r
560 TcpIo->IsConnDone = FALSE;\r
561\r
562 Tcp4 = NULL;\r
563 Tcp6 = NULL;\r
564\r
565 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
566 Tcp4 = TcpIo->Tcp.Tcp4;\r
567 Status = Tcp4->Connect (Tcp4, &TcpIo->ConnToken.Tcp4Token);\r
568 } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
569 Tcp6 = TcpIo->Tcp.Tcp6;\r
570 Status = Tcp6->Connect (Tcp6, &TcpIo->ConnToken.Tcp6Token);\r
571 } else {\r
572 return EFI_UNSUPPORTED;\r
573 }\r
574\r
4b738c76
HT
575 if (EFI_ERROR (Status)) {\r
576 return Status;\r
577 }\r
578\r
b5035efa 579 while (!TcpIo->IsConnDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
4bad9ada 580 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
581 Tcp4->Poll (Tcp4);\r
582 } else {\r
583 Tcp6->Poll (Tcp6);\r
584 }\r
4b738c76
HT
585 }\r
586\r
4bad9ada 587 if (!TcpIo->IsConnDone) {\r
267345ff
FS
588 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
589 Tcp4->Cancel (Tcp4, &TcpIo->ConnToken.Tcp4Token.CompletionToken);\r
590 } else {\r
591 Tcp6->Cancel (Tcp6, &TcpIo->ConnToken.Tcp6Token.CompletionToken);\r
592 }\r
4b738c76 593 Status = EFI_TIMEOUT;\r
4bad9ada 594 } else {\r
595 Status = TcpIo->ConnToken.Tcp4Token.CompletionToken.Status;\r
596 }\r
4b738c76 597\r
4bad9ada 598 return Status;\r
599}\r
600\r
601/**\r
602 Accept the incomding request from the other endpoint of the TCP socket.\r
603\r
604 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.\r
b5035efa 605 @param[in] Timeout The time to wait for connection done. Set to NULL for infinite wait.\r
4bad9ada 606\r
607 \r
608 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket\r
609 successfully.\r
610 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
611 @retval EFI_UNSUPPORTED One or more of the control options are not\r
612 supported in the implementation.\r
613\r
614 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the\r
b5035efa 615 TCP socket in the specified time period.\r
4bad9ada 616 @retval Others Other errors as indicated.\r
617\r
618**/\r
619EFI_STATUS\r
620EFIAPI\r
621TcpIoAccept (\r
622 IN OUT TCP_IO *TcpIo,\r
b5035efa 623 IN EFI_EVENT Timeout OPTIONAL\r
4bad9ada 624 )\r
625{\r
626 EFI_STATUS Status;\r
627 EFI_GUID *ProtocolGuid;\r
628 EFI_TCP4_PROTOCOL *Tcp4;\r
629 EFI_TCP6_PROTOCOL *Tcp6;\r
630\r
631 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {\r
632 return EFI_INVALID_PARAMETER;\r
633 }\r
634\r
635 TcpIo->IsListenDone = FALSE;\r
636\r
637 Tcp4 = NULL;\r
638 Tcp6 = NULL;\r
639\r
640 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
641 Tcp4 = TcpIo->Tcp.Tcp4;\r
642 Status = Tcp4->Accept (Tcp4, &TcpIo->ListenToken.Tcp4Token);\r
643 } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
644 Tcp6 = TcpIo->Tcp.Tcp6;\r
645 Status = Tcp6->Accept (Tcp6, &TcpIo->ListenToken.Tcp6Token);\r
646 } else {\r
647 return EFI_UNSUPPORTED;\r
648 }\r
649\r
4b738c76
HT
650 if (EFI_ERROR (Status)) {\r
651 return Status;\r
4bad9ada 652 }\r
653\r
b5035efa 654 while (!TcpIo->IsListenDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
4bad9ada 655 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
656 Tcp4->Poll (Tcp4);\r
657 } else {\r
658 Tcp6->Poll (Tcp6);\r
659 }\r
4b738c76 660 }\r
4bad9ada 661\r
662 if (!TcpIo->IsListenDone) {\r
267345ff
FS
663 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
664 Tcp4->Cancel (Tcp4, &TcpIo->ListenToken.Tcp4Token.CompletionToken);\r
665 } else {\r
666 Tcp6->Cancel (Tcp6, &TcpIo->ListenToken.Tcp6Token.CompletionToken);\r
667 }\r
4b738c76 668 Status = EFI_TIMEOUT;\r
4bad9ada 669 } else {\r
670 Status = TcpIo->ListenToken.Tcp4Token.CompletionToken.Status;\r
671 }\r
672\r
4b738c76
HT
673 //\r
674 // The new TCP instance handle created for the established connection is \r
675 // in ListenToken.\r
676 //\r
4bad9ada 677 if (!EFI_ERROR (Status)) {\r
678 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
679 ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
680 } else {\r
681 ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
682 }\r
683 \r
4b738c76 684 Status = gBS->OpenProtocol (\r
4bad9ada 685 TcpIo->ListenToken.Tcp4Token.NewChildHandle,\r
686 ProtocolGuid,\r
687 (VOID **) (&TcpIo->NewTcp.Tcp4),\r
688 TcpIo->Image,\r
689 TcpIo->Controller,\r
4b738c76
HT
690 EFI_OPEN_PROTOCOL_BY_DRIVER\r
691 );\r
692\r
693 }\r
4bad9ada 694\r
695 return Status;\r
696}\r
697\r
698/**\r
699 Reset the socket.\r
700\r
701 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.\r
702\r
703**/\r
704VOID\r
705EFIAPI\r
706TcpIoReset (\r
707 IN OUT TCP_IO *TcpIo\r
708 )\r
709{\r
710 EFI_TCP4_PROTOCOL *Tcp4;\r
711 EFI_TCP6_PROTOCOL *Tcp6;\r
712 EFI_STATUS Status;\r
713\r
714 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {\r
715 return ;\r
716 }\r
717\r
718 TcpIo->IsCloseDone = FALSE;\r
719 Tcp4 = NULL;\r
720 Tcp6 = NULL;\r
721\r
722 if (TcpIo->TcpVersion == TCP_VERSION_4) { \r
723 TcpIo->CloseToken.Tcp4Token.AbortOnClose = TRUE;\r
724 Tcp4 = TcpIo->Tcp.Tcp4;\r
725 Status = Tcp4->Close (Tcp4, &TcpIo->CloseToken.Tcp4Token);\r
726 } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
727 TcpIo->CloseToken.Tcp6Token.AbortOnClose = TRUE;\r
728 Tcp6 = TcpIo->Tcp.Tcp6;\r
729 Status = Tcp6->Close (Tcp6, &TcpIo->CloseToken.Tcp6Token);\r
730 } else {\r
731 return ;\r
732 }\r
733\r
4b738c76
HT
734 if (EFI_ERROR (Status)) {\r
735 return ;\r
736 }\r
737\r
4bad9ada 738 while (!TcpIo->IsCloseDone) {\r
739 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
740 Tcp4->Poll (Tcp4);\r
741 } else {\r
742 Tcp6->Poll (Tcp6);\r
743 }\r
744 }\r
745}\r
746\r
747 \r
748/**\r
749 Transmit the Packet to the other endpoint of the socket.\r
750\r
751 @param[in] TcpIo The TcpIo wrapping the TCP socket.\r
752 @param[in] Packet The packet to transmit.\r
753 \r
754 @retval EFI_SUCCESS The packet is trasmitted.\r
755 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
756 @retval EFI_UNSUPPORTED One or more of the control options are not\r
757 supported in the implementation.\r
758 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
759 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
760 @retval Others Other errors as indicated.\r
761\r
762**/\r
763EFI_STATUS\r
764EFIAPI\r
765TcpIoTransmit (\r
766 IN TCP_IO *TcpIo,\r
767 IN NET_BUF *Packet\r
768 )\r
769{\r
770 EFI_STATUS Status;\r
771 VOID *Data;\r
772 EFI_TCP4_PROTOCOL *Tcp4;\r
773 EFI_TCP6_PROTOCOL *Tcp6;\r
774 UINTN Size;\r
775\r
776 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) {\r
777 return EFI_INVALID_PARAMETER;\r
778 }\r
779\r
780 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
781\r
782 Size = sizeof (EFI_TCP4_TRANSMIT_DATA) + \r
783 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);\r
784 } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
785 Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +\r
786 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);\r
787 } else {\r
788 return EFI_UNSUPPORTED;\r
789 }\r
790\r
791 Data = AllocatePool (Size);\r
792 if (Data == NULL) {\r
4b738c76 793 return EFI_OUT_OF_RESOURCES;\r
4bad9ada 794 }\r
795\r
796 ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push = TRUE;\r
797 ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent = FALSE;\r
798 ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;\r
799\r
4b738c76
HT
800 //\r
801 // Build the fragment table.\r
802 //\r
4bad9ada 803 ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;\r
804\r
805 NetbufBuildExt (\r
806 Packet,\r
807 (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],\r
808 &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount\r
809 );\r
810\r
811 Tcp4 = NULL;\r
812 Tcp6 = NULL;\r
813 Status = EFI_DEVICE_ERROR;\r
814\r
4b738c76
HT
815 //\r
816 // Trasnmit the packet.\r
4bad9ada 817 //\r
818 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
819 TcpIo->TxToken.Tcp4Token.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;\r
820 Tcp4 = TcpIo->Tcp.Tcp4;\r
821 if (TcpIo->IsListenDone) {\r
822 Tcp4 = TcpIo->NewTcp.Tcp4;\r
823 }\r
824\r
825 if (Tcp4 == NULL) {\r
826 goto ON_EXIT;\r
827 }\r
828 \r
829 Status = Tcp4->Transmit (Tcp4, &TcpIo->TxToken.Tcp4Token);\r
830 } else {\r
831 TcpIo->TxToken.Tcp6Token.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;\r
832 Tcp6 = TcpIo->Tcp.Tcp6;\r
833 if (TcpIo->IsListenDone) {\r
834 Tcp6 = TcpIo->NewTcp.Tcp6;\r
835 }\r
836\r
837 if (Tcp6 == NULL) {\r
838 goto ON_EXIT;\r
839 }\r
840\r
841 Status = Tcp6->Transmit (Tcp6, &TcpIo->TxToken.Tcp6Token);\r
842 }\r
843\r
4b738c76
HT
844 if (EFI_ERROR (Status)) {\r
845 goto ON_EXIT;\r
846 }\r
847\r
4bad9ada 848 while (!TcpIo->IsTxDone) {\r
849 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
850 Tcp4->Poll (Tcp4);\r
851 } else {\r
852 Tcp6->Poll (Tcp6);\r
853 }\r
4b738c76
HT
854 }\r
855\r
4bad9ada 856 TcpIo->IsTxDone = FALSE;\r
857 Status = TcpIo->TxToken.Tcp4Token.CompletionToken.Status;\r
858\r
4b738c76
HT
859ON_EXIT:\r
860\r
4bad9ada 861 FreePool (Data);\r
4b738c76 862\r
4bad9ada 863 return Status;\r
864}\r
865\r
866/**\r
867 Receive data from the socket.\r
868\r
869 @param[in, out] TcpIo The TcpIo which wraps the socket to be destroyed.\r
870 @param[in] Packet The buffer to hold the data copy from the socket rx buffer.\r
871 @param[in] AsyncMode Is this receive asyncronous or not.\r
872 @param[in] Timeout The time to wait for receiving the amount of data the Packet\r
b5035efa 873 can hold. Set to NULL for infinite wait.\r
4bad9ada 874\r
875 @retval EFI_SUCCESS The required amount of data is received from the socket.\r
876 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
877 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
878 @retval EFI_OUT_OF_RESOURCES Failed to allocate momery.\r
879 @retval EFI_TIMEOUT Failed to receive the required amount of data in the\r
880 specified time period.\r
881 @retval Others Other errors as indicated.\r
882\r
883**/\r
884EFI_STATUS\r
885EFIAPI\r
886TcpIoReceive (\r
887 IN OUT TCP_IO *TcpIo,\r
888 IN NET_BUF *Packet,\r
889 IN BOOLEAN AsyncMode,\r
b5035efa 890 IN EFI_EVENT Timeout OPTIONAL\r
4bad9ada 891 )\r
892{\r
893 EFI_TCP4_PROTOCOL *Tcp4;\r
894 EFI_TCP6_PROTOCOL *Tcp6;\r
8322eb77 895 EFI_TCP4_RECEIVE_DATA *RxData;\r
4bad9ada 896 EFI_STATUS Status;\r
897 NET_FRAGMENT *Fragment;\r
898 UINT32 FragmentCount;\r
899 UINT32 CurrentFragment;\r
900\r
901 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) {\r
902 return EFI_INVALID_PARAMETER;\r
903 }\r
904\r
8322eb77 905 RxData = TcpIo->RxToken.Tcp4Token.Packet.RxData;\r
906 if (RxData == NULL) {\r
907 return EFI_INVALID_PARAMETER;\r
908 }\r
909\r
4bad9ada 910 Tcp4 = NULL;\r
911 Tcp6 = NULL;\r
912\r
913 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
4bad9ada 914 Tcp4 = TcpIo->Tcp.Tcp4;\r
915\r
916 if (TcpIo->IsListenDone) {\r
917 Tcp4 = TcpIo->NewTcp.Tcp4;\r
918 }\r
919\r
920 if (Tcp4 == NULL) {\r
921 return EFI_DEVICE_ERROR;\r
922 }\r
923\r
924 } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
4bad9ada 925 Tcp6 = TcpIo->Tcp.Tcp6;\r
926\r
927 if (TcpIo->IsListenDone) {\r
928 Tcp6 = TcpIo->NewTcp.Tcp6;\r
929 }\r
930\r
931 if (Tcp6 == NULL) {\r
932 return EFI_DEVICE_ERROR; \r
933 }\r
934\r
935 } else {\r
936 return EFI_UNSUPPORTED;\r
937 }\r
938\r
4b738c76
HT
939 FragmentCount = Packet->BlockOpNum;\r
940 Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));\r
ec50ecf2
ED
941 if (Fragment == NULL) {\r
942 Status = EFI_OUT_OF_RESOURCES;\r
943 goto ON_EXIT;\r
4b738c76
HT
944 }\r
945 //\r
946 // Build the fragment table.\r
947 //\r
948 NetbufBuildExt (Packet, Fragment, &FragmentCount);\r
4bad9ada 949\r
8322eb77 950 RxData->FragmentCount = 1;\r
4bad9ada 951 CurrentFragment = 0;\r
4b738c76
HT
952 Status = EFI_SUCCESS;\r
953\r
954 while (CurrentFragment < FragmentCount) {\r
8322eb77 955 RxData->DataLength = Fragment[CurrentFragment].Len;\r
956 RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;\r
957 RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;\r
4bad9ada 958\r
959 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
960 Status = Tcp4->Receive (Tcp4, &TcpIo->RxToken.Tcp4Token);\r
961 } else {\r
962 Status = Tcp6->Receive (Tcp6, &TcpIo->RxToken.Tcp6Token);\r
963 }\r
964 \r
4b738c76
HT
965 if (EFI_ERROR (Status)) {\r
966 goto ON_EXIT;\r
967 }\r
4bad9ada 968 \r
969 while (!TcpIo->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
970 //\r
971 // Poll until some data is received or an error occurs.\r
972 //\r
973 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
974 Tcp4->Poll (Tcp4);\r
975 } else {\r
976 Tcp6->Poll (Tcp6);\r
977 }\r
978 }\r
4b738c76 979\r
4bad9ada 980 if (!TcpIo->IsRxDone) {\r
4b738c76
HT
981 //\r
982 // Timeout occurs, cancel the receive request.\r
983 //\r
4bad9ada 984 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
985 Tcp4->Cancel (Tcp4, &TcpIo->RxToken.Tcp4Token.CompletionToken);\r
986 } else {\r
987 Tcp6->Cancel (Tcp6, &TcpIo->RxToken.Tcp6Token.CompletionToken);\r
988 }\r
4b738c76
HT
989\r
990 Status = EFI_TIMEOUT;\r
991 goto ON_EXIT;\r
992 } else {\r
4bad9ada 993 TcpIo->IsRxDone = FALSE;\r
994 }\r
995\r
996 Status = TcpIo->RxToken.Tcp4Token.CompletionToken.Status;\r
997\r
998 if (EFI_ERROR (Status)) {\r
4b738c76
HT
999 goto ON_EXIT;\r
1000 }\r
1001\r
8322eb77 1002 Fragment[CurrentFragment].Len -= RxData->FragmentTable[0].FragmentLength;\r
4b738c76
HT
1003 if (Fragment[CurrentFragment].Len == 0) {\r
1004 CurrentFragment++;\r
1005 } else {\r
8322eb77 1006 Fragment[CurrentFragment].Bulk += RxData->FragmentTable[0].FragmentLength;\r
4b738c76
HT
1007 }\r
1008 }\r
1009\r
1010ON_EXIT:\r
4bad9ada 1011\r
ec50ecf2
ED
1012 if (Fragment != NULL) {\r
1013 FreePool (Fragment);\r
1014 }\r
4b738c76 1015\r
4bad9ada 1016 return Status;\r
1017}\r