e2a78b7a9dd25c229e6c1202435caf7c587f7a24
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Driver.c
1 /** @file\r
2 \r
3 Copyright (c) 2005 - 2007, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   Tcp4Driver.c\r
15 \r
16 Abstract:\r
17 \r
18 \r
19 **/\r
20 \r
21 #include "Tcp4Main.h"\r
22 \r
23 \r
24 UINT16                               mTcp4RandomPort;\r
25 extern EFI_COMPONENT_NAME_PROTOCOL    gTcp4ComponentName;\r
26 extern EFI_COMPONENT_NAME2_PROTOCOL   gTcp4ComponentName2;\r
27 \r
28 TCP4_HEARTBEAT_TIMER  mTcp4Timer = {\r
29   NULL,\r
30   0\r
31 };\r
32 \r
33 EFI_TCP4_PROTOCOL mTcp4ProtocolTemplate = {\r
34   Tcp4GetModeData,\r
35   Tcp4Configure,\r
36   Tcp4Routes,\r
37   Tcp4Connect,\r
38   Tcp4Accept,\r
39   Tcp4Transmit,\r
40   Tcp4Receive,\r
41   Tcp4Close,\r
42   Tcp4Cancel,\r
43   Tcp4Poll\r
44 };\r
45 \r
46 SOCK_INIT_DATA mTcp4DefaultSockData = {\r
47   SOCK_STREAM,\r
48   (SOCK_STATE) 0,\r
49   NULL,\r
50   TCP_BACKLOG,\r
51   TCP_SND_BUF_SIZE,\r
52   TCP_RCV_BUF_SIZE,\r
53   &mTcp4ProtocolTemplate,\r
54   Tcp4Dispatcher,\r
55   NULL,\r
56 };\r
57 \r
58 EFI_DRIVER_BINDING_PROTOCOL mTcp4DriverBinding = {\r
59   Tcp4DriverBindingSupported,\r
60   Tcp4DriverBindingStart,\r
61   Tcp4DriverBindingStop,\r
62   0xa,\r
63   NULL,\r
64   NULL\r
65 };\r
66 \r
67 EFI_SERVICE_BINDING_PROTOCOL mTcp4ServiceBinding = {\r
68   Tcp4ServiceBindingCreateChild,\r
69   Tcp4ServiceBindingDestroyChild\r
70 };\r
71 \r
72 \r
73 /**\r
74   Create and start the heartbeat timer for TCP driver.\r
75 \r
76   None.\r
77 \r
78   @retval EFI_SUCCESS            The timer is successfully created and started.\r
79   @retval other                  The timer is not created.\r
80 \r
81 **/\r
82 STATIC\r
83 EFI_STATUS\r
84 Tcp4CreateTimer (\r
85   VOID\r
86   )\r
87 {\r
88   EFI_STATUS  Status;\r
89 \r
90   Status = EFI_SUCCESS;\r
91 \r
92   if (mTcp4Timer.RefCnt == 0) {\r
93 \r
94     Status = gBS->CreateEvent (\r
95                     EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
96                     NET_TPL_EVENT,\r
97                     TcpTicking,\r
98                     NULL,\r
99                     &mTcp4Timer.TimerEvent\r
100                     );\r
101     if (!EFI_ERROR (Status)) {\r
102 \r
103       Status = gBS->SetTimer (\r
104                       mTcp4Timer.TimerEvent,\r
105                       TimerPeriodic,\r
106                       (UINT64) (TICKS_PER_SECOND / TCP_TICK_HZ)\r
107                       );\r
108     }\r
109   }\r
110 \r
111   if (!EFI_ERROR (Status)) {\r
112 \r
113     mTcp4Timer.RefCnt++;\r
114   }\r
115 \r
116   return Status;\r
117 }\r
118 \r
119 \r
120 /**\r
121   Stop and destroy the heartbeat timer for TCP driver.\r
122 \r
123   None.\r
124 \r
125   @return None.\r
126 \r
127 **/\r
128 STATIC\r
129 VOID\r
130 Tcp4DestroyTimer (\r
131   VOID\r
132   )\r
133 {\r
134   ASSERT (mTcp4Timer.RefCnt > 0);\r
135 \r
136   mTcp4Timer.RefCnt--;\r
137 \r
138   if (mTcp4Timer.RefCnt > 0) {\r
139     return;\r
140   }\r
141 \r
142   gBS->SetTimer (mTcp4Timer.TimerEvent, TimerCancel, 0);\r
143   gBS->CloseEvent (mTcp4Timer.TimerEvent);\r
144   mTcp4Timer.TimerEvent = NULL;\r
145 }\r
146 \r
147 \r
148 EFI_STATUS\r
149 EFIAPI\r
150 Tcp4DriverEntryPoint (\r
151   IN EFI_HANDLE        ImageHandle,\r
152   IN EFI_SYSTEM_TABLE  *SystemTable\r
153   )\r
154 /*++\r
155 \r
156 Routine Description:\r
157 \r
158   The entry point for Tcp4 driver. used to install\r
159   Tcp4 driver on the ImageHandle.\r
160 \r
161 Arguments:\r
162 \r
163   ImageHandle - The firmware allocated handle for this\r
164                 driver image.\r
165   SystemTable - Pointer to the EFI system table.\r
166 \r
167 Returns:\r
168 \r
169   EFI_SUCCESS - Driver loaded.\r
170   other       - Driver not loaded.\r
171 \r
172 --*/\r
173 {\r
174   EFI_STATUS  Status;\r
175   UINT32      Seed;\r
176 \r
177   //\r
178   // Install the TCP4 Driver Binding Protocol\r
179   //\r
180   Status = EfiLibInstallDriverBindingComponentName2 (\r
181              ImageHandle,\r
182              SystemTable,\r
183              &mTcp4DriverBinding,\r
184              ImageHandle,\r
185              &gTcp4ComponentName,\r
186              &gTcp4ComponentName2\r
187              );\r
188   ASSERT_EFI_ERROR (Status);\r
189   //\r
190   // Initialize ISS and random port.\r
191   //\r
192   Seed            = NetRandomInitSeed ();\r
193   mTcpGlobalIss   = NET_RANDOM (Seed) % mTcpGlobalIss;\r
194   mTcp4RandomPort = (UINT16) ( TCP4_PORT_KNOWN +\r
195                     (UINT16) (NET_RANDOM(Seed) % TCP4_PORT_KNOWN));\r
196 \r
197   return Status;\r
198 }\r
199 \r
200 \r
201 /**\r
202   Test to see if this driver supports ControllerHandle.\r
203 \r
204   @param  This                   Protocol instance pointer.\r
205   @param  ControllerHandle       Handle of device to test.\r
206   @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
207                                  device to start.\r
208 \r
209   @retval EFI_SUCCESS            This driver supports this device.\r
210   @retval EFI_ALREADY_STARTED    This driver is already running on this device.\r
211   @retval other                  This driver does not support this device.\r
212 \r
213 **/\r
214 EFI_STATUS\r
215 EFIAPI\r
216 Tcp4DriverBindingSupported (\r
217   IN EFI_DRIVER_BINDING_PROTOCOL  * This,\r
218   IN EFI_HANDLE                   ControllerHandle,\r
219   IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL\r
220   )\r
221 {\r
222   EFI_STATUS  Status;\r
223 \r
224   //\r
225   // Test for the Tcp4ServiceBinding Protocol\r
226   //\r
227   Status = gBS->OpenProtocol (\r
228                   ControllerHandle,\r
229                   &gEfiTcp4ServiceBindingProtocolGuid,\r
230                   NULL,\r
231                   This->DriverBindingHandle,\r
232                   ControllerHandle,\r
233                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
234                   );\r
235   if (!EFI_ERROR (Status)) {\r
236     return EFI_ALREADY_STARTED;\r
237   }\r
238 \r
239   //\r
240   // Test for the Ip4 Protocol\r
241   //\r
242   Status = gBS->OpenProtocol (\r
243                   ControllerHandle,\r
244                   &gEfiIp4ServiceBindingProtocolGuid,\r
245                   NULL,\r
246                   This->DriverBindingHandle,\r
247                   ControllerHandle,\r
248                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
249                   );\r
250 \r
251   return Status;\r
252 }\r
253 \r
254 \r
255 /**\r
256   Start this driver on ControllerHandle.\r
257 \r
258   @param  This                   Protocol instance pointer.\r
259   @param  ControllerHandle       Handle of device to bind driver to.\r
260   @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
261                                  device to start.\r
262 \r
263   @retval EFI_SUCCESS            The driver is added to ControllerHandle.\r
264   @retval EFI_OUT_OF_RESOURCES   There are not enough resources to start the\r
265                                  driver.\r
266   @retval other                  The driver cannot be added to ControllerHandle.\r
267 \r
268 **/\r
269 EFI_STATUS\r
270 EFIAPI\r
271 Tcp4DriverBindingStart (\r
272   IN EFI_DRIVER_BINDING_PROTOCOL  * This,\r
273   IN EFI_HANDLE                   ControllerHandle,\r
274   IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL\r
275   )\r
276 {\r
277   EFI_STATUS               Status;\r
278   TCP4_SERVICE_DATA        *TcpServiceData;\r
279   IP_IO_OPEN_DATA          OpenData;\r
280 \r
281   TcpServiceData = NetAllocateZeroPool (sizeof (TCP4_SERVICE_DATA));\r
282 \r
283   if (NULL == TcpServiceData) {\r
284     TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Have no enough"\r
285       " resource to create a Tcp Servcie Data!\n"));\r
286 \r
287     return EFI_OUT_OF_RESOURCES;\r
288   }\r
289 \r
290   //\r
291   // Create a new IP IO to Consume it\r
292   //\r
293   TcpServiceData->IpIo = IpIoCreate (This->DriverBindingHandle, ControllerHandle);\r
294   if (NULL == TcpServiceData->IpIo) {\r
295 \r
296     TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Have no enough"\r
297       " resource to create an Ip Io!\n"));\r
298 \r
299     Status = EFI_OUT_OF_RESOURCES;\r
300     goto ON_ERROR;\r
301   }\r
302 \r
303   //\r
304   // Configure and start IpIo.\r
305   //\r
306   NetZeroMem (&OpenData, sizeof (IP_IO_OPEN_DATA));\r
307 \r
308   CopyMem (&OpenData.IpConfigData, &mIpIoDefaultIpConfigData, sizeof (OpenData.IpConfigData));\r
309   OpenData.IpConfigData.DefaultProtocol = EFI_IP_PROTO_TCP;\r
310 \r
311   OpenData.PktRcvdNotify = Tcp4RxCallback;\r
312   Status                 = IpIoOpen (TcpServiceData->IpIo, &OpenData);\r
313 \r
314   if (EFI_ERROR (Status)) {\r
315     goto ON_ERROR;\r
316   }\r
317 \r
318   //\r
319   // Create the timer event used by TCP driver\r
320   //\r
321   Status = Tcp4CreateTimer ();\r
322   if (EFI_ERROR (Status)) {\r
323 \r
324     TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Create TcpTimer"\r
325       " Event failed with %r\n", Status));\r
326 \r
327     goto ON_ERROR;\r
328   }\r
329 \r
330   //\r
331   // Install the Tcp4ServiceBinding Protocol on the\r
332   // controller handle\r
333   //\r
334   TcpServiceData->Tcp4ServiceBinding = mTcp4ServiceBinding;\r
335 \r
336   Status = gBS->InstallMultipleProtocolInterfaces (\r
337                   &ControllerHandle,\r
338                   &gEfiTcp4ServiceBindingProtocolGuid,\r
339                   &TcpServiceData->Tcp4ServiceBinding,\r
340                   NULL\r
341                   );\r
342   if (EFI_ERROR (Status)) {\r
343 \r
344     TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Install Tcp4 Service Binding"\r
345       " Protocol failed for %r\n", Status));\r
346 \r
347     Tcp4DestroyTimer ();\r
348     goto ON_ERROR;\r
349   }\r
350 \r
351   //\r
352   // Initialize member in TcpServiceData\r
353   //\r
354   TcpServiceData->ControllerHandle    = ControllerHandle;\r
355   TcpServiceData->Signature           = TCP4_DRIVER_SIGNATURE;\r
356   TcpServiceData->DriverBindingHandle = This->DriverBindingHandle;\r
357 \r
358   NetListInit (&TcpServiceData->SocketList);\r
359 \r
360   TcpSetVariableData (TcpServiceData);\r
361 \r
362   return EFI_SUCCESS;\r
363 \r
364 ON_ERROR:\r
365 \r
366   if (TcpServiceData->IpIo != NULL) {\r
367     IpIoDestroy (TcpServiceData->IpIo);\r
368   }\r
369 \r
370   NetFreePool (TcpServiceData);\r
371 \r
372   return Status;\r
373 }\r
374 \r
375 \r
376 /**\r
377   Stop this driver on ControllerHandle.\r
378 \r
379   @param  This                   Protocol instance pointer.\r
380   @param  ControllerHandle       Handle of device to stop driver on.\r
381   @param  NumberOfChildren       Number of Handles in ChildHandleBuffer. If number\r
382                                  of children is zero stop the entire bus driver.\r
383   @param  ChildHandleBuffer      List of Child Handles to Stop.\r
384 \r
385   @retval EFI_SUCCESS            This driver is removed from ControllerHandle.\r
386   @retval other                  This driver is not removed from ControllerHandle.\r
387 \r
388 **/\r
389 EFI_STATUS\r
390 EFIAPI\r
391 Tcp4DriverBindingStop (\r
392   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
393   IN  EFI_HANDLE                   ControllerHandle,\r
394   IN  UINTN                        NumberOfChildren,\r
395   IN  EFI_HANDLE                   *ChildHandleBuffer\r
396   )\r
397 {\r
398   EFI_STATUS                          Status;\r
399   EFI_HANDLE                          NicHandle;\r
400   EFI_SERVICE_BINDING_PROTOCOL        *ServiceBinding;\r
401   TCP4_SERVICE_DATA                   *TcpServiceData;\r
402   SOCKET                              *Sock;\r
403 \r
404   // Find the NicHandle where Tcp4 ServiceBinding Protocol is installed.\r
405   //\r
406   NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp4ProtocolGuid);\r
407   if (NicHandle == NULL) {\r
408     return EFI_DEVICE_ERROR;\r
409   }\r
410 \r
411   //\r
412   // Retrieve the TCP driver Data Structure\r
413   //\r
414   Status = gBS->OpenProtocol (\r
415                   NicHandle,\r
416                   &gEfiTcp4ServiceBindingProtocolGuid,\r
417                   (VOID **) &ServiceBinding,\r
418                   This->DriverBindingHandle,\r
419                   ControllerHandle,\r
420                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
421                   );\r
422   if (EFI_ERROR (Status)) {\r
423 \r
424     TCP4_DEBUG_ERROR (("Tcp4DriverBindingStop: Locate Tcp4 Service "\r
425       " Binding Protocol failed with %r\n", Status));\r
426 \r
427     return EFI_DEVICE_ERROR;\r
428   }\r
429 \r
430   TcpServiceData = TCP4_FROM_THIS (ServiceBinding);\r
431 \r
432   if (NumberOfChildren == 0) {\r
433     //\r
434     // Uninstall TCP servicebinding protocol\r
435     //\r
436     gBS->UninstallMultipleProtocolInterfaces (\r
437            NicHandle,\r
438            &gEfiTcp4ServiceBindingProtocolGuid,\r
439            ServiceBinding,\r
440            NULL\r
441            );\r
442 \r
443     //\r
444     // Destroy the IpIO consumed by TCP driver\r
445     //\r
446     IpIoDestroy (TcpServiceData->IpIo);\r
447 \r
448     //\r
449     // Destroy the heartbeat timer.\r
450     //\r
451     Tcp4DestroyTimer ();\r
452 \r
453     //\r
454     // Clear the variable.\r
455     //\r
456     TcpClearVariableData (TcpServiceData);\r
457 \r
458     //\r
459     // Release the TCP service data\r
460     //\r
461     NetFreePool (TcpServiceData);\r
462   } else {\r
463 \r
464     while (!NetListIsEmpty (&TcpServiceData->SocketList)) {\r
465       Sock = NET_LIST_HEAD (&TcpServiceData->SocketList, SOCKET, Link);\r
466 \r
467       ServiceBinding->DestroyChild (ServiceBinding, Sock->SockHandle);\r
468     }\r
469   }\r
470 \r
471   return Status;\r
472 }\r
473 \r
474 /**\r
475   Creates a child handle with a set of TCP4 services.\r
476 \r
477   @param  This                   Protocol instance pointer.\r
478   @param  ChildHandle            Pointer to the handle of the child to create.  If\r
479                                  it is NULL, then a new handle is created. If it is\r
480                                  not NULL, then the I/O services are added to the\r
481                                  existing child handle.\r
482 \r
483   @retval EFI_SUCCESS            The child handle is created.\r
484   @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
485   @retval EFI_OUT_OF_RESOURCES   There are not enough resources to create the\r
486                                  child.\r
487 \r
488 **/\r
489 EFI_STATUS\r
490 EFIAPI\r
491 Tcp4ServiceBindingCreateChild (\r
492   IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
493   IN EFI_HANDLE                    *ChildHandle\r
494   )\r
495 {\r
496   SOCKET            *Sock;\r
497   TCP4_SERVICE_DATA *TcpServiceData;\r
498   TCP4_PROTO_DATA   TcpProto;\r
499   EFI_STATUS        Status;\r
500   VOID              *Ip4;\r
501   EFI_TPL           OldTpl;\r
502 \r
503   if (NULL == This || NULL == ChildHandle) {\r
504     return EFI_INVALID_PARAMETER;\r
505   }\r
506 \r
507   OldTpl              = NET_RAISE_TPL (NET_TPL_LOCK);\r
508   TcpServiceData      = TCP4_FROM_THIS (This);\r
509   TcpProto.TcpService = TcpServiceData;\r
510   TcpProto.TcpPcb     = NULL;\r
511 \r
512   //\r
513   // Create a tcp instance with defualt Tcp default\r
514   // sock init data and TcpProto\r
515   //\r
516   mTcp4DefaultSockData.DriverBinding = TcpServiceData->DriverBindingHandle;\r
517 \r
518   Sock = SockCreateChild (&mTcp4DefaultSockData, &TcpProto, sizeof (TCP4_PROTO_DATA));\r
519   if (NULL == Sock) {\r
520     TCP4_DEBUG_ERROR (("Tcp4DriverBindingCreateChild: "\r
521       "No resource to create a Tcp Child\n"));\r
522 \r
523     Status = EFI_OUT_OF_RESOURCES;\r
524     goto ON_EXIT;\r
525   }\r
526 \r
527   *ChildHandle = Sock->SockHandle;\r
528 \r
529   //\r
530   // Open the default Ip4 protocol of IP_IO BY_DRIVER.\r
531   //\r
532   Status = gBS->OpenProtocol (\r
533                   TcpServiceData->IpIo->ChildHandle,\r
534                   &gEfiIp4ProtocolGuid,\r
535                   (VOID **) &Ip4,\r
536                   TcpServiceData->DriverBindingHandle,\r
537                   Sock->SockHandle,\r
538                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
539                   );\r
540   if (EFI_ERROR (Status)) {\r
541     SockDestroyChild (Sock);\r
542     goto ON_EXIT;\r
543   }\r
544 \r
545   //\r
546   // Open the device path on the handle where service binding resides on.\r
547   //\r
548   Status = gBS->OpenProtocol (\r
549                   TcpServiceData->ControllerHandle,\r
550                   &gEfiDevicePathProtocolGuid,\r
551                   (VOID **) &Sock->ParentDevicePath,\r
552                   TcpServiceData->DriverBindingHandle,\r
553                   Sock->SockHandle,\r
554                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
555                   );\r
556   if (EFI_ERROR (Status)) {\r
557     gBS->CloseProtocol (\r
558            TcpServiceData->IpIo->ChildHandle,\r
559            &gEfiIp4ProtocolGuid,\r
560            TcpServiceData->DriverBindingHandle,\r
561            Sock->SockHandle\r
562            );\r
563     SockDestroyChild (Sock);\r
564   } else {\r
565     NetListInsertTail (&TcpServiceData->SocketList, &Sock->Link);\r
566   }\r
567 \r
568 ON_EXIT:\r
569 \r
570   NET_RESTORE_TPL (OldTpl);\r
571   return Status;\r
572 }\r
573 \r
574 \r
575 /**\r
576   Destroys a child handle with a set of UDP4 services.\r
577 \r
578   @param  This                   Protocol instance pointer.\r
579   @param  ChildHandle            Handle of the child to be destroyed.\r
580 \r
581   @retval EFI_SUCCESS            The TCP4 services are removed from  the child\r
582                                  handle.\r
583   @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
584   @retval other                  The child handle is not destroyed.\r
585 \r
586 **/\r
587 EFI_STATUS\r
588 EFIAPI\r
589 Tcp4ServiceBindingDestroyChild (\r
590   IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
591   IN EFI_HANDLE                    ChildHandle\r
592   )\r
593 {\r
594   EFI_STATUS         Status;\r
595   EFI_TCP4_PROTOCOL  *Tcp4;\r
596   SOCKET             *Sock;\r
597   TCP4_PROTO_DATA    *TcpProtoData;\r
598   TCP4_SERVICE_DATA  *TcpServiceData;\r
599   EFI_TPL            OldTpl;\r
600 \r
601   if (NULL == This || NULL == ChildHandle) {\r
602     return EFI_INVALID_PARAMETER;\r
603   }\r
604 \r
605   OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
606 \r
607   //\r
608   // retrieve the Tcp4 protocol from ChildHandle\r
609   //\r
610   Status = gBS->OpenProtocol (\r
611                   ChildHandle,\r
612                   &gEfiTcp4ProtocolGuid,\r
613                   (VOID **) &Tcp4,\r
614                   mTcp4DriverBinding.DriverBindingHandle,\r
615                   ChildHandle,\r
616                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
617                   );\r
618   if (EFI_ERROR (Status)) {\r
619     Status = EFI_UNSUPPORTED;\r
620     goto ON_EXIT;\r
621   }\r
622 \r
623   //\r
624   // destroy this sock and related Tcp protocol control\r
625   // block\r
626   //\r
627   Sock           = SOCK_FROM_THIS (Tcp4);\r
628   TcpProtoData   = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
629   TcpServiceData = TcpProtoData->TcpService;\r
630 \r
631   NetListRemoveEntry (&Sock->Link);\r
632 \r
633   SockDestroyChild (Sock);\r
634 \r
635   //\r
636   // Close the device path protocol\r
637   //\r
638   gBS->CloseProtocol (\r
639          TcpServiceData->ControllerHandle,\r
640          &gEfiDevicePathProtocolGuid,\r
641          TcpServiceData->DriverBindingHandle,\r
642          ChildHandle\r
643          );\r
644 \r
645   //\r
646   // Close the Ip4 protocol.\r
647   //\r
648   gBS->CloseProtocol (\r
649          TcpServiceData->IpIo->ChildHandle,\r
650          &gEfiIp4ProtocolGuid,\r
651          TcpServiceData->DriverBindingHandle,\r
652          ChildHandle\r
653          );\r
654 \r
655 ON_EXIT:\r
656   NET_RESTORE_TPL (OldTpl);\r
657   return Status;\r
658 }\r