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