]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/TcpDxe/TcpDriver.c
Get ParentDevicePath by using attribute EFI_OPEN_PROTOCOL_GET_PROTOCOL instead of...
[mirror_edk2.git] / NetworkPkg / TcpDxe / TcpDriver.c
1 /** @file
2 The driver binding and service binding protocol for the TCP driver.
3
4 Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "TcpMain.h"
17
18 UINT16 mTcp4RandomPort;
19 UINT16 mTcp6RandomPort;
20
21 TCP_HEARTBEAT_TIMER mTcpTimer = {
22 NULL,
23 0
24 };
25
26 EFI_TCP4_PROTOCOL gTcp4ProtocolTemplate = {
27 Tcp4GetModeData,
28 Tcp4Configure,
29 Tcp4Routes,
30 Tcp4Connect,
31 Tcp4Accept,
32 Tcp4Transmit,
33 Tcp4Receive,
34 Tcp4Close,
35 Tcp4Cancel,
36 Tcp4Poll
37 };
38
39 EFI_TCP6_PROTOCOL gTcp6ProtocolTemplate = {
40 Tcp6GetModeData,
41 Tcp6Configure,
42 Tcp6Connect,
43 Tcp6Accept,
44 Tcp6Transmit,
45 Tcp6Receive,
46 Tcp6Close,
47 Tcp6Cancel,
48 Tcp6Poll
49 };
50
51 SOCK_INIT_DATA mTcpDefaultSockData = {
52 SockStream,
53 SO_CLOSED,
54 NULL,
55 TCP_BACKLOG,
56 TCP_SND_BUF_SIZE,
57 TCP_RCV_BUF_SIZE,
58 IP_VERSION_4,
59 NULL,
60 TcpCreateSocketCallback,
61 TcpDestroySocketCallback,
62 NULL,
63 NULL,
64 0,
65 TcpDispatcher,
66 NULL,
67 };
68
69 EFI_DRIVER_BINDING_PROTOCOL gTcpDriverBinding = {
70 TcpDriverBindingSupported,
71 TcpDriverBindingStart,
72 TcpDriverBindingStop,
73 0xa,
74 NULL,
75 NULL
76 };
77
78 EFI_SERVICE_BINDING_PROTOCOL gTcpServiceBinding = {
79 TcpServiceBindingCreateChild,
80 TcpServiceBindingDestroyChild
81 };
82
83
84 /**
85 Create and start the heartbeat timer for the TCP driver.
86
87 @retval EFI_SUCCESS The timer was successfully created and started.
88 @retval other The timer was not created.
89
90 **/
91 EFI_STATUS
92 TcpCreateTimer (
93 VOID
94 )
95 {
96 EFI_STATUS Status;
97
98 Status = EFI_SUCCESS;
99
100 if (mTcpTimer.RefCnt == 0) {
101
102 Status = gBS->CreateEvent (
103 EVT_TIMER | EVT_NOTIFY_SIGNAL,
104 TPL_NOTIFY,
105 TcpTicking,
106 NULL,
107 &mTcpTimer.TimerEvent
108 );
109 if (!EFI_ERROR (Status)) {
110
111 Status = gBS->SetTimer (
112 mTcpTimer.TimerEvent,
113 TimerPeriodic,
114 (UINT64) (TICKS_PER_SECOND / TCP_TICK_HZ)
115 );
116 }
117 }
118
119 if (!EFI_ERROR (Status)) {
120
121 mTcpTimer.RefCnt++;
122 }
123
124 return Status;
125 }
126
127 /**
128 Stop and destroy the heartbeat timer for TCP driver.
129
130 **/
131 VOID
132 TcpDestroyTimer (
133 VOID
134 )
135 {
136 ASSERT (mTcpTimer.RefCnt > 0);
137
138 mTcpTimer.RefCnt--;
139
140 if (mTcpTimer.RefCnt > 0) {
141 return;
142 }
143
144 gBS->SetTimer (mTcpTimer.TimerEvent, TimerCancel, 0);
145 gBS->CloseEvent (mTcpTimer.TimerEvent);
146 mTcpTimer.TimerEvent = NULL;
147 }
148
149 /**
150 The entry point for Tcp driver, which is used to install Tcp driver on the ImageHandle.
151
152 @param[in] ImageHandle The firmware allocated handle for this driver image.
153 @param[in] SystemTable Pointer to the EFI system table.
154
155 @retval EFI_SUCCESS The driver loaded.
156 @retval other The driver did not load.
157
158 **/
159 EFI_STATUS
160 EFIAPI
161 TcpDriverEntryPoint (
162 IN EFI_HANDLE ImageHandle,
163 IN EFI_SYSTEM_TABLE *SystemTable
164 )
165 {
166 EFI_STATUS Status;
167 UINT32 Seed;
168
169 //
170 // Install the TCP Driver Binding Protocol
171 //
172 Status = EfiLibInstallDriverBindingComponentName2 (
173 ImageHandle,
174 SystemTable,
175 &gTcpDriverBinding,
176 ImageHandle,
177 &gTcpComponentName,
178 &gTcpComponentName2
179 );
180 if (EFI_ERROR (Status)) {
181 return Status;
182 }
183
184 //
185 // Initialize ISS and random port.
186 //
187 Seed = NetRandomInitSeed ();
188 mTcpGlobalIss = NET_RANDOM (Seed) % mTcpGlobalIss;
189 mTcp4RandomPort = (UINT16) (TCP_PORT_KNOWN + (NET_RANDOM (Seed) % TCP_PORT_KNOWN));
190 mTcp6RandomPort = mTcp4RandomPort;
191
192 return EFI_SUCCESS;
193 }
194
195 /**
196 Create a new TCP4 or TCP6 driver service binding protocol
197
198 @param[in] Controller Controller handle of device to bind driver to.
199 @param[in] Image The TCP driver's image handle.
200 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
201
202 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
203 @retval EFI_SUCCESS A new IP6 service binding private was created.
204
205 **/
206 EFI_STATUS
207 TcpCreateService (
208 IN EFI_HANDLE Controller,
209 IN EFI_HANDLE Image,
210 IN UINT8 IpVersion
211 )
212 {
213 EFI_STATUS Status;
214 EFI_GUID *IpServiceBindingGuid;
215 EFI_GUID *TcpServiceBindingGuid;
216 TCP_SERVICE_DATA *TcpServiceData;
217 IP_IO_OPEN_DATA OpenData;
218
219 if (IpVersion == IP_VERSION_4) {
220 IpServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;
221 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
222 } else {
223 IpServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;
224 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
225 }
226
227 Status = gBS->OpenProtocol (
228 Controller,
229 TcpServiceBindingGuid,
230 NULL,
231 Image,
232 Controller,
233 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
234 );
235 if (!EFI_ERROR (Status)) {
236 return EFI_ALREADY_STARTED;
237 }
238
239 Status = gBS->OpenProtocol (
240 Controller,
241 IpServiceBindingGuid,
242 NULL,
243 Image,
244 Controller,
245 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
246 );
247 if (EFI_ERROR (Status)) {
248 return EFI_UNSUPPORTED;
249 }
250
251 //
252 // Create the TCP service data.
253 //
254 TcpServiceData = AllocateZeroPool (sizeof (TCP_SERVICE_DATA));
255 if (TcpServiceData == NULL) {
256 return EFI_OUT_OF_RESOURCES;
257 }
258
259 TcpServiceData->Signature = TCP_DRIVER_SIGNATURE;
260 TcpServiceData->ControllerHandle = Controller;
261 TcpServiceData->DriverBindingHandle = Image;
262 TcpServiceData->IpVersion = IpVersion;
263 CopyMem (
264 &TcpServiceData->ServiceBinding,
265 &gTcpServiceBinding,
266 sizeof (EFI_SERVICE_BINDING_PROTOCOL)
267 );
268
269 TcpServiceData->IpIo = IpIoCreate (Image, Controller, IpVersion);
270 if (TcpServiceData->IpIo == NULL) {
271 Status = EFI_OUT_OF_RESOURCES;
272 goto ON_ERROR;
273 }
274
275
276 InitializeListHead (&TcpServiceData->SocketList);
277 ZeroMem (&OpenData, sizeof (IP_IO_OPEN_DATA));
278
279 if (IpVersion == IP_VERSION_4) {
280 CopyMem (
281 &OpenData.IpConfigData.Ip4CfgData,
282 &mIp4IoDefaultIpConfigData,
283 sizeof (EFI_IP4_CONFIG_DATA)
284 );
285 OpenData.IpConfigData.Ip4CfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
286 } else {
287 CopyMem (
288 &OpenData.IpConfigData.Ip6CfgData,
289 &mIp6IoDefaultIpConfigData,
290 sizeof (EFI_IP6_CONFIG_DATA)
291 );
292 OpenData.IpConfigData.Ip6CfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
293 }
294
295 OpenData.PktRcvdNotify = TcpRxCallback;
296 Status = IpIoOpen (TcpServiceData->IpIo, &OpenData);
297 if (EFI_ERROR (Status)) {
298 goto ON_ERROR;
299 }
300
301 Status = TcpCreateTimer ();
302 if (EFI_ERROR (Status)) {
303 goto ON_ERROR;
304 }
305
306 Status = gBS->InstallMultipleProtocolInterfaces (
307 &Controller,
308 TcpServiceBindingGuid,
309 &TcpServiceData->ServiceBinding,
310 NULL
311 );
312 if (EFI_ERROR (Status)) {
313 TcpDestroyTimer ();
314
315 goto ON_ERROR;
316 }
317
318 TcpSetVariableData (TcpServiceData);
319
320 return EFI_SUCCESS;
321
322 ON_ERROR:
323
324 if (TcpServiceData->IpIo != NULL) {
325 IpIoDestroy (TcpServiceData->IpIo);
326 TcpServiceData->IpIo = NULL;
327 }
328
329 FreePool (TcpServiceData);
330
331 return Status;
332 }
333
334 /**
335 Callback function which provided by user to remove one node in NetDestroyLinkList process.
336
337 @param[in] Entry The entry to be removed.
338 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
339
340 @retval EFI_SUCCESS The entry has been removed successfully.
341 @retval Others Fail to remove the entry.
342
343 **/
344 EFI_STATUS
345 EFIAPI
346 TcpDestroyChildEntryInHandleBuffer (
347 IN LIST_ENTRY *Entry,
348 IN VOID *Context
349 )
350 {
351 SOCKET *Sock;
352 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
353 UINTN NumberOfChildren;
354 EFI_HANDLE *ChildHandleBuffer;
355
356 if (Entry == NULL || Context == NULL) {
357 return EFI_INVALID_PARAMETER;
358 }
359
360 Sock = NET_LIST_USER_STRUCT_S (Entry, SOCKET, Link, SOCK_SIGNATURE);
361 ServiceBinding = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
362 NumberOfChildren = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
363 ChildHandleBuffer = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
364
365 if (!NetIsInHandleBuffer (Sock->SockHandle, NumberOfChildren, ChildHandleBuffer)) {
366 return EFI_SUCCESS;
367 }
368
369 return ServiceBinding->DestroyChild (ServiceBinding, Sock->SockHandle);
370 }
371
372 /**
373 Destroy a TCP6 or TCP4 service binding instance. It will release all
374 the resources allocated by the instance.
375
376 @param[in] Controller Controller handle of device to bind driver to.
377 @param[in] ImageHandle The TCP driver's image handle.
378 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number
379 of children is zero stop the entire bus driver.
380 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
381 if NumberOfChildren is 0.
382 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6
383
384 @retval EFI_SUCCESS The resources used by the instance were cleaned up.
385 @retval Others Failed to clean up some of the resources.
386
387 **/
388 EFI_STATUS
389 TcpDestroyService (
390 IN EFI_HANDLE Controller,
391 IN EFI_HANDLE ImageHandle,
392 IN UINTN NumberOfChildren,
393 IN EFI_HANDLE *ChildHandleBuffer, OPTIONAL
394 IN UINT8 IpVersion
395 )
396 {
397 EFI_HANDLE NicHandle;
398 EFI_GUID *IpProtocolGuid;
399 EFI_GUID *ServiceBindingGuid;
400 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
401 TCP_SERVICE_DATA *TcpServiceData;
402 EFI_STATUS Status;
403 LIST_ENTRY *List;
404 TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
405
406 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
407
408 if (IpVersion == IP_VERSION_4) {
409 IpProtocolGuid = &gEfiIp4ProtocolGuid;
410 ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
411 } else {
412 IpProtocolGuid = &gEfiIp6ProtocolGuid;
413 ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
414 }
415
416 NicHandle = NetLibGetNicHandle (Controller, IpProtocolGuid);
417 if (NicHandle == NULL) {
418 return EFI_SUCCESS;
419 }
420
421 Status = gBS->OpenProtocol (
422 NicHandle,
423 ServiceBindingGuid,
424 (VOID **) &ServiceBinding,
425 ImageHandle,
426 Controller,
427 EFI_OPEN_PROTOCOL_GET_PROTOCOL
428 );
429 if (EFI_ERROR (Status)) {
430 return EFI_DEVICE_ERROR;
431 }
432
433 TcpServiceData = TCP_SERVICE_FROM_THIS (ServiceBinding);
434
435 if (NumberOfChildren != 0) {
436 List = &TcpServiceData->SocketList;
437 Context.ServiceBinding = ServiceBinding;
438 Context.NumberOfChildren = NumberOfChildren;
439 Context.ChildHandleBuffer = ChildHandleBuffer;
440 Status = NetDestroyLinkList (
441 List,
442 TcpDestroyChildEntryInHandleBuffer,
443 &Context,
444 NULL
445 );
446 } else if (IsListEmpty (&TcpServiceData->SocketList)) {
447 //
448 // Uninstall TCP servicebinding protocol
449 //
450 gBS->UninstallMultipleProtocolInterfaces (
451 NicHandle,
452 ServiceBindingGuid,
453 ServiceBinding,
454 NULL
455 );
456
457 //
458 // Destroy the IpIO consumed by TCP driver
459 //
460 IpIoDestroy (TcpServiceData->IpIo);
461 TcpServiceData->IpIo = NULL;
462
463 //
464 // Destroy the heartbeat timer.
465 //
466 TcpDestroyTimer ();
467
468 //
469 // Clear the variable.
470 //
471 TcpClearVariableData (TcpServiceData);
472
473 //
474 // Release the TCP service data
475 //
476 FreePool (TcpServiceData);
477
478 Status = EFI_SUCCESS;
479 }
480
481 return Status;
482 }
483
484 /**
485 Test to see if this driver supports ControllerHandle.
486
487 @param[in] This Protocol instance pointer.
488 @param[in] ControllerHandle Handle of device to test.
489 @param[in] RemainingDevicePath Optional parameter use to pick a specific
490 child device to start.
491
492 @retval EFI_SUCCESS This driver supports this device.
493 @retval EFI_ALREADY_STARTED This driver is already running on this device.
494 @retval other This driver does not support this device.
495
496 **/
497 EFI_STATUS
498 EFIAPI
499 TcpDriverBindingSupported (
500 IN EFI_DRIVER_BINDING_PROTOCOL *This,
501 IN EFI_HANDLE ControllerHandle,
502 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
503 )
504 {
505 EFI_STATUS Status;
506 BOOLEAN IsTcp4Started;
507
508 //
509 // Test for the Tcp4ServiceBinding Protocol
510 //
511 Status = gBS->OpenProtocol (
512 ControllerHandle,
513 &gEfiTcp4ServiceBindingProtocolGuid,
514 NULL,
515 This->DriverBindingHandle,
516 ControllerHandle,
517 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
518 );
519 if (EFI_ERROR (Status)) {
520 //
521 // Test for the Ip4ServiceBinding Protocol
522 //
523 Status = gBS->OpenProtocol (
524 ControllerHandle,
525 &gEfiIp4ServiceBindingProtocolGuid,
526 NULL,
527 This->DriverBindingHandle,
528 ControllerHandle,
529 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
530 );
531 if (!EFI_ERROR (Status)) {
532 return EFI_SUCCESS;
533 }
534
535 IsTcp4Started = FALSE;
536 } else {
537 IsTcp4Started = TRUE;
538 }
539
540 //
541 // Check the Tcp6ServiceBinding Protocol
542 //
543 Status = gBS->OpenProtocol (
544 ControllerHandle,
545 &gEfiTcp6ServiceBindingProtocolGuid,
546 NULL,
547 This->DriverBindingHandle,
548 ControllerHandle,
549 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
550 );
551 if (EFI_ERROR (Status)) {
552 //
553 // Test for the Ip6ServiceBinding Protocol
554 //
555 Status = gBS->OpenProtocol (
556 ControllerHandle,
557 &gEfiIp6ServiceBindingProtocolGuid,
558 NULL,
559 This->DriverBindingHandle,
560 ControllerHandle,
561 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
562 );
563 if (!EFI_ERROR (Status)) {
564 return EFI_SUCCESS;
565 }
566 } else if (IsTcp4Started) {
567 return EFI_ALREADY_STARTED;
568 }
569
570 return EFI_UNSUPPORTED;
571 }
572
573 /**
574 Start this driver on ControllerHandle.
575
576 @param[in] This Protocol instance pointer.
577 @param[in] ControllerHandle Handle of device to bind driver to.
578 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
579 device to start.
580
581 @retval EFI_SUCCESS The driver is added to ControllerHandle.
582 @retval EFI_OUT_OF_RESOURCES There are not enough resources to start the
583 driver.
584 @retval other The driver cannot be added to ControllerHandle.
585
586 **/
587 EFI_STATUS
588 EFIAPI
589 TcpDriverBindingStart (
590 IN EFI_DRIVER_BINDING_PROTOCOL *This,
591 IN EFI_HANDLE ControllerHandle,
592 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
593 )
594 {
595 EFI_STATUS Tcp4Status;
596 EFI_STATUS Tcp6Status;
597
598 Tcp4Status = TcpCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_4);
599 if ((Tcp4Status == EFI_ALREADY_STARTED) || (Tcp4Status == EFI_UNSUPPORTED)) {
600 Tcp4Status = EFI_SUCCESS;
601 }
602
603 Tcp6Status = TcpCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_6);
604 if ((Tcp6Status == EFI_ALREADY_STARTED) || (Tcp6Status == EFI_UNSUPPORTED)) {
605 Tcp6Status = EFI_SUCCESS;
606 }
607
608 if (!EFI_ERROR (Tcp4Status) || !EFI_ERROR (Tcp6Status)) {
609 return EFI_SUCCESS;
610 } else if (EFI_ERROR (Tcp4Status)) {
611 return Tcp4Status;
612 } else {
613 return Tcp6Status;
614 }
615 }
616
617 /**
618 Stop this driver on ControllerHandle.
619
620 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
621 @param[in] ControllerHandle A handle to the device being stopped. The handle must
622 support a bus specific I/O protocol for the driver
623 to use to stop the device.
624 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
625 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
626 if NumberOfChildren is 0.
627
628 @retval EFI_SUCCESS The device was stopped.
629 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
630
631 **/
632 EFI_STATUS
633 EFIAPI
634 TcpDriverBindingStop (
635 IN EFI_DRIVER_BINDING_PROTOCOL *This,
636 IN EFI_HANDLE ControllerHandle,
637 IN UINTN NumberOfChildren,
638 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
639 )
640 {
641 EFI_STATUS Tcp4Status;
642 EFI_STATUS Tcp6Status;
643
644 Tcp4Status = TcpDestroyService (
645 ControllerHandle,
646 This->DriverBindingHandle,
647 NumberOfChildren,
648 ChildHandleBuffer,
649 IP_VERSION_4
650 );
651
652 Tcp6Status = TcpDestroyService (
653 ControllerHandle,
654 This->DriverBindingHandle,
655 NumberOfChildren,
656 ChildHandleBuffer,
657 IP_VERSION_6
658 );
659
660 if (EFI_ERROR (Tcp4Status) && EFI_ERROR (Tcp6Status)) {
661 return EFI_DEVICE_ERROR;
662 } else {
663 return EFI_SUCCESS;
664 }
665 }
666
667 /**
668 The Callback funtion called after the TCP socket was created.
669
670 @param[in] This Pointer to the socket just created
671 @param[in] Context Context of the socket
672
673 @retval EFI_SUCCESS This protocol installed successfully.
674 @retval other An error occured.
675
676 **/
677 EFI_STATUS
678 TcpCreateSocketCallback (
679 IN SOCKET *This,
680 IN VOID *Context
681 )
682 {
683 EFI_STATUS Status;
684 TCP_SERVICE_DATA *TcpServiceData;
685 EFI_GUID *IpProtocolGuid;
686 VOID *Ip;
687
688 if (This->IpVersion == IP_VERSION_4) {
689 IpProtocolGuid = &gEfiIp4ProtocolGuid;
690 } else {
691 IpProtocolGuid = &gEfiIp6ProtocolGuid;
692 }
693
694 TcpServiceData = ((TCP_PROTO_DATA *) This->ProtoReserved)->TcpService;
695
696 //
697 // Open the default IP protocol of IP_IO BY_DRIVER.
698 //
699 Status = gBS->OpenProtocol (
700 TcpServiceData->IpIo->ChildHandle,
701 IpProtocolGuid,
702 &Ip,
703 TcpServiceData->DriverBindingHandle,
704 This->SockHandle,
705 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
706 );
707 if (EFI_ERROR (Status)) {
708 return Status;
709 }
710
711 //
712 // Open the device path on the handle where service binding resides on.
713 //
714 Status = gBS->OpenProtocol (
715 TcpServiceData->ControllerHandle,
716 &gEfiDevicePathProtocolGuid,
717 (VOID **) &This->ParentDevicePath,
718 TcpServiceData->DriverBindingHandle,
719 This->SockHandle,
720 EFI_OPEN_PROTOCOL_GET_PROTOCOL
721 );
722 if (EFI_ERROR (Status)) {
723 gBS->CloseProtocol (
724 TcpServiceData->IpIo->ChildHandle,
725 IpProtocolGuid,
726 TcpServiceData->DriverBindingHandle,
727 This->SockHandle
728 );
729 } else {
730 //
731 // Insert this socket into the SocketList.
732 //
733 InsertTailList (&TcpServiceData->SocketList, &This->Link);
734 }
735
736 return Status;
737 }
738
739 /**
740 The callback function called before the TCP socket was to be destroyed.
741
742 @param[in] This The TCP socket to be destroyed.
743 @param[in] Context The context of the socket.
744
745 **/
746 VOID
747 TcpDestroySocketCallback (
748 IN SOCKET *This,
749 IN VOID *Context
750 )
751 {
752 TCP_SERVICE_DATA *TcpServiceData;
753 EFI_GUID *IpProtocolGuid;
754
755 if (This->IpVersion == IP_VERSION_4) {
756 IpProtocolGuid = &gEfiIp4ProtocolGuid;
757 } else {
758 IpProtocolGuid = &gEfiIp6ProtocolGuid;
759 }
760
761 TcpServiceData = ((TCP_PROTO_DATA *) This->ProtoReserved)->TcpService;
762
763 //
764 // Remove this node from the list.
765 //
766 RemoveEntryList (&This->Link);
767
768 //
769 // Close the IP protocol.
770 //
771 gBS->CloseProtocol (
772 TcpServiceData->IpIo->ChildHandle,
773 IpProtocolGuid,
774 TcpServiceData->DriverBindingHandle,
775 This->SockHandle
776 );
777 }
778
779 /**
780 Creates a child handle with a set of TCP services.
781
782 The CreateChild() function installs a protocol on ChildHandle.
783 If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
784 If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
785
786 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
787 @param[in, out] ChildHandle Pointer to the handle of the child to create.
788 If it is NULL, then a new handle is created.
789 If it is a pointer to an existing UEFI handle,
790 then the protocol is added to the existing UEFI handle.
791
792 @retval EFI_SUCCES The protocol was added to ChildHandle.
793 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
794 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
795 the child.
796 @retval other The child handle was not created.
797
798 **/
799 EFI_STATUS
800 EFIAPI
801 TcpServiceBindingCreateChild (
802 IN EFI_SERVICE_BINDING_PROTOCOL *This,
803 IN OUT EFI_HANDLE *ChildHandle
804 )
805 {
806 SOCKET *Sock;
807 TCP_SERVICE_DATA *TcpServiceData;
808 TCP_PROTO_DATA TcpProto;
809 EFI_STATUS Status;
810 EFI_TPL OldTpl;
811
812 if (NULL == This || NULL == ChildHandle) {
813 return EFI_INVALID_PARAMETER;
814 }
815
816 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
817
818 Status = EFI_SUCCESS;
819 TcpServiceData = TCP_SERVICE_FROM_THIS (This);
820 TcpProto.TcpService = TcpServiceData;
821 TcpProto.TcpPcb = NULL;
822
823 //
824 // Create a tcp instance with defualt Tcp default
825 // sock init data and TcpProto
826 //
827 mTcpDefaultSockData.ProtoData = &TcpProto;
828 mTcpDefaultSockData.DataSize = sizeof (TCP_PROTO_DATA);
829 mTcpDefaultSockData.DriverBinding = TcpServiceData->DriverBindingHandle;
830 mTcpDefaultSockData.IpVersion = TcpServiceData->IpVersion;
831
832 if (TcpServiceData->IpVersion == IP_VERSION_4) {
833 mTcpDefaultSockData.Protocol = &gTcp4ProtocolTemplate;
834 } else {
835 mTcpDefaultSockData.Protocol = &gTcp6ProtocolTemplate;
836 }
837
838 Sock = SockCreateChild (&mTcpDefaultSockData);
839 if (NULL == Sock) {
840 DEBUG (
841 (EFI_D_ERROR,
842 "TcpDriverBindingCreateChild: No resource to create a Tcp Child\n")
843 );
844
845 Status = EFI_OUT_OF_RESOURCES;
846 } else {
847 *ChildHandle = Sock->SockHandle;
848 }
849
850 mTcpDefaultSockData.ProtoData = NULL;
851
852 gBS->RestoreTPL (OldTpl);
853 return Status;
854 }
855
856 /**
857 Destroys a child handle with a set of TCP services.
858
859 The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
860 that was installed by CreateChild() from ChildHandle. If the removed protocol is the
861 last protocol on ChildHandle, then ChildHandle is destroyed.
862
863 @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
864 @param ChildHandle Handle of the child to be destroyed.
865
866 @retval EFI_SUCCES The protocol was removed from ChildHandle.
867 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
868 @retval EFI_INVALID_PARAMETER Child handle is NULL.
869 @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
870 because its services are being used.
871 @retval other The child handle was not destroyed.
872
873 **/
874 EFI_STATUS
875 EFIAPI
876 TcpServiceBindingDestroyChild (
877 IN EFI_SERVICE_BINDING_PROTOCOL *This,
878 IN EFI_HANDLE ChildHandle
879 )
880 {
881 EFI_STATUS Status;
882 VOID *Tcp;
883 SOCKET *Sock;
884
885 if (NULL == This || NULL == ChildHandle) {
886 return EFI_INVALID_PARAMETER;
887 }
888
889 //
890 // retrieve the Tcp4 protocol from ChildHandle
891 //
892 Status = gBS->OpenProtocol (
893 ChildHandle,
894 &gEfiTcp4ProtocolGuid,
895 &Tcp,
896 gTcpDriverBinding.DriverBindingHandle,
897 ChildHandle,
898 EFI_OPEN_PROTOCOL_GET_PROTOCOL
899 );
900 if (EFI_ERROR (Status)) {
901 //
902 // No Tcp4, try the Tcp6 protocol
903 //
904 Status = gBS->OpenProtocol (
905 ChildHandle,
906 &gEfiTcp6ProtocolGuid,
907 &Tcp,
908 gTcpDriverBinding.DriverBindingHandle,
909 ChildHandle,
910 EFI_OPEN_PROTOCOL_GET_PROTOCOL
911 );
912 if (EFI_ERROR (Status)) {
913 Status = EFI_UNSUPPORTED;
914 }
915 }
916
917 if (!EFI_ERROR (Status)) {
918 //
919 // destroy this sock and related Tcp protocol control
920 // block
921 //
922 Sock = SOCK_FROM_THIS (Tcp);
923
924 SockDestroyChild (Sock);
925 }
926
927 return Status;
928 }