]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/TcpDxe/TcpDriver.c
4e697b1f4e4fbeff434d3113a163e75f0989e11e
[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 - 2012, 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 TcpDestroyChildEntryInHandleBuffer (
346 IN LIST_ENTRY *Entry,
347 IN VOID *Context
348 )
349 {
350 SOCKET *Sock;
351 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
352 UINTN NumberOfChildren;
353 EFI_HANDLE *ChildHandleBuffer;
354
355 if (Entry == NULL || Context == NULL) {
356 return EFI_INVALID_PARAMETER;
357 }
358
359 Sock = NET_LIST_USER_STRUCT_S (Entry, SOCKET, Link, SOCK_SIGNATURE);
360 ServiceBinding = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
361 NumberOfChildren = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
362 ChildHandleBuffer = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
363
364 if (!NetIsInHandleBuffer (Sock->SockHandle, NumberOfChildren, ChildHandleBuffer)) {
365 return EFI_SUCCESS;
366 }
367
368 return ServiceBinding->DestroyChild (ServiceBinding, Sock->SockHandle);
369 }
370
371 /**
372 Destroy a TCP6 or TCP4 service binding instance. It will release all
373 the resources allocated by the instance.
374
375 @param[in] Controller Controller handle of device to bind driver to.
376 @param[in] ImageHandle The TCP driver's image handle.
377 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number
378 of children is zero stop the entire bus driver.
379 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
380 if NumberOfChildren is 0.
381 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6
382
383 @retval EFI_SUCCESS The resources used by the instance were cleaned up.
384 @retval Others Failed to clean up some of the resources.
385
386 **/
387 EFI_STATUS
388 TcpDestroyService (
389 IN EFI_HANDLE Controller,
390 IN EFI_HANDLE ImageHandle,
391 IN UINTN NumberOfChildren,
392 IN EFI_HANDLE *ChildHandleBuffer, OPTIONAL
393 IN UINT8 IpVersion
394 )
395 {
396 EFI_HANDLE NicHandle;
397 EFI_GUID *IpProtocolGuid;
398 EFI_GUID *ServiceBindingGuid;
399 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
400 TCP_SERVICE_DATA *TcpServiceData;
401 EFI_STATUS Status;
402 LIST_ENTRY *List;
403 TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
404
405 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
406
407 if (IpVersion == IP_VERSION_4) {
408 IpProtocolGuid = &gEfiIp4ProtocolGuid;
409 ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
410 } else {
411 IpProtocolGuid = &gEfiIp6ProtocolGuid;
412 ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
413 }
414
415 NicHandle = NetLibGetNicHandle (Controller, IpProtocolGuid);
416 if (NicHandle == NULL) {
417 return EFI_SUCCESS;
418 }
419
420 Status = gBS->OpenProtocol (
421 NicHandle,
422 ServiceBindingGuid,
423 (VOID **) &ServiceBinding,
424 ImageHandle,
425 Controller,
426 EFI_OPEN_PROTOCOL_GET_PROTOCOL
427 );
428 if (EFI_ERROR (Status)) {
429 return EFI_DEVICE_ERROR;
430 }
431
432 TcpServiceData = TCP_SERVICE_FROM_THIS (ServiceBinding);
433
434 if (NumberOfChildren != 0) {
435 List = &TcpServiceData->SocketList;
436 Context.ServiceBinding = ServiceBinding;
437 Context.NumberOfChildren = NumberOfChildren;
438 Context.ChildHandleBuffer = ChildHandleBuffer;
439 Status = NetDestroyLinkList (
440 List,
441 TcpDestroyChildEntryInHandleBuffer,
442 &Context,
443 NULL
444 );
445 } else if (IsListEmpty (&TcpServiceData->SocketList)) {
446 //
447 // Uninstall TCP servicebinding protocol
448 //
449 gBS->UninstallMultipleProtocolInterfaces (
450 NicHandle,
451 ServiceBindingGuid,
452 ServiceBinding,
453 NULL
454 );
455
456 //
457 // Destroy the IpIO consumed by TCP driver
458 //
459 IpIoDestroy (TcpServiceData->IpIo);
460 TcpServiceData->IpIo = NULL;
461
462 //
463 // Destroy the heartbeat timer.
464 //
465 TcpDestroyTimer ();
466
467 //
468 // Clear the variable.
469 //
470 TcpClearVariableData (TcpServiceData);
471
472 //
473 // Release the TCP service data
474 //
475 FreePool (TcpServiceData);
476
477 Status = EFI_SUCCESS;
478 }
479
480 return Status;
481 }
482
483 /**
484 Test to see if this driver supports ControllerHandle.
485
486 @param[in] This Protocol instance pointer.
487 @param[in] ControllerHandle Handle of device to test.
488 @param[in] RemainingDevicePath Optional parameter use to pick a specific
489 child device to start.
490
491 @retval EFI_SUCCESS This driver supports this device.
492 @retval EFI_ALREADY_STARTED This driver is already running on this device.
493 @retval other This driver does not support this device.
494
495 **/
496 EFI_STATUS
497 EFIAPI
498 TcpDriverBindingSupported (
499 IN EFI_DRIVER_BINDING_PROTOCOL *This,
500 IN EFI_HANDLE ControllerHandle,
501 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
502 )
503 {
504 EFI_STATUS Status;
505 BOOLEAN IsTcp4Started;
506
507 //
508 // Test for the Tcp4ServiceBinding Protocol
509 //
510 Status = gBS->OpenProtocol (
511 ControllerHandle,
512 &gEfiTcp4ServiceBindingProtocolGuid,
513 NULL,
514 This->DriverBindingHandle,
515 ControllerHandle,
516 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
517 );
518 if (EFI_ERROR (Status)) {
519 //
520 // Test for the Ip4ServiceBinding Protocol
521 //
522 Status = gBS->OpenProtocol (
523 ControllerHandle,
524 &gEfiIp4ServiceBindingProtocolGuid,
525 NULL,
526 This->DriverBindingHandle,
527 ControllerHandle,
528 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
529 );
530 if (!EFI_ERROR (Status)) {
531 return EFI_SUCCESS;
532 }
533
534 IsTcp4Started = FALSE;
535 } else {
536 IsTcp4Started = TRUE;
537 }
538
539 //
540 // Check the Tcp6ServiceBinding Protocol
541 //
542 Status = gBS->OpenProtocol (
543 ControllerHandle,
544 &gEfiTcp6ServiceBindingProtocolGuid,
545 NULL,
546 This->DriverBindingHandle,
547 ControllerHandle,
548 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
549 );
550 if (EFI_ERROR (Status)) {
551 //
552 // Test for the Ip6ServiceBinding Protocol
553 //
554 Status = gBS->OpenProtocol (
555 ControllerHandle,
556 &gEfiIp6ServiceBindingProtocolGuid,
557 NULL,
558 This->DriverBindingHandle,
559 ControllerHandle,
560 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
561 );
562 if (!EFI_ERROR (Status)) {
563 return EFI_SUCCESS;
564 }
565 } else if (IsTcp4Started) {
566 return EFI_ALREADY_STARTED;
567 }
568
569 return EFI_UNSUPPORTED;
570 }
571
572 /**
573 Start this driver on ControllerHandle.
574
575 @param[in] This Protocol instance pointer.
576 @param[in] ControllerHandle Handle of device to bind driver to.
577 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
578 device to start.
579
580 @retval EFI_SUCCESS The driver is added to ControllerHandle.
581 @retval EFI_OUT_OF_RESOURCES There are not enough resources to start the
582 driver.
583 @retval other The driver cannot be added to ControllerHandle.
584
585 **/
586 EFI_STATUS
587 EFIAPI
588 TcpDriverBindingStart (
589 IN EFI_DRIVER_BINDING_PROTOCOL *This,
590 IN EFI_HANDLE ControllerHandle,
591 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
592 )
593 {
594 EFI_STATUS Tcp4Status;
595 EFI_STATUS Tcp6Status;
596
597 Tcp4Status = TcpCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_4);
598 if ((Tcp4Status == EFI_ALREADY_STARTED) || (Tcp4Status == EFI_UNSUPPORTED)) {
599 Tcp4Status = EFI_SUCCESS;
600 }
601
602 Tcp6Status = TcpCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_6);
603 if ((Tcp6Status == EFI_ALREADY_STARTED) || (Tcp6Status == EFI_UNSUPPORTED)) {
604 Tcp6Status = EFI_SUCCESS;
605 }
606
607 if (!EFI_ERROR (Tcp4Status) || !EFI_ERROR (Tcp6Status)) {
608 return EFI_SUCCESS;
609 } else if (EFI_ERROR (Tcp4Status)) {
610 return Tcp4Status;
611 } else {
612 return Tcp6Status;
613 }
614 }
615
616 /**
617 Stop this driver on ControllerHandle.
618
619 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
620 @param[in] ControllerHandle A handle to the device being stopped. The handle must
621 support a bus specific I/O protocol for the driver
622 to use to stop the device.
623 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
624 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
625 if NumberOfChildren is 0.
626
627 @retval EFI_SUCCESS The device was stopped.
628 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
629
630 **/
631 EFI_STATUS
632 EFIAPI
633 TcpDriverBindingStop (
634 IN EFI_DRIVER_BINDING_PROTOCOL *This,
635 IN EFI_HANDLE ControllerHandle,
636 IN UINTN NumberOfChildren,
637 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
638 )
639 {
640 EFI_STATUS Tcp4Status;
641 EFI_STATUS Tcp6Status;
642
643 Tcp4Status = TcpDestroyService (
644 ControllerHandle,
645 This->DriverBindingHandle,
646 NumberOfChildren,
647 ChildHandleBuffer,
648 IP_VERSION_4
649 );
650
651 Tcp6Status = TcpDestroyService (
652 ControllerHandle,
653 This->DriverBindingHandle,
654 NumberOfChildren,
655 ChildHandleBuffer,
656 IP_VERSION_6
657 );
658
659 if (EFI_ERROR (Tcp4Status) && EFI_ERROR (Tcp6Status)) {
660 return EFI_DEVICE_ERROR;
661 } else {
662 return EFI_SUCCESS;
663 }
664 }
665
666 /**
667 The Callback funtion called after the TCP socket was created.
668
669 @param[in] This Pointer to the socket just created
670 @param[in] Context Context of the socket
671
672 @retval EFI_SUCCESS This protocol installed successfully.
673 @retval other An error occured.
674
675 **/
676 EFI_STATUS
677 TcpCreateSocketCallback (
678 IN SOCKET *This,
679 IN VOID *Context
680 )
681 {
682 EFI_STATUS Status;
683 TCP_SERVICE_DATA *TcpServiceData;
684 EFI_GUID *IpProtocolGuid;
685 VOID *Ip;
686
687 if (This->IpVersion == IP_VERSION_4) {
688 IpProtocolGuid = &gEfiIp4ProtocolGuid;
689 } else {
690 IpProtocolGuid = &gEfiIp6ProtocolGuid;
691 }
692
693 TcpServiceData = ((TCP_PROTO_DATA *) This->ProtoReserved)->TcpService;
694
695 //
696 // Open the default IP protocol of IP_IO BY_DRIVER.
697 //
698 Status = gBS->OpenProtocol (
699 TcpServiceData->IpIo->ChildHandle,
700 IpProtocolGuid,
701 &Ip,
702 TcpServiceData->DriverBindingHandle,
703 This->SockHandle,
704 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
705 );
706 if (EFI_ERROR (Status)) {
707 return Status;
708 }
709
710 //
711 // Open the device path on the handle where service binding resides on.
712 //
713 Status = gBS->OpenProtocol (
714 TcpServiceData->ControllerHandle,
715 &gEfiDevicePathProtocolGuid,
716 (VOID **) &This->ParentDevicePath,
717 TcpServiceData->DriverBindingHandle,
718 This->SockHandle,
719 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
720 );
721 if (EFI_ERROR (Status)) {
722 gBS->CloseProtocol (
723 TcpServiceData->IpIo->ChildHandle,
724 IpProtocolGuid,
725 TcpServiceData->DriverBindingHandle,
726 This->SockHandle
727 );
728 } else {
729 //
730 // Insert this socket into the SocketList.
731 //
732 InsertTailList (&TcpServiceData->SocketList, &This->Link);
733 }
734
735 return Status;
736 }
737
738 /**
739 The callback function called before the TCP socket was to be destroyed.
740
741 @param[in] This The TCP socket to be destroyed.
742 @param[in] Context The context of the socket.
743
744 **/
745 VOID
746 TcpDestroySocketCallback (
747 IN SOCKET *This,
748 IN VOID *Context
749 )
750 {
751 TCP_SERVICE_DATA *TcpServiceData;
752 EFI_GUID *IpProtocolGuid;
753
754 if (This->IpVersion == IP_VERSION_4) {
755 IpProtocolGuid = &gEfiIp4ProtocolGuid;
756 } else {
757 IpProtocolGuid = &gEfiIp6ProtocolGuid;
758 }
759
760 TcpServiceData = ((TCP_PROTO_DATA *) This->ProtoReserved)->TcpService;
761
762 //
763 // Remove this node from the list.
764 //
765 RemoveEntryList (&This->Link);
766
767 //
768 // Close the device path protocol
769 //
770 gBS->CloseProtocol (
771 TcpServiceData->ControllerHandle,
772 &gEfiDevicePathProtocolGuid,
773 TcpServiceData->DriverBindingHandle,
774 This->SockHandle
775 );
776
777 //
778 // Close the IP protocol.
779 //
780 gBS->CloseProtocol (
781 TcpServiceData->IpIo->ChildHandle,
782 IpProtocolGuid,
783 TcpServiceData->DriverBindingHandle,
784 This->SockHandle
785 );
786 }
787
788 /**
789 Creates a child handle with a set of TCP services.
790
791 The CreateChild() function installs a protocol on ChildHandle.
792 If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
793 If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
794
795 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
796 @param[in, out] ChildHandle Pointer to the handle of the child to create.
797 If it is NULL, then a new handle is created.
798 If it is a pointer to an existing UEFI handle,
799 then the protocol is added to the existing UEFI handle.
800
801 @retval EFI_SUCCES The protocol was added to ChildHandle.
802 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
803 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
804 the child.
805 @retval other The child handle was not created.
806
807 **/
808 EFI_STATUS
809 EFIAPI
810 TcpServiceBindingCreateChild (
811 IN EFI_SERVICE_BINDING_PROTOCOL *This,
812 IN OUT EFI_HANDLE *ChildHandle
813 )
814 {
815 SOCKET *Sock;
816 TCP_SERVICE_DATA *TcpServiceData;
817 TCP_PROTO_DATA TcpProto;
818 EFI_STATUS Status;
819 EFI_TPL OldTpl;
820
821 if (NULL == This || NULL == ChildHandle) {
822 return EFI_INVALID_PARAMETER;
823 }
824
825 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
826
827 Status = EFI_SUCCESS;
828 TcpServiceData = TCP_SERVICE_FROM_THIS (This);
829 TcpProto.TcpService = TcpServiceData;
830 TcpProto.TcpPcb = NULL;
831
832 //
833 // Create a tcp instance with defualt Tcp default
834 // sock init data and TcpProto
835 //
836 mTcpDefaultSockData.ProtoData = &TcpProto;
837 mTcpDefaultSockData.DataSize = sizeof (TCP_PROTO_DATA);
838 mTcpDefaultSockData.DriverBinding = TcpServiceData->DriverBindingHandle;
839 mTcpDefaultSockData.IpVersion = TcpServiceData->IpVersion;
840
841 if (TcpServiceData->IpVersion == IP_VERSION_4) {
842 mTcpDefaultSockData.Protocol = &gTcp4ProtocolTemplate;
843 } else {
844 mTcpDefaultSockData.Protocol = &gTcp6ProtocolTemplate;
845 }
846
847 Sock = SockCreateChild (&mTcpDefaultSockData);
848 if (NULL == Sock) {
849 DEBUG (
850 (EFI_D_ERROR,
851 "TcpDriverBindingCreateChild: No resource to create a Tcp Child\n")
852 );
853
854 Status = EFI_OUT_OF_RESOURCES;
855 } else {
856 *ChildHandle = Sock->SockHandle;
857 }
858
859 mTcpDefaultSockData.ProtoData = NULL;
860
861 gBS->RestoreTPL (OldTpl);
862 return Status;
863 }
864
865 /**
866 Destroys a child handle with a set of TCP services.
867
868 The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
869 that was installed by CreateChild() from ChildHandle. If the removed protocol is the
870 last protocol on ChildHandle, then ChildHandle is destroyed.
871
872 @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
873 @param ChildHandle Handle of the child to be destroyed.
874
875 @retval EFI_SUCCES The protocol was removed from ChildHandle.
876 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
877 @retval EFI_INVALID_PARAMETER Child handle is NULL.
878 @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
879 because its services are being used.
880 @retval other The child handle was not destroyed.
881
882 **/
883 EFI_STATUS
884 EFIAPI
885 TcpServiceBindingDestroyChild (
886 IN EFI_SERVICE_BINDING_PROTOCOL *This,
887 IN EFI_HANDLE ChildHandle
888 )
889 {
890 EFI_STATUS Status;
891 VOID *Tcp;
892 SOCKET *Sock;
893
894 if (NULL == This || NULL == ChildHandle) {
895 return EFI_INVALID_PARAMETER;
896 }
897
898 //
899 // retrieve the Tcp4 protocol from ChildHandle
900 //
901 Status = gBS->OpenProtocol (
902 ChildHandle,
903 &gEfiTcp4ProtocolGuid,
904 &Tcp,
905 gTcpDriverBinding.DriverBindingHandle,
906 ChildHandle,
907 EFI_OPEN_PROTOCOL_GET_PROTOCOL
908 );
909 if (EFI_ERROR (Status)) {
910 //
911 // No Tcp4, try the Tcp6 protocol
912 //
913 Status = gBS->OpenProtocol (
914 ChildHandle,
915 &gEfiTcp6ProtocolGuid,
916 &Tcp,
917 gTcpDriverBinding.DriverBindingHandle,
918 ChildHandle,
919 EFI_OPEN_PROTOCOL_GET_PROTOCOL
920 );
921 if (EFI_ERROR (Status)) {
922 Status = EFI_UNSUPPORTED;
923 }
924 }
925
926 if (!EFI_ERROR (Status)) {
927 //
928 // destroy this sock and related Tcp protocol control
929 // block
930 //
931 Sock = SOCK_FROM_THIS (Tcp);
932
933 SockDestroyChild (Sock);
934 }
935
936 return Status;
937 }