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