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