]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c
MdeModulePkg: IP4 should re-initiate a DHCP if it detects network reconnection
[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
2c320007
JW
213 IpSb->ReconfigEvent = NULL;\r
214 \r
215 IpSb->MediaPresent = TRUE;\r
216\r
772db4bb 217 //\r
218 // Create various resources. First create the route table, timer\r
219 // event and MNP child. IGMP, interface's initialization depend\r
220 // on the MNP child.\r
221 //\r
222 IpSb->DefaultRouteTable = Ip4CreateRouteTable ();\r
223\r
224 if (IpSb->DefaultRouteTable == NULL) {\r
225 Status = EFI_OUT_OF_RESOURCES;\r
226 goto ON_ERROR;\r
227 }\r
228\r
229 Status = gBS->CreateEvent (\r
230 EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
e48e37fc 231 TPL_CALLBACK,\r
772db4bb 232 Ip4TimerTicking,\r
233 IpSb,\r
234 &IpSb->Timer\r
235 );\r
236\r
237 if (EFI_ERROR (Status)) {\r
238 goto ON_ERROR;\r
239 }\r
240\r
241 Status = NetLibCreateServiceChild (\r
242 Controller,\r
243 ImageHandle,\r
244 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
245 &IpSb->MnpChildHandle\r
246 );\r
247\r
248 if (EFI_ERROR (Status)) {\r
249 goto ON_ERROR;\r
250 }\r
251\r
252 Status = gBS->OpenProtocol (\r
253 IpSb->MnpChildHandle,\r
254 &gEfiManagedNetworkProtocolGuid,\r
255 (VOID **) &IpSb->Mnp,\r
256 ImageHandle,\r
257 Controller,\r
258 EFI_OPEN_PROTOCOL_BY_DRIVER\r
259 );\r
260\r
261 if (EFI_ERROR (Status)) {\r
262 goto ON_ERROR;\r
263 }\r
264\r
265 Status = Ip4ServiceConfigMnp (IpSb, TRUE);\r
266\r
267 if (EFI_ERROR (Status)) {\r
268 goto ON_ERROR;\r
269 }\r
270\r
271 Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);\r
272\r
273 if (EFI_ERROR (Status)) {\r
274 goto ON_ERROR;\r
275 }\r
276\r
277 Status = Ip4InitIgmp (IpSb);\r
278\r
279 if (EFI_ERROR (Status)) {\r
280 goto ON_ERROR;\r
281 }\r
282\r
1f6729ff 283 IpSb->MacString = NULL;\r
284 Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &IpSb->MacString);\r
285 \r
286 if (EFI_ERROR (Status)) {\r
287 goto ON_ERROR;\r
288 }\r
289\r
772db4bb 290 IpSb->DefaultInterface = Ip4CreateInterface (IpSb->Mnp, Controller, ImageHandle);\r
291\r
292 if (IpSb->DefaultInterface == NULL) {\r
293 Status = EFI_OUT_OF_RESOURCES;\r
294 goto ON_ERROR;\r
295 }\r
296\r
e48e37fc 297 InsertHeadList (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);\r
772db4bb 298\r
1f6729ff 299 ZeroMem (&IpSb->Ip4Config2Instance, sizeof (IP4_CONFIG2_INSTANCE));\r
300 \r
301 Status = Ip4Config2InitInstance (&IpSb->Ip4Config2Instance);\r
302\r
303 if (EFI_ERROR (Status)) {\r
304 goto ON_ERROR;\r
305 }\r
306\r
a1503a32 307 IpSb->MaxPacketSize = IpSb->SnpMode.MaxPacketSize - sizeof (IP4_HEAD);\r
779ae357 308 if (NetLibGetVlanId (IpSb->Controller) != 0) {\r
309 //\r
310 // This is a VLAN device, reduce MTU by VLAN tag length\r
311 //\r
312 IpSb->MaxPacketSize -= NET_VLAN_TAG_LEN;\r
313 }\r
9e375eb1 314 IpSb->OldMaxPacketSize = IpSb->MaxPacketSize;\r
772db4bb 315 *Service = IpSb;\r
1f6729ff 316\r
772db4bb 317 return EFI_SUCCESS;\r
318\r
319ON_ERROR:\r
320 Ip4CleanService (IpSb);\r
766c7483 321 FreePool (IpSb);\r
772db4bb 322\r
323 return Status;\r
324}\r
325\r
326\r
327/**\r
328 Clean up a IP4 service binding instance. It will release all\r
329 the resource allocated by the instance. The instance may be\r
5405e9a6 330 partly initialized, or partly destroyed. If a resource is\r
75dce340 331 destroyed, it is marked as that in case the destroy failed and\r
772db4bb 332 being called again later.\r
333\r
1f6729ff 334 @param[in] IpSb The IP4 service binding instance to clean up\r
772db4bb 335\r
336 @retval EFI_SUCCESS The resource used by the instance are cleaned up\r
5405e9a6 337 @retval other Failed to clean up some of the resources.\r
772db4bb 338\r
339**/\r
340EFI_STATUS\r
341Ip4CleanService (\r
342 IN IP4_SERVICE *IpSb\r
343 )\r
344{\r
345 EFI_STATUS Status;\r
346\r
347 if (IpSb->DefaultInterface != NULL) {\r
348 Status = Ip4FreeInterface (IpSb->DefaultInterface, NULL);\r
349\r
350 if (EFI_ERROR (Status)) {\r
351 return Status;\r
352 }\r
353\r
354 IpSb->DefaultInterface = NULL;\r
355 }\r
356\r
357 if (IpSb->DefaultRouteTable != NULL) {\r
358 Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
359 IpSb->DefaultRouteTable = NULL;\r
360 }\r
361\r
362 Ip4CleanAssembleTable (&IpSb->Assemble);\r
363\r
364 if (IpSb->MnpChildHandle != NULL) {\r
5405e9a6 365 if (IpSb->Mnp != NULL) {\r
772db4bb 366 gBS->CloseProtocol (\r
5405e9a6 367 IpSb->MnpChildHandle,\r
368 &gEfiManagedNetworkProtocolGuid,\r
369 IpSb->Image,\r
370 IpSb->Controller\r
371 );\r
772db4bb 372\r
373 IpSb->Mnp = NULL;\r
374 }\r
375\r
376 NetLibDestroyServiceChild (\r
377 IpSb->Controller,\r
378 IpSb->Image,\r
379 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
380 IpSb->MnpChildHandle\r
381 );\r
382\r
383 IpSb->MnpChildHandle = NULL;\r
384 }\r
385\r
386 if (IpSb->Timer != NULL) {\r
387 gBS->SetTimer (IpSb->Timer, TimerCancel, 0);\r
388 gBS->CloseEvent (IpSb->Timer);\r
389\r
390 IpSb->Timer = NULL;\r
391 }\r
392\r
2c320007
JW
393 if (IpSb->ReconfigEvent != NULL) {\r
394 gBS->CloseEvent (IpSb->ReconfigEvent);\r
395\r
396 IpSb->ReconfigEvent = NULL;\r
397 }\r
398\r
1f6729ff 399 if (IpSb->MacString != NULL) {\r
400 FreePool (IpSb->MacString);\r
772db4bb 401 }\r
402\r
1f6729ff 403 Ip4Config2CleanInstance (&IpSb->Ip4Config2Instance);\r
404\r
772db4bb 405 return EFI_SUCCESS;\r
406}\r
407\r
216f7970 408/**\r
409 Callback function which provided by user to remove one node in NetDestroyLinkList process.\r
410 \r
411 @param[in] Entry The entry to be removed.\r
412 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.\r
413\r
414 @retval EFI_SUCCESS The entry has been removed successfully.\r
415 @retval Others Fail to remove the entry.\r
416\r
417**/\r
418EFI_STATUS\r
1f7eb561 419EFIAPI\r
216f7970 420Ip4DestroyChildEntryInHandleBuffer (\r
421 IN LIST_ENTRY *Entry,\r
422 IN VOID *Context\r
1f7eb561 423 )\r
216f7970 424{\r
425 IP4_PROTOCOL *IpInstance;\r
426 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
427 UINTN NumberOfChildren;\r
428 EFI_HANDLE *ChildHandleBuffer;\r
429\r
430 if (Entry == NULL || Context == NULL) {\r
431 return EFI_INVALID_PARAMETER;\r
432 }\r
433\r
434 IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, Link, IP4_PROTOCOL_SIGNATURE);\r
435 ServiceBinding = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;\r
436 NumberOfChildren = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;\r
437 ChildHandleBuffer = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;\r
438\r
439 if (!NetIsInHandleBuffer (IpInstance->Handle, NumberOfChildren, ChildHandleBuffer)) {\r
440 return EFI_SUCCESS;\r
441 }\r
442\r
443 return ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);\r
444}\r
772db4bb 445\r
446/**\r
5405e9a6 447 Start this driver on ControllerHandle. This service is called by the\r
448 EFI boot service ConnectController(). In order to make\r
449 drivers as small as possible, there are a few calling restrictions for\r
450 this service. ConnectController() must follow these\r
451 calling restrictions. If any other agent wishes to call Start() it\r
452 must also follow these calling restrictions.\r
453\r
3e8c18da 454 @param[in] This Protocol instance pointer.\r
455 @param[in] ControllerHandle Handle of device to bind driver to\r
456 @param[in] RemainingDevicePath Optional parameter use to pick a specific child\r
457 device to start.\r
5405e9a6 458\r
459 @retval EFI_SUCCESS This driver is added to ControllerHandle\r
460 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
461 @retval other This driver does not support this device\r
772db4bb 462\r
463**/\r
464EFI_STATUS\r
465EFIAPI\r
466Ip4DriverBindingStart (\r
1f6729ff 467 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
772db4bb 468 IN EFI_HANDLE ControllerHandle,\r
1f6729ff 469 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
772db4bb 470 )\r
1f6729ff 471{ \r
472 EFI_STATUS Status;\r
473 IP4_SERVICE *IpSb;\r
772db4bb 474\r
475 //\r
476 // Test for the Ip4 service binding protocol\r
477 //\r
478 Status = gBS->OpenProtocol (\r
479 ControllerHandle,\r
480 &gEfiIp4ServiceBindingProtocolGuid,\r
481 NULL,\r
482 This->DriverBindingHandle,\r
483 ControllerHandle,\r
484 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
485 );\r
486\r
487 if (Status == EFI_SUCCESS) {\r
488 return EFI_ALREADY_STARTED;\r
489 }\r
1f6729ff 490 \r
772db4bb 491 Status = Ip4CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);\r
1f6729ff 492 \r
772db4bb 493 if (EFI_ERROR (Status)) {\r
494 return Status;\r
495 }\r
1f6729ff 496 \r
e2851998 497 ASSERT (IpSb != NULL);\r
772db4bb 498\r
499 //\r
500 // Install the Ip4ServiceBinding Protocol onto ControlerHandle\r
501 //\r
502 Status = gBS->InstallMultipleProtocolInterfaces (\r
503 &ControllerHandle,\r
504 &gEfiIp4ServiceBindingProtocolGuid,\r
505 &IpSb->ServiceBinding,\r
1f6729ff 506 &gEfiIp4Config2ProtocolGuid,\r
507 &IpSb->Ip4Config2Instance.Ip4Config2,\r
772db4bb 508 NULL\r
509 );\r
510\r
511 if (EFI_ERROR (Status)) {\r
512 goto FREE_SERVICE;\r
513 }\r
1f6729ff 514 \r
772db4bb 515 //\r
1f6729ff 516 // Ready to go: start the receiving and timer.\r
517 // Ip4Config2SetPolicy maybe call Ip4ReceiveFrame() to set the default interface's RecvRequest first after\r
518 // Ip4Config2 instance is initialized. So, EFI_ALREADY_STARTED is the allowed return status.\r
772db4bb 519 //\r
520 Status = Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);\r
521\r
1f6729ff 522 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
772db4bb 523 goto UNINSTALL_PROTOCOL;\r
524 }\r
525\r
526 Status = gBS->SetTimer (IpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);\r
527\r
528 if (EFI_ERROR (Status)) {\r
529 goto UNINSTALL_PROTOCOL;\r
530 }\r
531\r
532 //\r
533 // Initialize the IP4 ID\r
534 //\r
535 mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ());\r
536\r
772db4bb 537 return Status;\r
538\r
539UNINSTALL_PROTOCOL:\r
540 gBS->UninstallProtocolInterface (\r
541 ControllerHandle,\r
542 &gEfiIp4ServiceBindingProtocolGuid,\r
543 &IpSb->ServiceBinding\r
544 );\r
545\r
546FREE_SERVICE:\r
547 Ip4CleanService (IpSb);\r
766c7483 548 FreePool (IpSb);\r
772db4bb 549 return Status;\r
550}\r
551\r
552\r
553/**\r
5405e9a6 554 Stop this driver on ControllerHandle. This service is called by the\r
555 EFI boot service DisconnectController(). In order to\r
556 make drivers as small as possible, there are a few calling\r
557 restrictions for this service. DisconnectController()\r
558 must follow these calling restrictions. If any other agent wishes\r
559 to call Stop() it must also follow these calling restrictions.\r
e2851998 560\r
3e8c18da 561 @param[in] This Protocol instance pointer.\r
562 @param[in] ControllerHandle Handle of device to stop driver on\r
563 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number\r
564 of children is zero stop the entire bus driver.\r
565 @param[in] ChildHandleBuffer List of Child Handles to Stop.\r
5405e9a6 566\r
3e8c18da 567 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
568 @retval other This driver was not removed from this device\r
772db4bb 569\r
570**/\r
571EFI_STATUS\r
572EFIAPI\r
573Ip4DriverBindingStop (\r
574 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
575 IN EFI_HANDLE ControllerHandle,\r
576 IN UINTN NumberOfChildren,\r
577 IN EFI_HANDLE *ChildHandleBuffer\r
578 )\r
579{\r
216f7970 580 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
581 IP4_SERVICE *IpSb; \r
582 EFI_HANDLE NicHandle;\r
583 EFI_STATUS Status; \r
584 INTN State;\r
585 LIST_ENTRY *List;\r
586 IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;\r
d0ccf55e 587 IP4_INTERFACE *IpIf;\r
588 IP4_ROUTE_TABLE *RouteTable;\r
772db4bb 589\r
1f6729ff 590 BOOLEAN IsDhcp4;\r
772db4bb 591\r
1f6729ff 592 IsDhcp4 = FALSE;\r
593 \r
772db4bb 594 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);\r
772db4bb 595 if (NicHandle == NULL) {\r
596 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);\r
216f7970 597 if (NicHandle == NULL) {\r
1f6729ff 598 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);\r
599 if (NicHandle != NULL) {\r
600 IsDhcp4 = TRUE; \r
601 } else {\r
602 return EFI_SUCCESS;\r
603 }\r
216f7970 604 }\r
772db4bb 605 }\r
1f6729ff 606 \r
772db4bb 607 Status = gBS->OpenProtocol (\r
608 NicHandle,\r
609 &gEfiIp4ServiceBindingProtocolGuid,\r
610 (VOID **) &ServiceBinding,\r
611 This->DriverBindingHandle,\r
612 NicHandle,\r
613 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
614 );\r
772db4bb 615 if (EFI_ERROR (Status)) {\r
616 return EFI_DEVICE_ERROR;\r
617 }\r
1f6729ff 618 \r
619 IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);\r
772db4bb 620\r
1f6729ff 621 if (IsDhcp4) {\r
622 Status = Ip4Config2DestroyDhcp4 (&IpSb->Ip4Config2Instance);\r
623 gBS->CloseEvent (IpSb->Ip4Config2Instance.Dhcp4Event);\r
624 IpSb->Ip4Config2Instance.Dhcp4Event = NULL;\r
625 } else if (NumberOfChildren != 0) {\r
216f7970 626 List = &IpSb->Children;\r
627 Context.ServiceBinding = ServiceBinding;\r
628 Context.NumberOfChildren = NumberOfChildren;\r
629 Context.ChildHandleBuffer = ChildHandleBuffer;\r
630 Status = NetDestroyLinkList (\r
631 List,\r
632 Ip4DestroyChildEntryInHandleBuffer,\r
633 &Context,\r
634 NULL\r
635 );\r
d0ccf55e 636 } else if (IpSb->DefaultInterface->ArpHandle == ControllerHandle) {\r
1f6729ff 637 \r
d0ccf55e 638 //\r
639 // The ARP protocol for the default interface is being uninstalled and all\r
640 // its IP child handles should have been destroyed before. So, release the\r
641 // default interface and route table, create a new one and mark it as not started.\r
642 //\r
643 Ip4CancelReceive (IpSb->DefaultInterface);\r
644 Ip4FreeInterface (IpSb->DefaultInterface, NULL);\r
645 Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
646 \r
647 IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
648 if (IpIf == NULL) {\r
649 goto ON_ERROR;\r
650 }\r
651 RouteTable = Ip4CreateRouteTable ();\r
652 if (RouteTable == NULL) {\r
653 Ip4FreeInterface (IpIf, NULL);\r
654 goto ON_ERROR;;\r
655 }\r
656 \r
657 IpSb->DefaultInterface = IpIf;\r
658 InsertHeadList (&IpSb->Interfaces, &IpIf->Link);\r
659 IpSb->DefaultRouteTable = RouteTable;\r
660 Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);\r
661\r
d0ccf55e 662 IpSb->State = IP4_SERVICE_UNSTARTED;\r
1f6729ff 663\r
216f7970 664 } else if (IsListEmpty (&IpSb->Children)) {\r
c4a62a12 665 State = IpSb->State;\r
75dce340 666 IpSb->State = IP4_SERVICE_DESTROY;\r
772db4bb 667\r
c4a62a12 668 //\r
669 // OK, clean other resources then uninstall the service binding protocol.\r
670 //\r
671 Status = Ip4CleanService (IpSb);\r
c4a62a12 672 if (EFI_ERROR (Status)) {\r
673 IpSb->State = State;\r
674 goto ON_ERROR;\r
675 }\r
772db4bb 676\r
1f6729ff 677 gBS->UninstallMultipleProtocolInterfaces (\r
c4a62a12 678 NicHandle,\r
679 &gEfiIp4ServiceBindingProtocolGuid,\r
1f6729ff 680 ServiceBinding,\r
681 &gEfiIp4Config2ProtocolGuid,\r
682 &IpSb->Ip4Config2Instance.Ip4Config2,\r
683 NULL\r
c4a62a12 684 );\r
216f7970 685 \r
686 if (gIp4ControllerNameTable != NULL) {\r
687 FreeUnicodeStringTable (gIp4ControllerNameTable);\r
688 gIp4ControllerNameTable = NULL;\r
c4a62a12 689 }\r
766c7483 690 FreePool (IpSb);\r
c4a62a12 691 }\r
772db4bb 692\r
693ON_ERROR:\r
772db4bb 694 return Status;\r
695}\r
696\r
697\r
698/**\r
3e8c18da 699 Creates a child handle and installs a protocol.\r
e2851998 700\r
701 The CreateChild() function installs a protocol on ChildHandle.\r
702 If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.\r
3e8c18da 703 If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.\r
772db4bb 704\r
3e8c18da 705 @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
706 @param ChildHandle Pointer to the handle of the child to create. If it is NULL,\r
e2851998 707 then a new handle is created. If it is a pointer to an existing UEFI handle,\r
3e8c18da 708 then the protocol is added to the existing UEFI handle.\r
772db4bb 709\r
3e8c18da 710 @retval EFI_SUCCES The protocol was added to ChildHandle.\r
5405e9a6 711 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.\r
712 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create\r
713 the child\r
714 @retval other The child handle was not created\r
772db4bb 715\r
716**/\r
717EFI_STATUS\r
718EFIAPI\r
719Ip4ServiceBindingCreateChild (\r
720 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
5405e9a6 721 IN OUT EFI_HANDLE *ChildHandle\r
772db4bb 722 )\r
723{\r
724 IP4_SERVICE *IpSb;\r
725 IP4_PROTOCOL *IpInstance;\r
726 EFI_TPL OldTpl;\r
727 EFI_STATUS Status;\r
728 VOID *Mnp;\r
729\r
730 if ((This == NULL) || (ChildHandle == NULL)) {\r
731 return EFI_INVALID_PARAMETER;\r
732 }\r
733\r
734 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);\r
e48e37fc 735 IpInstance = AllocatePool (sizeof (IP4_PROTOCOL));\r
772db4bb 736\r
737 if (IpInstance == NULL) {\r
738 return EFI_OUT_OF_RESOURCES;\r
739 }\r
740\r
741 Ip4InitProtocol (IpSb, IpInstance);\r
742\r
743 //\r
744 // Install Ip4 onto ChildHandle\r
745 //\r
746 Status = gBS->InstallMultipleProtocolInterfaces (\r
747 ChildHandle,\r
748 &gEfiIp4ProtocolGuid,\r
749 &IpInstance->Ip4Proto,\r
750 NULL\r
751 );\r
752\r
753 if (EFI_ERROR (Status)) {\r
754 goto ON_ERROR;\r
755 }\r
756\r
757 IpInstance->Handle = *ChildHandle;\r
758\r
759 //\r
760 // Open the Managed Network protocol BY_CHILD.\r
761 //\r
762 Status = gBS->OpenProtocol (\r
763 IpSb->MnpChildHandle,\r
764 &gEfiManagedNetworkProtocolGuid,\r
765 (VOID **) &Mnp,\r
766 gIp4DriverBinding.DriverBindingHandle,\r
767 IpInstance->Handle,\r
768 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
769 );\r
770 if (EFI_ERROR (Status)) {\r
771 gBS->UninstallMultipleProtocolInterfaces (\r
772 ChildHandle,\r
773 &gEfiIp4ProtocolGuid,\r
774 &IpInstance->Ip4Proto,\r
775 NULL\r
776 );\r
777\r
778 goto ON_ERROR;\r
779 }\r
780\r
781 //\r
782 // Insert it into the service binding instance.\r
783 //\r
e48e37fc 784 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 785\r
e48e37fc 786 InsertTailList (&IpSb->Children, &IpInstance->Link);\r
772db4bb 787 IpSb->NumChildren++;\r
788\r
e48e37fc 789 gBS->RestoreTPL (OldTpl);\r
772db4bb 790\r
791ON_ERROR:\r
792\r
793 if (EFI_ERROR (Status)) {\r
794\r
795 Ip4CleanProtocol (IpInstance);\r
796\r
766c7483 797 FreePool (IpInstance);\r
772db4bb 798 }\r
799\r
800 return Status;\r
801}\r
802\r
803\r
804/**\r
3e8c18da 805 Destroys a child handle with a protocol installed on it.\r
e2851998 806\r
807 The DestroyChild() function does the opposite of CreateChild(). It removes a protocol\r
808 that was installed by CreateChild() from ChildHandle. If the removed protocol is the\r
3e8c18da 809 last protocol on ChildHandle, then ChildHandle is destroyed.\r
772db4bb 810\r
3e8c18da 811 @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
5405e9a6 812 @param ChildHandle Handle of the child to destroy\r
813\r
3e8c18da 814 @retval EFI_SUCCES The protocol was removed from ChildHandle.\r
815 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.\r
284ee2e8 816 @retval EFI_INVALID_PARAMETER Child handle is NULL.\r
3e8c18da 817 @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle\r
818 because its services are being used.\r
5405e9a6 819 @retval other The child handle was not destroyed\r
772db4bb 820\r
821**/\r
822EFI_STATUS\r
823EFIAPI\r
824Ip4ServiceBindingDestroyChild (\r
825 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
826 IN EFI_HANDLE ChildHandle\r
827 )\r
828{\r
829 EFI_STATUS Status;\r
830 IP4_SERVICE *IpSb;\r
831 IP4_PROTOCOL *IpInstance;\r
832 EFI_IP4_PROTOCOL *Ip4;\r
833 EFI_TPL OldTpl;\r
834 INTN State;\r
835\r
836 if ((This == NULL) || (ChildHandle == NULL)) {\r
837 return EFI_INVALID_PARAMETER;\r
838 }\r
839\r
840 //\r
841 // Retrieve the private context data structures\r
842 //\r
843 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);\r
844\r
845 Status = gBS->OpenProtocol (\r
846 ChildHandle,\r
847 &gEfiIp4ProtocolGuid,\r
848 (VOID **) &Ip4,\r
849 gIp4DriverBinding.DriverBindingHandle,\r
850 ChildHandle,\r
851 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
852 );\r
853\r
854 if (EFI_ERROR (Status)) {\r
855 return EFI_UNSUPPORTED;\r
856 }\r
857\r
858 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);\r
859\r
860 if (IpInstance->Service != IpSb) {\r
861 return EFI_INVALID_PARAMETER;\r
862 }\r
863\r
e48e37fc 864 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 865\r
866 //\r
75dce340 867 // A child can be destroyed more than once. For example,\r
868 // Ip4DriverBindingStop will destroy all of its children.\r
869 // when UDP driver is being stopped, it will destroy all\r
772db4bb 870 // the IP child it opens.\r
871 //\r
75dce340 872 if (IpInstance->State == IP4_STATE_DESTROY) {\r
e48e37fc 873 gBS->RestoreTPL (OldTpl);\r
772db4bb 874 return EFI_SUCCESS;\r
875 }\r
876\r
877 State = IpInstance->State;\r
75dce340 878 IpInstance->State = IP4_STATE_DESTROY;\r
772db4bb 879\r
880 //\r
881 // Close the Managed Network protocol.\r
882 //\r
883 gBS->CloseProtocol (\r
884 IpSb->MnpChildHandle,\r
885 &gEfiManagedNetworkProtocolGuid,\r
886 gIp4DriverBinding.DriverBindingHandle,\r
887 ChildHandle\r
888 );\r
889\r
216f7970 890 if (IpInstance->Interface != NULL && IpInstance->Interface->Arp != NULL) {\r
891 gBS->CloseProtocol (\r
892 IpInstance->Interface->ArpHandle,\r
893 &gEfiArpProtocolGuid,\r
894 gIp4DriverBinding.DriverBindingHandle,\r
895 ChildHandle\r
896 );\r
897 }\r
898\r
772db4bb 899 //\r
900 // Uninstall the IP4 protocol first. Many thing happens during\r
901 // this:\r
902 // 1. The consumer of the IP4 protocol will be stopped if it\r
903 // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is\r
904 // stopped, IP driver's stop function will be called, and uninstall\r
905 // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This\r
906 // makes it possible to create the network stack bottom up, and\r
907 // stop it top down.\r
908 // 2. the upper layer will recycle the received packet. The recycle\r
909 // event's TPL is higher than this function. The recycle events\r
910 // will be called back before preceeding. If any packets not recycled,\r
911 // that means there is a resource leak.\r
912 //\r
216f7970 913 gBS->RestoreTPL (OldTpl);\r
772db4bb 914 Status = gBS->UninstallProtocolInterface (\r
915 ChildHandle,\r
916 &gEfiIp4ProtocolGuid,\r
917 &IpInstance->Ip4Proto\r
918 );\r
216f7970 919 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 920 if (EFI_ERROR (Status)) {\r
921 goto ON_ERROR;\r
922 }\r
923\r
924 Status = Ip4CleanProtocol (IpInstance);\r
772db4bb 925 if (EFI_ERROR (Status)) {\r
926 gBS->InstallMultipleProtocolInterfaces (\r
927 &ChildHandle,\r
928 &gEfiIp4ProtocolGuid,\r
929 Ip4,\r
930 NULL\r
931 );\r
932\r
933 goto ON_ERROR;\r
934 }\r
935\r
e48e37fc 936 RemoveEntryList (&IpInstance->Link);\r
772db4bb 937 IpSb->NumChildren--;\r
938\r
e48e37fc 939 gBS->RestoreTPL (OldTpl);\r
772db4bb 940\r
766c7483 941 FreePool (IpInstance);\r
772db4bb 942 return EFI_SUCCESS;\r
943\r
944ON_ERROR:\r
945 IpInstance->State = State;\r
e48e37fc 946 gBS->RestoreTPL (OldTpl);\r
772db4bb 947\r
948 return Status;\r
949}\r