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