]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c
MdeModulePkg: Update Ip4Dxe driver to support Ip4Config2 protocol,
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Driver.c
CommitLineData
772db4bb 1/** @file\r
3e8c18da 2 The driver binding and service binding protocol for IP4 driver.\r
e2851998 3\r
1f6729ff 4Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials\r
772db4bb 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
772db4bb 13**/\r
14\r
15#include "Ip4Impl.h"\r
16\r
17EFI_DRIVER_BINDING_PROTOCOL gIp4DriverBinding = {\r
18 Ip4DriverBindingSupported,\r
19 Ip4DriverBindingStart,\r
20 Ip4DriverBindingStop,\r
21 0xa,\r
22 NULL,\r
23 NULL\r
24};\r
25\r
5405e9a6 26/**\r
27 This is the declaration of an EFI image entry point. This entry point is\r
28 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
29 both device drivers and bus drivers.\r
e2851998 30\r
5405e9a6 31 The entry point for IP4 driver which install the driver\r
32 binding and component name protocol on its image.\r
33\r
3e8c18da 34 @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
35 @param[in] SystemTable A pointer to the EFI System Table.\r
5405e9a6 36\r
37 @retval EFI_SUCCESS The operation completed successfully.\r
38 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
39\r
40**/\r
772db4bb 41EFI_STATUS\r
42EFIAPI\r
43Ip4DriverEntryPoint (\r
44 IN EFI_HANDLE ImageHandle,\r
45 IN EFI_SYSTEM_TABLE *SystemTable\r
46 )\r
772db4bb 47{\r
83cbd279 48 return EfiLibInstallDriverBindingComponentName2 (\r
772db4bb 49 ImageHandle,\r
50 SystemTable,\r
51 &gIp4DriverBinding,\r
52 ImageHandle,\r
53 &gIp4ComponentName,\r
83cbd279 54 &gIp4ComponentName2\r
772db4bb 55 );\r
56}\r
57\r
772db4bb 58/**\r
5405e9a6 59 Test to see if this driver supports ControllerHandle. This service\r
60 is called by the EFI boot service ConnectController(). In\r
61 order to make drivers as small as possible, there are a few calling\r
62 restrictions for this service. ConnectController() must\r
63 follow these calling restrictions. If any other agent wishes to call\r
64 Supported() it must also follow these calling restrictions.\r
65\r
3e8c18da 66 @param[in] This Protocol instance pointer.\r
67 @param[in] ControllerHandle Handle of device to test\r
68 @param[in] RemainingDevicePath Optional parameter use to pick a specific child\r
69 device to start.\r
5405e9a6 70\r
71 @retval EFI_SUCCESS This driver supports this device\r
72 @retval EFI_ALREADY_STARTED This driver is already running on this device\r
73 @retval other This driver does not support this device\r
772db4bb 74\r
75**/\r
76EFI_STATUS\r
77EFIAPI\r
78Ip4DriverBindingSupported (\r
79 IN EFI_DRIVER_BINDING_PROTOCOL * This,\r
80 IN EFI_HANDLE ControllerHandle,\r
81 IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL\r
82 )\r
83{\r
84 EFI_STATUS Status;\r
85\r
86 //\r
87 // Test for the MNP service binding Protocol\r
88 //\r
89 Status = gBS->OpenProtocol (\r
90 ControllerHandle,\r
91 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
92 NULL,\r
93 This->DriverBindingHandle,\r
94 ControllerHandle,\r
95 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
96 );\r
97\r
98 if (EFI_ERROR (Status)) {\r
99 return Status;\r
100 }\r
101\r
102 //\r
103 // Test for the Arp service binding Protocol\r
104 //\r
105 Status = gBS->OpenProtocol (\r
106 ControllerHandle,\r
107 &gEfiArpServiceBindingProtocolGuid,\r
108 NULL,\r
109 This->DriverBindingHandle,\r
110 ControllerHandle,\r
111 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
112 );\r
113\r
114 return Status;\r
115}\r
116\r
2ff29212 117/**\r
118 Clean up a IP4 service binding instance. It will release all\r
119 the resource allocated by the instance. The instance may be\r
120 partly initialized, or partly destroyed. If a resource is\r
75dce340 121 destroyed, it is marked as that in case the destroy failed and\r
2ff29212 122 being called again later.\r
123\r
1f6729ff 124 @param[in] IpSb The IP4 service binding instance to clean up\r
2ff29212 125\r
126 @retval EFI_SUCCESS The resource used by the instance are cleaned up\r
127 @retval other Failed to clean up some of the resources.\r
128\r
129**/\r
772db4bb 130EFI_STATUS\r
131Ip4CleanService (\r
132 IN IP4_SERVICE *IpSb\r
133 );\r
134\r
135\r
136/**\r
5405e9a6 137 Create a new IP4 driver service binding private instance.\r
772db4bb 138\r
3e8c18da 139 @param Controller The controller that has MNP service binding\r
140 installed\r
141 @param ImageHandle The IP4 driver's image handle\r
142 @param Service The variable to receive the newly created IP4\r
143 service.\r
772db4bb 144\r
145 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource\r
146 @retval EFI_SUCCESS A new IP4 service binding private is created.\r
5405e9a6 147 @retval other Other error occurs.\r
772db4bb 148\r
149**/\r
772db4bb 150EFI_STATUS\r
151Ip4CreateService (\r
152 IN EFI_HANDLE Controller,\r
153 IN EFI_HANDLE ImageHandle,\r
154 OUT IP4_SERVICE **Service\r
155 )\r
156{\r
157 IP4_SERVICE *IpSb;\r
158 EFI_STATUS Status;\r
159\r
160 ASSERT (Service != NULL);\r
161\r
162 *Service = NULL;\r
163\r
164 //\r
165 // allocate a service private data then initialize all the filed to\r
166 // empty resources, so if any thing goes wrong when allocating\r
167 // resources, Ip4CleanService can be called to clean it up.\r
168 //\r
1f6729ff 169 IpSb = AllocateZeroPool (sizeof (IP4_SERVICE));\r
772db4bb 170\r
171 if (IpSb == NULL) {\r
172 return EFI_OUT_OF_RESOURCES;\r
173 }\r
174\r
175 IpSb->Signature = IP4_SERVICE_SIGNATURE;\r
176 IpSb->ServiceBinding.CreateChild = Ip4ServiceBindingCreateChild;\r
177 IpSb->ServiceBinding.DestroyChild = Ip4ServiceBindingDestroyChild;\r
178 IpSb->State = IP4_SERVICE_UNSTARTED;\r
772db4bb 179\r
180 IpSb->NumChildren = 0;\r
e48e37fc 181 InitializeListHead (&IpSb->Children);\r
772db4bb 182\r
e48e37fc 183 InitializeListHead (&IpSb->Interfaces);\r
772db4bb 184 IpSb->DefaultInterface = NULL;\r
185 IpSb->DefaultRouteTable = NULL;\r
186\r
187 Ip4InitAssembleTable (&IpSb->Assemble);\r
188\r
189 IpSb->IgmpCtrl.Igmpv1QuerySeen = 0;\r
e48e37fc 190 InitializeListHead (&IpSb->IgmpCtrl.Groups);\r
772db4bb 191\r
192 IpSb->Image = ImageHandle;\r
193 IpSb->Controller = Controller;\r
194\r
195 IpSb->MnpChildHandle = NULL;\r
196 IpSb->Mnp = NULL;\r
197\r
198 IpSb->MnpConfigData.ReceivedQueueTimeoutValue = 0;\r
199 IpSb->MnpConfigData.TransmitQueueTimeoutValue = 0;\r
200 IpSb->MnpConfigData.ProtocolTypeFilter = IP4_ETHER_PROTO;\r
201 IpSb->MnpConfigData.EnableUnicastReceive = TRUE;\r
202 IpSb->MnpConfigData.EnableMulticastReceive = TRUE;\r
203 IpSb->MnpConfigData.EnableBroadcastReceive = TRUE;\r
204 IpSb->MnpConfigData.EnablePromiscuousReceive = FALSE;\r
205 IpSb->MnpConfigData.FlushQueuesOnReset = TRUE;\r
206 IpSb->MnpConfigData.EnableReceiveTimestamps = FALSE;\r
207 IpSb->MnpConfigData.DisableBackgroundPolling = FALSE;\r
208\r
e48e37fc 209 ZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));\r
772db4bb 210\r
1f6729ff 211 IpSb->Timer = NULL;\r
772db4bb 212\r
213 //\r
214 // Create various resources. First create the route table, timer\r
215 // event and MNP child. IGMP, interface's initialization depend\r
216 // on the MNP child.\r
217 //\r
218 IpSb->DefaultRouteTable = Ip4CreateRouteTable ();\r
219\r
220 if (IpSb->DefaultRouteTable == NULL) {\r
221 Status = EFI_OUT_OF_RESOURCES;\r
222 goto ON_ERROR;\r
223 }\r
224\r
225 Status = gBS->CreateEvent (\r
226 EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
e48e37fc 227 TPL_CALLBACK,\r
772db4bb 228 Ip4TimerTicking,\r
229 IpSb,\r
230 &IpSb->Timer\r
231 );\r
232\r
233 if (EFI_ERROR (Status)) {\r
234 goto ON_ERROR;\r
235 }\r
236\r
237 Status = NetLibCreateServiceChild (\r
238 Controller,\r
239 ImageHandle,\r
240 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
241 &IpSb->MnpChildHandle\r
242 );\r
243\r
244 if (EFI_ERROR (Status)) {\r
245 goto ON_ERROR;\r
246 }\r
247\r
248 Status = gBS->OpenProtocol (\r
249 IpSb->MnpChildHandle,\r
250 &gEfiManagedNetworkProtocolGuid,\r
251 (VOID **) &IpSb->Mnp,\r
252 ImageHandle,\r
253 Controller,\r
254 EFI_OPEN_PROTOCOL_BY_DRIVER\r
255 );\r
256\r
257 if (EFI_ERROR (Status)) {\r
258 goto ON_ERROR;\r
259 }\r
260\r
261 Status = Ip4ServiceConfigMnp (IpSb, TRUE);\r
262\r
263 if (EFI_ERROR (Status)) {\r
264 goto ON_ERROR;\r
265 }\r
266\r
267 Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);\r
268\r
269 if (EFI_ERROR (Status)) {\r
270 goto ON_ERROR;\r
271 }\r
272\r
273 Status = Ip4InitIgmp (IpSb);\r
274\r
275 if (EFI_ERROR (Status)) {\r
276 goto ON_ERROR;\r
277 }\r
278\r
1f6729ff 279 IpSb->MacString = NULL;\r
280 Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &IpSb->MacString);\r
281 \r
282 if (EFI_ERROR (Status)) {\r
283 goto ON_ERROR;\r
284 }\r
285\r
772db4bb 286 IpSb->DefaultInterface = Ip4CreateInterface (IpSb->Mnp, Controller, ImageHandle);\r
287\r
288 if (IpSb->DefaultInterface == NULL) {\r
289 Status = EFI_OUT_OF_RESOURCES;\r
290 goto ON_ERROR;\r
291 }\r
292\r
e48e37fc 293 InsertHeadList (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);\r
772db4bb 294\r
1f6729ff 295 ZeroMem (&IpSb->Ip4Config2Instance, sizeof (IP4_CONFIG2_INSTANCE));\r
296 \r
297 Status = Ip4Config2InitInstance (&IpSb->Ip4Config2Instance);\r
298\r
299 if (EFI_ERROR (Status)) {\r
300 goto ON_ERROR;\r
301 }\r
302\r
a1503a32 303 IpSb->MaxPacketSize = IpSb->SnpMode.MaxPacketSize - sizeof (IP4_HEAD);\r
779ae357 304 if (NetLibGetVlanId (IpSb->Controller) != 0) {\r
305 //\r
306 // This is a VLAN device, reduce MTU by VLAN tag length\r
307 //\r
308 IpSb->MaxPacketSize -= NET_VLAN_TAG_LEN;\r
309 }\r
9e375eb1 310 IpSb->OldMaxPacketSize = IpSb->MaxPacketSize;\r
772db4bb 311 *Service = IpSb;\r
1f6729ff 312\r
772db4bb 313 return EFI_SUCCESS;\r
314\r
315ON_ERROR:\r
316 Ip4CleanService (IpSb);\r
766c7483 317 FreePool (IpSb);\r
772db4bb 318\r
319 return Status;\r
320}\r
321\r
322\r
323/**\r
324 Clean up a IP4 service binding instance. It will release all\r
325 the resource allocated by the instance. The instance may be\r
5405e9a6 326 partly initialized, or partly destroyed. If a resource is\r
75dce340 327 destroyed, it is marked as that in case the destroy failed and\r
772db4bb 328 being called again later.\r
329\r
1f6729ff 330 @param[in] IpSb The IP4 service binding instance to clean up\r
772db4bb 331\r
332 @retval EFI_SUCCESS The resource used by the instance are cleaned up\r
5405e9a6 333 @retval other Failed to clean up some of the resources.\r
772db4bb 334\r
335**/\r
336EFI_STATUS\r
337Ip4CleanService (\r
338 IN IP4_SERVICE *IpSb\r
339 )\r
340{\r
341 EFI_STATUS Status;\r
342\r
343 if (IpSb->DefaultInterface != NULL) {\r
344 Status = Ip4FreeInterface (IpSb->DefaultInterface, NULL);\r
345\r
346 if (EFI_ERROR (Status)) {\r
347 return Status;\r
348 }\r
349\r
350 IpSb->DefaultInterface = NULL;\r
351 }\r
352\r
353 if (IpSb->DefaultRouteTable != NULL) {\r
354 Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
355 IpSb->DefaultRouteTable = NULL;\r
356 }\r
357\r
358 Ip4CleanAssembleTable (&IpSb->Assemble);\r
359\r
360 if (IpSb->MnpChildHandle != NULL) {\r
5405e9a6 361 if (IpSb->Mnp != NULL) {\r
772db4bb 362 gBS->CloseProtocol (\r
5405e9a6 363 IpSb->MnpChildHandle,\r
364 &gEfiManagedNetworkProtocolGuid,\r
365 IpSb->Image,\r
366 IpSb->Controller\r
367 );\r
772db4bb 368\r
369 IpSb->Mnp = NULL;\r
370 }\r
371\r
372 NetLibDestroyServiceChild (\r
373 IpSb->Controller,\r
374 IpSb->Image,\r
375 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
376 IpSb->MnpChildHandle\r
377 );\r
378\r
379 IpSb->MnpChildHandle = NULL;\r
380 }\r
381\r
382 if (IpSb->Timer != NULL) {\r
383 gBS->SetTimer (IpSb->Timer, TimerCancel, 0);\r
384 gBS->CloseEvent (IpSb->Timer);\r
385\r
386 IpSb->Timer = NULL;\r
387 }\r
388\r
1f6729ff 389 if (IpSb->MacString != NULL) {\r
390 FreePool (IpSb->MacString);\r
772db4bb 391 }\r
392\r
1f6729ff 393 Ip4Config2CleanInstance (&IpSb->Ip4Config2Instance);\r
394\r
772db4bb 395 return EFI_SUCCESS;\r
396}\r
397\r
216f7970 398/**\r
399 Callback function which provided by user to remove one node in NetDestroyLinkList process.\r
400 \r
401 @param[in] Entry The entry to be removed.\r
402 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.\r
403\r
404 @retval EFI_SUCCESS The entry has been removed successfully.\r
405 @retval Others Fail to remove the entry.\r
406\r
407**/\r
408EFI_STATUS\r
1f7eb561 409EFIAPI\r
216f7970 410Ip4DestroyChildEntryInHandleBuffer (\r
411 IN LIST_ENTRY *Entry,\r
412 IN VOID *Context\r
1f7eb561 413 )\r
216f7970 414{\r
415 IP4_PROTOCOL *IpInstance;\r
416 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
417 UINTN NumberOfChildren;\r
418 EFI_HANDLE *ChildHandleBuffer;\r
419\r
420 if (Entry == NULL || Context == NULL) {\r
421 return EFI_INVALID_PARAMETER;\r
422 }\r
423\r
424 IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, Link, IP4_PROTOCOL_SIGNATURE);\r
425 ServiceBinding = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;\r
426 NumberOfChildren = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;\r
427 ChildHandleBuffer = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;\r
428\r
429 if (!NetIsInHandleBuffer (IpInstance->Handle, NumberOfChildren, ChildHandleBuffer)) {\r
430 return EFI_SUCCESS;\r
431 }\r
432\r
433 return ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);\r
434}\r
772db4bb 435\r
436/**\r
5405e9a6 437 Start this driver on ControllerHandle. This service is called by the\r
438 EFI boot service ConnectController(). In order to make\r
439 drivers as small as possible, there are a few calling restrictions for\r
440 this service. ConnectController() must follow these\r
441 calling restrictions. If any other agent wishes to call Start() it\r
442 must also follow these calling restrictions.\r
443\r
3e8c18da 444 @param[in] This Protocol instance pointer.\r
445 @param[in] ControllerHandle Handle of device to bind driver to\r
446 @param[in] RemainingDevicePath Optional parameter use to pick a specific child\r
447 device to start.\r
5405e9a6 448\r
449 @retval EFI_SUCCESS This driver is added to ControllerHandle\r
450 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
451 @retval other This driver does not support this device\r
772db4bb 452\r
453**/\r
454EFI_STATUS\r
455EFIAPI\r
456Ip4DriverBindingStart (\r
1f6729ff 457 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
772db4bb 458 IN EFI_HANDLE ControllerHandle,\r
1f6729ff 459 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
772db4bb 460 )\r
1f6729ff 461{ \r
462 EFI_STATUS Status;\r
463 IP4_SERVICE *IpSb;\r
772db4bb 464\r
465 //\r
466 // Test for the Ip4 service binding protocol\r
467 //\r
468 Status = gBS->OpenProtocol (\r
469 ControllerHandle,\r
470 &gEfiIp4ServiceBindingProtocolGuid,\r
471 NULL,\r
472 This->DriverBindingHandle,\r
473 ControllerHandle,\r
474 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
475 );\r
476\r
477 if (Status == EFI_SUCCESS) {\r
478 return EFI_ALREADY_STARTED;\r
479 }\r
1f6729ff 480 \r
772db4bb 481 Status = Ip4CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);\r
1f6729ff 482 \r
772db4bb 483 if (EFI_ERROR (Status)) {\r
484 return Status;\r
485 }\r
1f6729ff 486 \r
e2851998 487 ASSERT (IpSb != NULL);\r
772db4bb 488\r
489 //\r
490 // Install the Ip4ServiceBinding Protocol onto ControlerHandle\r
491 //\r
492 Status = gBS->InstallMultipleProtocolInterfaces (\r
493 &ControllerHandle,\r
494 &gEfiIp4ServiceBindingProtocolGuid,\r
495 &IpSb->ServiceBinding,\r
1f6729ff 496 &gEfiIp4Config2ProtocolGuid,\r
497 &IpSb->Ip4Config2Instance.Ip4Config2,\r
772db4bb 498 NULL\r
499 );\r
500\r
501 if (EFI_ERROR (Status)) {\r
502 goto FREE_SERVICE;\r
503 }\r
1f6729ff 504 \r
772db4bb 505 //\r
1f6729ff 506 // Ready to go: start the receiving and timer.\r
507 // Ip4Config2SetPolicy maybe call Ip4ReceiveFrame() to set the default interface's RecvRequest first after\r
508 // Ip4Config2 instance is initialized. So, EFI_ALREADY_STARTED is the allowed return status.\r
772db4bb 509 //\r
510 Status = Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);\r
511\r
1f6729ff 512 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
772db4bb 513 goto UNINSTALL_PROTOCOL;\r
514 }\r
515\r
516 Status = gBS->SetTimer (IpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);\r
517\r
518 if (EFI_ERROR (Status)) {\r
519 goto UNINSTALL_PROTOCOL;\r
520 }\r
521\r
522 //\r
523 // Initialize the IP4 ID\r
524 //\r
525 mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ());\r
526\r
772db4bb 527 return Status;\r
528\r
529UNINSTALL_PROTOCOL:\r
530 gBS->UninstallProtocolInterface (\r
531 ControllerHandle,\r
532 &gEfiIp4ServiceBindingProtocolGuid,\r
533 &IpSb->ServiceBinding\r
534 );\r
535\r
536FREE_SERVICE:\r
537 Ip4CleanService (IpSb);\r
766c7483 538 FreePool (IpSb);\r
772db4bb 539 return Status;\r
540}\r
541\r
542\r
543/**\r
5405e9a6 544 Stop this driver on ControllerHandle. This service is called by the\r
545 EFI boot service DisconnectController(). In order to\r
546 make drivers as small as possible, there are a few calling\r
547 restrictions for this service. DisconnectController()\r
548 must follow these calling restrictions. If any other agent wishes\r
549 to call Stop() it must also follow these calling restrictions.\r
e2851998 550\r
3e8c18da 551 @param[in] This Protocol instance pointer.\r
552 @param[in] ControllerHandle Handle of device to stop driver on\r
553 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number\r
554 of children is zero stop the entire bus driver.\r
555 @param[in] ChildHandleBuffer List of Child Handles to Stop.\r
5405e9a6 556\r
3e8c18da 557 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
558 @retval other This driver was not removed from this device\r
772db4bb 559\r
560**/\r
561EFI_STATUS\r
562EFIAPI\r
563Ip4DriverBindingStop (\r
564 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
565 IN EFI_HANDLE ControllerHandle,\r
566 IN UINTN NumberOfChildren,\r
567 IN EFI_HANDLE *ChildHandleBuffer\r
568 )\r
569{\r
216f7970 570 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
571 IP4_SERVICE *IpSb; \r
572 EFI_HANDLE NicHandle;\r
573 EFI_STATUS Status; \r
574 INTN State;\r
575 LIST_ENTRY *List;\r
576 IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;\r
d0ccf55e 577 IP4_INTERFACE *IpIf;\r
578 IP4_ROUTE_TABLE *RouteTable;\r
772db4bb 579\r
1f6729ff 580 BOOLEAN IsDhcp4;\r
772db4bb 581\r
1f6729ff 582 IsDhcp4 = FALSE;\r
583 \r
772db4bb 584 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);\r
772db4bb 585 if (NicHandle == NULL) {\r
586 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);\r
216f7970 587 if (NicHandle == NULL) {\r
1f6729ff 588 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);\r
589 if (NicHandle != NULL) {\r
590 IsDhcp4 = TRUE; \r
591 } else {\r
592 return EFI_SUCCESS;\r
593 }\r
216f7970 594 }\r
772db4bb 595 }\r
1f6729ff 596 \r
772db4bb 597 Status = gBS->OpenProtocol (\r
598 NicHandle,\r
599 &gEfiIp4ServiceBindingProtocolGuid,\r
600 (VOID **) &ServiceBinding,\r
601 This->DriverBindingHandle,\r
602 NicHandle,\r
603 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
604 );\r
772db4bb 605 if (EFI_ERROR (Status)) {\r
606 return EFI_DEVICE_ERROR;\r
607 }\r
1f6729ff 608 \r
609 IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);\r
772db4bb 610\r
1f6729ff 611 if (IsDhcp4) {\r
612 Status = Ip4Config2DestroyDhcp4 (&IpSb->Ip4Config2Instance);\r
613 gBS->CloseEvent (IpSb->Ip4Config2Instance.Dhcp4Event);\r
614 IpSb->Ip4Config2Instance.Dhcp4Event = NULL;\r
615 } else if (NumberOfChildren != 0) {\r
216f7970 616 List = &IpSb->Children;\r
617 Context.ServiceBinding = ServiceBinding;\r
618 Context.NumberOfChildren = NumberOfChildren;\r
619 Context.ChildHandleBuffer = ChildHandleBuffer;\r
620 Status = NetDestroyLinkList (\r
621 List,\r
622 Ip4DestroyChildEntryInHandleBuffer,\r
623 &Context,\r
624 NULL\r
625 );\r
d0ccf55e 626 } else if (IpSb->DefaultInterface->ArpHandle == ControllerHandle) {\r
1f6729ff 627 \r
d0ccf55e 628 //\r
629 // The ARP protocol for the default interface is being uninstalled and all\r
630 // its IP child handles should have been destroyed before. So, release the\r
631 // default interface and route table, create a new one and mark it as not started.\r
632 //\r
633 Ip4CancelReceive (IpSb->DefaultInterface);\r
634 Ip4FreeInterface (IpSb->DefaultInterface, NULL);\r
635 Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
636 \r
637 IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
638 if (IpIf == NULL) {\r
639 goto ON_ERROR;\r
640 }\r
641 RouteTable = Ip4CreateRouteTable ();\r
642 if (RouteTable == NULL) {\r
643 Ip4FreeInterface (IpIf, NULL);\r
644 goto ON_ERROR;;\r
645 }\r
646 \r
647 IpSb->DefaultInterface = IpIf;\r
648 InsertHeadList (&IpSb->Interfaces, &IpIf->Link);\r
649 IpSb->DefaultRouteTable = RouteTable;\r
650 Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);\r
651\r
d0ccf55e 652 IpSb->State = IP4_SERVICE_UNSTARTED;\r
1f6729ff 653\r
216f7970 654 } else if (IsListEmpty (&IpSb->Children)) {\r
c4a62a12 655 State = IpSb->State;\r
75dce340 656 IpSb->State = IP4_SERVICE_DESTROY;\r
772db4bb 657\r
c4a62a12 658 //\r
659 // OK, clean other resources then uninstall the service binding protocol.\r
660 //\r
661 Status = Ip4CleanService (IpSb);\r
c4a62a12 662 if (EFI_ERROR (Status)) {\r
663 IpSb->State = State;\r
664 goto ON_ERROR;\r
665 }\r
772db4bb 666\r
1f6729ff 667 gBS->UninstallMultipleProtocolInterfaces (\r
c4a62a12 668 NicHandle,\r
669 &gEfiIp4ServiceBindingProtocolGuid,\r
1f6729ff 670 ServiceBinding,\r
671 &gEfiIp4Config2ProtocolGuid,\r
672 &IpSb->Ip4Config2Instance.Ip4Config2,\r
673 NULL\r
c4a62a12 674 );\r
216f7970 675 \r
676 if (gIp4ControllerNameTable != NULL) {\r
677 FreeUnicodeStringTable (gIp4ControllerNameTable);\r
678 gIp4ControllerNameTable = NULL;\r
c4a62a12 679 }\r
766c7483 680 FreePool (IpSb);\r
c4a62a12 681 }\r
772db4bb 682\r
683ON_ERROR:\r
772db4bb 684 return Status;\r
685}\r
686\r
687\r
688/**\r
3e8c18da 689 Creates a child handle and installs a protocol.\r
e2851998 690\r
691 The CreateChild() function installs a protocol on ChildHandle.\r
692 If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.\r
3e8c18da 693 If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.\r
772db4bb 694\r
3e8c18da 695 @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
696 @param ChildHandle Pointer to the handle of the child to create. If it is NULL,\r
e2851998 697 then a new handle is created. If it is a pointer to an existing UEFI handle,\r
3e8c18da 698 then the protocol is added to the existing UEFI handle.\r
772db4bb 699\r
3e8c18da 700 @retval EFI_SUCCES The protocol was added to ChildHandle.\r
5405e9a6 701 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.\r
702 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create\r
703 the child\r
704 @retval other The child handle was not created\r
772db4bb 705\r
706**/\r
707EFI_STATUS\r
708EFIAPI\r
709Ip4ServiceBindingCreateChild (\r
710 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
5405e9a6 711 IN OUT EFI_HANDLE *ChildHandle\r
772db4bb 712 )\r
713{\r
714 IP4_SERVICE *IpSb;\r
715 IP4_PROTOCOL *IpInstance;\r
716 EFI_TPL OldTpl;\r
717 EFI_STATUS Status;\r
718 VOID *Mnp;\r
719\r
720 if ((This == NULL) || (ChildHandle == NULL)) {\r
721 return EFI_INVALID_PARAMETER;\r
722 }\r
723\r
724 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);\r
e48e37fc 725 IpInstance = AllocatePool (sizeof (IP4_PROTOCOL));\r
772db4bb 726\r
727 if (IpInstance == NULL) {\r
728 return EFI_OUT_OF_RESOURCES;\r
729 }\r
730\r
731 Ip4InitProtocol (IpSb, IpInstance);\r
732\r
733 //\r
734 // Install Ip4 onto ChildHandle\r
735 //\r
736 Status = gBS->InstallMultipleProtocolInterfaces (\r
737 ChildHandle,\r
738 &gEfiIp4ProtocolGuid,\r
739 &IpInstance->Ip4Proto,\r
740 NULL\r
741 );\r
742\r
743 if (EFI_ERROR (Status)) {\r
744 goto ON_ERROR;\r
745 }\r
746\r
747 IpInstance->Handle = *ChildHandle;\r
748\r
749 //\r
750 // Open the Managed Network protocol BY_CHILD.\r
751 //\r
752 Status = gBS->OpenProtocol (\r
753 IpSb->MnpChildHandle,\r
754 &gEfiManagedNetworkProtocolGuid,\r
755 (VOID **) &Mnp,\r
756 gIp4DriverBinding.DriverBindingHandle,\r
757 IpInstance->Handle,\r
758 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
759 );\r
760 if (EFI_ERROR (Status)) {\r
761 gBS->UninstallMultipleProtocolInterfaces (\r
762 ChildHandle,\r
763 &gEfiIp4ProtocolGuid,\r
764 &IpInstance->Ip4Proto,\r
765 NULL\r
766 );\r
767\r
768 goto ON_ERROR;\r
769 }\r
770\r
771 //\r
772 // Insert it into the service binding instance.\r
773 //\r
e48e37fc 774 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 775\r
e48e37fc 776 InsertTailList (&IpSb->Children, &IpInstance->Link);\r
772db4bb 777 IpSb->NumChildren++;\r
778\r
e48e37fc 779 gBS->RestoreTPL (OldTpl);\r
772db4bb 780\r
781ON_ERROR:\r
782\r
783 if (EFI_ERROR (Status)) {\r
784\r
785 Ip4CleanProtocol (IpInstance);\r
786\r
766c7483 787 FreePool (IpInstance);\r
772db4bb 788 }\r
789\r
790 return Status;\r
791}\r
792\r
793\r
794/**\r
3e8c18da 795 Destroys a child handle with a protocol installed on it.\r
e2851998 796\r
797 The DestroyChild() function does the opposite of CreateChild(). It removes a protocol\r
798 that was installed by CreateChild() from ChildHandle. If the removed protocol is the\r
3e8c18da 799 last protocol on ChildHandle, then ChildHandle is destroyed.\r
772db4bb 800\r
3e8c18da 801 @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
5405e9a6 802 @param ChildHandle Handle of the child to destroy\r
803\r
3e8c18da 804 @retval EFI_SUCCES The protocol was removed from ChildHandle.\r
805 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.\r
284ee2e8 806 @retval EFI_INVALID_PARAMETER Child handle is NULL.\r
3e8c18da 807 @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle\r
808 because its services are being used.\r
5405e9a6 809 @retval other The child handle was not destroyed\r
772db4bb 810\r
811**/\r
812EFI_STATUS\r
813EFIAPI\r
814Ip4ServiceBindingDestroyChild (\r
815 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
816 IN EFI_HANDLE ChildHandle\r
817 )\r
818{\r
819 EFI_STATUS Status;\r
820 IP4_SERVICE *IpSb;\r
821 IP4_PROTOCOL *IpInstance;\r
822 EFI_IP4_PROTOCOL *Ip4;\r
823 EFI_TPL OldTpl;\r
824 INTN State;\r
825\r
826 if ((This == NULL) || (ChildHandle == NULL)) {\r
827 return EFI_INVALID_PARAMETER;\r
828 }\r
829\r
830 //\r
831 // Retrieve the private context data structures\r
832 //\r
833 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);\r
834\r
835 Status = gBS->OpenProtocol (\r
836 ChildHandle,\r
837 &gEfiIp4ProtocolGuid,\r
838 (VOID **) &Ip4,\r
839 gIp4DriverBinding.DriverBindingHandle,\r
840 ChildHandle,\r
841 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
842 );\r
843\r
844 if (EFI_ERROR (Status)) {\r
845 return EFI_UNSUPPORTED;\r
846 }\r
847\r
848 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);\r
849\r
850 if (IpInstance->Service != IpSb) {\r
851 return EFI_INVALID_PARAMETER;\r
852 }\r
853\r
e48e37fc 854 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 855\r
856 //\r
75dce340 857 // A child can be destroyed more than once. For example,\r
858 // Ip4DriverBindingStop will destroy all of its children.\r
859 // when UDP driver is being stopped, it will destroy all\r
772db4bb 860 // the IP child it opens.\r
861 //\r
75dce340 862 if (IpInstance->State == IP4_STATE_DESTROY) {\r
e48e37fc 863 gBS->RestoreTPL (OldTpl);\r
772db4bb 864 return EFI_SUCCESS;\r
865 }\r
866\r
867 State = IpInstance->State;\r
75dce340 868 IpInstance->State = IP4_STATE_DESTROY;\r
772db4bb 869\r
870 //\r
871 // Close the Managed Network protocol.\r
872 //\r
873 gBS->CloseProtocol (\r
874 IpSb->MnpChildHandle,\r
875 &gEfiManagedNetworkProtocolGuid,\r
876 gIp4DriverBinding.DriverBindingHandle,\r
877 ChildHandle\r
878 );\r
879\r
216f7970 880 if (IpInstance->Interface != NULL && IpInstance->Interface->Arp != NULL) {\r
881 gBS->CloseProtocol (\r
882 IpInstance->Interface->ArpHandle,\r
883 &gEfiArpProtocolGuid,\r
884 gIp4DriverBinding.DriverBindingHandle,\r
885 ChildHandle\r
886 );\r
887 }\r
888\r
772db4bb 889 //\r
890 // Uninstall the IP4 protocol first. Many thing happens during\r
891 // this:\r
892 // 1. The consumer of the IP4 protocol will be stopped if it\r
893 // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is\r
894 // stopped, IP driver's stop function will be called, and uninstall\r
895 // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This\r
896 // makes it possible to create the network stack bottom up, and\r
897 // stop it top down.\r
898 // 2. the upper layer will recycle the received packet. The recycle\r
899 // event's TPL is higher than this function. The recycle events\r
900 // will be called back before preceeding. If any packets not recycled,\r
901 // that means there is a resource leak.\r
902 //\r
216f7970 903 gBS->RestoreTPL (OldTpl);\r
772db4bb 904 Status = gBS->UninstallProtocolInterface (\r
905 ChildHandle,\r
906 &gEfiIp4ProtocolGuid,\r
907 &IpInstance->Ip4Proto\r
908 );\r
216f7970 909 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 910 if (EFI_ERROR (Status)) {\r
911 goto ON_ERROR;\r
912 }\r
913\r
914 Status = Ip4CleanProtocol (IpInstance);\r
772db4bb 915 if (EFI_ERROR (Status)) {\r
916 gBS->InstallMultipleProtocolInterfaces (\r
917 &ChildHandle,\r
918 &gEfiIp4ProtocolGuid,\r
919 Ip4,\r
920 NULL\r
921 );\r
922\r
923 goto ON_ERROR;\r
924 }\r
925\r
e48e37fc 926 RemoveEntryList (&IpInstance->Link);\r
772db4bb 927 IpSb->NumChildren--;\r
928\r
e48e37fc 929 gBS->RestoreTPL (OldTpl);\r
772db4bb 930\r
766c7483 931 FreePool (IpInstance);\r
772db4bb 932 return EFI_SUCCESS;\r
933\r
934ON_ERROR:\r
935 IpInstance->State = State;\r
e48e37fc 936 gBS->RestoreTPL (OldTpl);\r
772db4bb 937\r
938 return Status;\r
939}\r