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