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