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