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