1 /** @file
2   Driver Binding functions implementation for UEFI HTTP boot.
3 
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "HttpBootDxe.h"
10 
11 ///
12 /// Driver Binding Protocol instance
13 ///
14 EFI_DRIVER_BINDING_PROTOCOL gHttpBootIp4DxeDriverBinding = {
15   HttpBootIp4DxeDriverBindingSupported,
16   HttpBootIp4DxeDriverBindingStart,
17   HttpBootIp4DxeDriverBindingStop,
18   HTTP_BOOT_DXE_VERSION,
19   NULL,
20   NULL
21 };
22 
23 EFI_DRIVER_BINDING_PROTOCOL gHttpBootIp6DxeDriverBinding = {
24   HttpBootIp6DxeDriverBindingSupported,
25   HttpBootIp6DxeDriverBindingStart,
26   HttpBootIp6DxeDriverBindingStop,
27   HTTP_BOOT_DXE_VERSION,
28   NULL,
29   NULL
30 };
31 
32 
33 
34 /**
35   Check whether UNDI protocol supports IPv6.
36 
37   @param[in]   Private           Pointer to HTTP_BOOT_PRIVATE_DATA.
38   @param[out]  Ipv6Support       TRUE if UNDI supports IPv6.
39 
40   @retval EFI_SUCCESS            Get the result whether UNDI supports IPv6 by NII or AIP protocol successfully.
41   @retval EFI_NOT_FOUND          Don't know whether UNDI supports IPv6 since NII or AIP is not available.
42 
43 **/
44 EFI_STATUS
HttpBootCheckIpv6Support(IN HTTP_BOOT_PRIVATE_DATA * Private,OUT BOOLEAN * Ipv6Support)45 HttpBootCheckIpv6Support (
46   IN  HTTP_BOOT_PRIVATE_DATA       *Private,
47   OUT BOOLEAN                      *Ipv6Support
48   )
49 {
50   EFI_HANDLE                       Handle;
51   EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;
52   EFI_STATUS                       Status;
53   EFI_GUID                         *InfoTypesBuffer;
54   UINTN                            InfoTypeBufferCount;
55   UINTN                            TypeIndex;
56   BOOLEAN                          Supported;
57   VOID                             *InfoBlock;
58   UINTN                            InfoBlockSize;
59 
60   ASSERT (Private != NULL && Ipv6Support != NULL);
61 
62   //
63   // Check whether the UNDI supports IPv6 by NII protocol.
64   //
65   if (Private->Nii != NULL) {
66     *Ipv6Support = Private->Nii->Ipv6Supported;
67     return EFI_SUCCESS;
68   }
69 
70   //
71   // Get the NIC handle by SNP protocol.
72   //
73   Handle = NetLibGetSnpHandle (Private->Controller, NULL);
74   if (Handle == NULL) {
75     return EFI_NOT_FOUND;
76   }
77 
78   Aip    = NULL;
79   Status = gBS->HandleProtocol (
80                   Handle,
81                   &gEfiAdapterInformationProtocolGuid,
82                   (VOID *) &Aip
83                   );
84   if (EFI_ERROR (Status) || Aip == NULL) {
85     return EFI_NOT_FOUND;
86   }
87 
88   InfoTypesBuffer     = NULL;
89   InfoTypeBufferCount = 0;
90   Status = Aip->GetSupportedTypes (Aip, &InfoTypesBuffer, &InfoTypeBufferCount);
91   if (EFI_ERROR (Status) || InfoTypesBuffer == NULL) {
92     FreePool (InfoTypesBuffer);
93     return EFI_NOT_FOUND;
94   }
95 
96   Supported = FALSE;
97   for (TypeIndex = 0; TypeIndex < InfoTypeBufferCount; TypeIndex++) {
98     if (CompareGuid (&InfoTypesBuffer[TypeIndex], &gEfiAdapterInfoUndiIpv6SupportGuid)) {
99       Supported = TRUE;
100       break;
101     }
102   }
103 
104   FreePool (InfoTypesBuffer);
105   if (!Supported) {
106     return EFI_NOT_FOUND;
107   }
108 
109   //
110   // We now have adapter information block.
111   //
112   InfoBlock     = NULL;
113   InfoBlockSize = 0;
114   Status = Aip->GetInformation (Aip, &gEfiAdapterInfoUndiIpv6SupportGuid, &InfoBlock, &InfoBlockSize);
115   if (EFI_ERROR (Status) || InfoBlock == NULL) {
116     FreePool (InfoBlock);
117     return EFI_NOT_FOUND;
118   }
119 
120   *Ipv6Support = ((EFI_ADAPTER_INFO_UNDI_IPV6_SUPPORT *) InfoBlock)->Ipv6Support;
121   FreePool (InfoBlock);
122 
123   return EFI_SUCCESS;
124 }
125 
126 /**
127   Destroy the HTTP child based on IPv4 stack.
128 
129   @param[in]  This              Pointer to the EFI_DRIVER_BINDING_PROTOCOL.
130   @param[in]  Private           Pointer to HTTP_BOOT_PRIVATE_DATA.
131 
132 **/
133 VOID
HttpBootDestroyIp4Children(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN HTTP_BOOT_PRIVATE_DATA * Private)134 HttpBootDestroyIp4Children (
135   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
136   IN HTTP_BOOT_PRIVATE_DATA       *Private
137   )
138 {
139   ASSERT (This != NULL);
140   ASSERT (Private != NULL);
141 
142   if (Private->Dhcp4Child != NULL) {
143     gBS->CloseProtocol (
144            Private->Dhcp4Child,
145            &gEfiDhcp4ProtocolGuid,
146            This->DriverBindingHandle,
147            Private->Controller
148            );
149 
150     NetLibDestroyServiceChild (
151       Private->Controller,
152       This->DriverBindingHandle,
153       &gEfiDhcp4ServiceBindingProtocolGuid,
154       Private->Dhcp4Child
155       );
156   }
157 
158   if (Private->Ip6Nic == NULL && Private->HttpCreated) {
159     HttpIoDestroyIo (&Private->HttpIo);
160     Private->HttpCreated = FALSE;
161   }
162 
163   if (Private->Ip4Nic != NULL) {
164 
165     gBS->CloseProtocol (
166            Private->Controller,
167            &gEfiCallerIdGuid,
168            This->DriverBindingHandle,
169            Private->Ip4Nic->Controller
170            );
171 
172     gBS->UninstallMultipleProtocolInterfaces (
173            Private->Ip4Nic->Controller,
174            &gEfiLoadFileProtocolGuid,
175            &Private->Ip4Nic->LoadFile,
176            &gEfiDevicePathProtocolGuid,
177            Private->Ip4Nic->DevicePath,
178            NULL
179            );
180     FreePool (Private->Ip4Nic);
181     Private->Ip4Nic = NULL;
182   }
183 
184 }
185 
186 /**
187   Destroy the HTTP child based on IPv6 stack.
188 
189   @param[in]  This              Pointer to the EFI_DRIVER_BINDING_PROTOCOL.
190   @param[in]  Private           Pointer to HTTP_BOOT_PRIVATE_DATA.
191 
192 **/
193 VOID
HttpBootDestroyIp6Children(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN HTTP_BOOT_PRIVATE_DATA * Private)194 HttpBootDestroyIp6Children (
195   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
196   IN HTTP_BOOT_PRIVATE_DATA       *Private
197   )
198 {
199   ASSERT (This != NULL);
200   ASSERT (Private != NULL);
201 
202   if (Private->Ip6Child != NULL) {
203     gBS->CloseProtocol (
204            Private->Ip6Child,
205            &gEfiIp6ProtocolGuid,
206            This->DriverBindingHandle,
207            Private->Controller
208            );
209 
210     NetLibDestroyServiceChild (
211       Private->Controller,
212       This->DriverBindingHandle,
213       &gEfiIp6ServiceBindingProtocolGuid,
214       Private->Ip6Child
215       );
216   }
217 
218   if (Private->Dhcp6Child != NULL) {
219     gBS->CloseProtocol (
220            Private->Dhcp6Child,
221            &gEfiDhcp6ProtocolGuid,
222            This->DriverBindingHandle,
223            Private->Controller
224            );
225 
226     NetLibDestroyServiceChild (
227       Private->Controller,
228       This->DriverBindingHandle,
229       &gEfiDhcp6ServiceBindingProtocolGuid,
230       Private->Dhcp6Child
231       );
232   }
233 
234   if (Private->Ip4Nic == NULL && Private->HttpCreated) {
235     HttpIoDestroyIo(&Private->HttpIo);
236     Private->HttpCreated = FALSE;
237   }
238 
239   if (Private->Ip6Nic != NULL) {
240 
241     gBS->CloseProtocol (
242            Private->Controller,
243            &gEfiCallerIdGuid,
244            This->DriverBindingHandle,
245            Private->Ip6Nic->Controller
246            );
247 
248     gBS->UninstallMultipleProtocolInterfaces (
249            Private->Ip6Nic->Controller,
250            &gEfiLoadFileProtocolGuid,
251            &Private->Ip6Nic->LoadFile,
252            &gEfiDevicePathProtocolGuid,
253            Private->Ip6Nic->DevicePath,
254            NULL
255            );
256     FreePool (Private->Ip6Nic);
257     Private->Ip6Nic = NULL;
258   }
259 }
260 
261 /**
262   Tests to see if this driver supports a given controller. If a child device is provided,
263   it further tests to see if this driver supports creating a handle for the specified child device.
264 
265   This function checks to see if the driver specified by This supports the device specified by
266   ControllerHandle. Drivers will typically use the device path attached to
267   ControllerHandle and/or the services from the bus I/O abstraction attached to
268   ControllerHandle to determine if the driver supports ControllerHandle. This function
269   may be called many times during platform initialization. In order to reduce boot times, the tests
270   performed by this function must be very small, and take as little time as possible to execute. This
271   function must not change the state of any hardware devices, and this function must be aware that the
272   device specified by ControllerHandle may already be managed by the same driver or a
273   different driver. This function must match its calls to AllocatePages() with FreePages(),
274   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
275   Because ControllerHandle may have been previously started by the same driver, if a protocol is
276   already in the opened state, then it must not be closed with CloseProtocol(). This is required
277   to guarantee the state of ControllerHandle is not modified by this function.
278 
279   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
280   @param[in]  ControllerHandle     The handle of the controller to test. This handle
281                                    must support a protocol interface that supplies
282                                    an I/O abstraction to the driver.
283   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
284                                    parameter is ignored by device drivers, and is optional for bus
285                                    drivers. For bus drivers, if this parameter is not NULL, then
286                                    the bus driver must determine if the bus controller specified
287                                    by ControllerHandle and the child controller specified
288                                    by RemainingDevicePath are both supported by this
289                                    bus driver.
290 
291   @retval EFI_SUCCESS              The device specified by ControllerHandle and
292                                    RemainingDevicePath is supported by the driver specified by This.
293   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
294                                    RemainingDevicePath is already being managed by the driver
295                                    specified by This.
296   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
297                                    RemainingDevicePath is already being managed by a different
298                                    driver or an application that requires exclusive access.
299                                    Currently not implemented.
300   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
301                                    RemainingDevicePath is not supported by the driver specified by This.
302 **/
303 EFI_STATUS
304 EFIAPI
HttpBootIp4DxeDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)305 HttpBootIp4DxeDriverBindingSupported (
306   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
307   IN EFI_HANDLE                   ControllerHandle,
308   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
309   )
310 {
311   EFI_STATUS                    Status;
312 
313   //
314   // Try to open the DHCP4, HTTP4 and Device Path protocol.
315   //
316   Status = gBS->OpenProtocol (
317                   ControllerHandle,
318                   &gEfiDhcp4ServiceBindingProtocolGuid,
319                   NULL,
320                   This->DriverBindingHandle,
321                   ControllerHandle,
322                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
323                   );
324   if (EFI_ERROR (Status)) {
325     return Status;
326   }
327 
328   Status = gBS->OpenProtocol (
329                   ControllerHandle,
330                   &gEfiHttpServiceBindingProtocolGuid,
331                   NULL,
332                   This->DriverBindingHandle,
333                   ControllerHandle,
334                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
335                   );
336   if (EFI_ERROR (Status)) {
337     return Status;
338   }
339 
340   Status = gBS->OpenProtocol (
341                   ControllerHandle,
342                   &gEfiDevicePathProtocolGuid,
343                   NULL,
344                   This->DriverBindingHandle,
345                   ControllerHandle,
346                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
347                   );
348 
349   return Status;
350 }
351 
352 
353 /**
354   Starts a device controller or a bus controller.
355 
356   The Start() function is designed to be invoked from the EFI boot service ConnectController().
357   As a result, much of the error checking on the parameters to Start() has been moved into this
358   common boot service. It is legal to call Start() from other locations,
359   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
360   1. ControllerHandle must be a valid EFI_HANDLE.
361   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
362      EFI_DEVICE_PATH_PROTOCOL.
363   3. Prior to calling Start(), the Supported() function for the driver specified by This must
364      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
365 
366   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
367   @param[in]  ControllerHandle     The handle of the controller to start. This handle
368                                    must support a protocol interface that supplies
369                                    an I/O abstraction to the driver.
370   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
371                                    parameter is ignored by device drivers, and is optional for bus
372                                    drivers. For a bus driver, if this parameter is NULL, then handles
373                                    for all the children of Controller are created by this driver.
374                                    If this parameter is not NULL and the first Device Path Node is
375                                    not the End of Device Path Node, then only the handle for the
376                                    child device specified by the first Device Path Node of
377                                    RemainingDevicePath is created by this driver.
378                                    If the first Device Path Node of RemainingDevicePath is
379                                    the End of Device Path Node, no child handle is created by this
380                                    driver.
381 
382   @retval EFI_SUCCESS              The device was started.
383   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
384   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
385   @retval Others                   The driver failded to start the device.
386 
387 **/
388 EFI_STATUS
389 EFIAPI
HttpBootIp4DxeDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)390 HttpBootIp4DxeDriverBindingStart (
391   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
392   IN EFI_HANDLE                   ControllerHandle,
393   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
394   )
395 {
396   EFI_STATUS                 Status;
397   HTTP_BOOT_PRIVATE_DATA     *Private;
398   EFI_DEV_PATH               *Node;
399   EFI_DEVICE_PATH_PROTOCOL   *DevicePath;
400   UINT32                     *Id;
401   BOOLEAN                    FirstStart;
402 
403   FirstStart = FALSE;
404 
405   Status = gBS->OpenProtocol (
406                   ControllerHandle,
407                   &gEfiCallerIdGuid,
408                   (VOID **) &Id,
409                   This->DriverBindingHandle,
410                   ControllerHandle,
411                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
412                   );
413 
414   if (!EFI_ERROR (Status)) {
415     Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id);
416   } else {
417     FirstStart = TRUE;
418 
419     //
420     // Initialize the private data structure.
421     //
422     Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA));
423     if (Private == NULL) {
424       return EFI_OUT_OF_RESOURCES;
425     }
426     Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;
427     Private->Controller = ControllerHandle;
428     InitializeListHead (&Private->CacheList);
429     //
430     // Get the NII interface if it exists, it's not required.
431     //
432     Status = gBS->OpenProtocol (
433                     ControllerHandle,
434                     &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
435                     (VOID **) &Private->Nii,
436                     This->DriverBindingHandle,
437                     ControllerHandle,
438                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
439                     );
440     if (EFI_ERROR (Status)) {
441       Private->Nii = NULL;
442     }
443 
444     //
445     // Open Device Path Protocol to prepare for appending IP and URI node.
446     //
447     Status = gBS->OpenProtocol (
448                     ControllerHandle,
449                     &gEfiDevicePathProtocolGuid,
450                     (VOID **) &Private->ParentDevicePath,
451                     This->DriverBindingHandle,
452                     ControllerHandle,
453                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
454                     );
455     if (EFI_ERROR (Status)) {
456       goto ON_ERROR;
457     }
458 
459     //
460     // Initialize the HII configuration form.
461     //
462     Status = HttpBootConfigFormInit (Private);
463     if (EFI_ERROR (Status)) {
464       goto ON_ERROR;
465     }
466 
467     //
468     // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between
469     // NIC handle and the private data.
470     //
471     Status = gBS->InstallProtocolInterface (
472                     &ControllerHandle,
473                     &gEfiCallerIdGuid,
474                     EFI_NATIVE_INTERFACE,
475                     &Private->Id
476                     );
477     if (EFI_ERROR (Status)) {
478       goto ON_ERROR;
479     }
480 
481   }
482 
483   if (Private->Ip4Nic != NULL) {
484     //
485     // Already created before
486     //
487     return EFI_SUCCESS;
488   }
489 
490   Private->Ip4Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC));
491   if (Private->Ip4Nic == NULL) {
492     Status = EFI_OUT_OF_RESOURCES;
493     goto ON_ERROR;
494   }
495   Private->Ip4Nic->Private     = Private;
496   Private->Ip4Nic->ImageHandle = This->DriverBindingHandle;
497   Private->Ip4Nic->Signature   = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;
498 
499   //
500   // Create DHCP4 child instance.
501   //
502   Status = NetLibCreateServiceChild (
503              ControllerHandle,
504              This->DriverBindingHandle,
505              &gEfiDhcp4ServiceBindingProtocolGuid,
506              &Private->Dhcp4Child
507              );
508   if (EFI_ERROR (Status)) {
509     goto ON_ERROR;
510   }
511 
512   Status = gBS->OpenProtocol (
513                   Private->Dhcp4Child,
514                   &gEfiDhcp4ProtocolGuid,
515                   (VOID **) &Private->Dhcp4,
516                   This->DriverBindingHandle,
517                   ControllerHandle,
518                   EFI_OPEN_PROTOCOL_BY_DRIVER
519                   );
520   if (EFI_ERROR (Status)) {
521     goto ON_ERROR;
522   }
523 
524   //
525   // Get the Ip4Config2 protocol, it's required to configure the default gateway address.
526   //
527   Status = gBS->OpenProtocol (
528                   ControllerHandle,
529                   &gEfiIp4Config2ProtocolGuid,
530                   (VOID **) &Private->Ip4Config2,
531                   This->DriverBindingHandle,
532                   ControllerHandle,
533                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
534                   );
535   if (EFI_ERROR (Status)) {
536     goto ON_ERROR;
537   }
538 
539   //
540   // Append IPv4 device path node.
541   //
542   Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH));
543   if (Node == NULL) {
544     Status = EFI_OUT_OF_RESOURCES;
545     goto ON_ERROR;
546   }
547   Node->Ipv4.Header.Type = MESSAGING_DEVICE_PATH;
548   Node->Ipv4.Header.SubType = MSG_IPv4_DP;
549   SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH));
550   Node->Ipv4.StaticIpAddress = FALSE;
551   DevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
552   FreePool (Node);
553   if (DevicePath == NULL) {
554     Status = EFI_OUT_OF_RESOURCES;
555     goto ON_ERROR;
556   }
557 
558   //
559   // Append URI device path node.
560   //
561   Node = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL));
562   if (Node == NULL) {
563     Status = EFI_OUT_OF_RESOURCES;
564     goto ON_ERROR;
565   }
566   Node->DevPath.Type = MESSAGING_DEVICE_PATH;
567   Node->DevPath.SubType = MSG_URI_DP;
568   SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL));
569   Private->Ip4Nic->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
570   FreePool (Node);
571   FreePool (DevicePath);
572   if (Private->Ip4Nic->DevicePath == NULL) {
573     Status = EFI_OUT_OF_RESOURCES;
574     goto ON_ERROR;
575   }
576 
577   //
578   // Create a child handle for the HTTP boot and install DevPath and Load file protocol on it.
579   //
580   CopyMem (&Private->Ip4Nic->LoadFile, &gHttpBootDxeLoadFile, sizeof (EFI_LOAD_FILE_PROTOCOL));
581   Status = gBS->InstallMultipleProtocolInterfaces (
582                   &Private->Ip4Nic->Controller,
583                   &gEfiLoadFileProtocolGuid,
584                   &Private->Ip4Nic->LoadFile,
585                   &gEfiDevicePathProtocolGuid,
586                   Private->Ip4Nic->DevicePath,
587                   NULL
588                   );
589   if (EFI_ERROR (Status)) {
590     goto ON_ERROR;
591   }
592 
593   //
594   // Open the Caller Id child to setup a parent-child relationship between
595   // real NIC handle and the HTTP boot Ipv4 NIC handle.
596   //
597   Status = gBS->OpenProtocol (
598                   ControllerHandle,
599                   &gEfiCallerIdGuid,
600                   (VOID **) &Id,
601                   This->DriverBindingHandle,
602                   Private->Ip4Nic->Controller,
603                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
604                   );
605   if (EFI_ERROR (Status)) {
606     goto ON_ERROR;
607   }
608 
609   return EFI_SUCCESS;
610 
611 ON_ERROR:
612   if (Private != NULL) {
613     if (FirstStart) {
614       gBS->UninstallProtocolInterface (
615              ControllerHandle,
616              &gEfiCallerIdGuid,
617              &Private->Id
618              );
619     }
620 
621     HttpBootDestroyIp4Children (This, Private);
622     HttpBootConfigFormUnload (Private);
623 
624     if (FirstStart) {
625       FreePool (Private);
626     }
627   }
628 
629   return Status;
630 }
631 
632 
633 /**
634   Stops a device controller or a bus controller.
635 
636   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
637   As a result, much of the error checking on the parameters to Stop() has been moved
638   into this common boot service. It is legal to call Stop() from other locations,
639   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
640   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
641      same driver's Start() function.
642   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
643      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
644      Start() function, and the Start() function must have called OpenProtocol() on
645      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
646 
647   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
648   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
649                                 support a bus specific I/O protocol for the driver
650                                 to use to stop the device.
651   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
652   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
653                                 if NumberOfChildren is 0.
654 
655   @retval EFI_SUCCESS           The device was stopped.
656   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
657 
658 **/
659 EFI_STATUS
660 EFIAPI
HttpBootIp4DxeDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)661 HttpBootIp4DxeDriverBindingStop (
662   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
663   IN EFI_HANDLE                   ControllerHandle,
664   IN UINTN                        NumberOfChildren,
665   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
666   )
667 {
668   EFI_STATUS                      Status;
669   EFI_LOAD_FILE_PROTOCOL          *LoadFile;
670   HTTP_BOOT_PRIVATE_DATA          *Private;
671   EFI_HANDLE                      NicHandle;
672   UINT32                          *Id;
673 
674   //
675   // Try to get the Load File Protocol from the controller handle.
676   //
677   Status = gBS->OpenProtocol (
678                   ControllerHandle,
679                   &gEfiLoadFileProtocolGuid,
680                   (VOID **) &LoadFile,
681                   This->DriverBindingHandle,
682                   ControllerHandle,
683                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
684                   );
685   if (EFI_ERROR (Status)) {
686     //
687     // If failed, try to find the NIC handle for this controller.
688     //
689     NicHandle = HttpBootGetNicByIp4Children (ControllerHandle);
690     if (NicHandle == NULL) {
691       return EFI_SUCCESS;
692     }
693 
694     //
695     // Try to retrieve the private data by the Caller Id Guid.
696     //
697     Status = gBS->OpenProtocol (
698                     NicHandle,
699                     &gEfiCallerIdGuid,
700                     (VOID **) &Id,
701                     This->DriverBindingHandle,
702                     ControllerHandle,
703                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
704                     );
705     if (EFI_ERROR (Status)) {
706       return Status;
707     }
708     Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID (Id);
709   } else {
710     Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (LoadFile);
711     NicHandle = Private->Controller;
712   }
713 
714   //
715   // Disable the HTTP boot function.
716   //
717   Status = HttpBootStop (Private);
718   if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) {
719     return Status;
720   }
721 
722   //
723   // Destory all child instance and uninstall protocol interface.
724   //
725   HttpBootDestroyIp4Children (This, Private);
726 
727   if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) {
728     //
729     // Release the cached data.
730     //
731     HttpBootFreeCacheList (Private);
732 
733     //
734     // Unload the config form.
735     //
736     HttpBootConfigFormUnload (Private);
737 
738     gBS->UninstallProtocolInterface (
739            NicHandle,
740            &gEfiCallerIdGuid,
741            &Private->Id
742            );
743     FreePool (Private);
744 
745   }
746 
747   return EFI_SUCCESS;
748 }
749 
750 /**
751   Tests to see if this driver supports a given controller. If a child device is provided,
752   it further tests to see if this driver supports creating a handle for the specified child device.
753 
754   This function checks to see if the driver specified by This supports the device specified by
755   ControllerHandle. Drivers will typically use the device path attached to
756   ControllerHandle and/or the services from the bus I/O abstraction attached to
757   ControllerHandle to determine if the driver supports ControllerHandle. This function
758   may be called many times during platform initialization. In order to reduce boot times, the tests
759   performed by this function must be very small, and take as little time as possible to execute. This
760   function must not change the state of any hardware devices, and this function must be aware that the
761   device specified by ControllerHandle may already be managed by the same driver or a
762   different driver. This function must match its calls to AllocatePages() with FreePages(),
763   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
764   Because ControllerHandle may have been previously started by the same driver, if a protocol is
765   already in the opened state, then it must not be closed with CloseProtocol(). This is required
766   to guarantee the state of ControllerHandle is not modified by this function.
767 
768   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
769   @param[in]  ControllerHandle     The handle of the controller to test. This handle
770                                    must support a protocol interface that supplies
771                                    an I/O abstraction to the driver.
772   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
773                                    parameter is ignored by device drivers, and is optional for bus
774                                    drivers. For bus drivers, if this parameter is not NULL, then
775                                    the bus driver must determine if the bus controller specified
776                                    by ControllerHandle and the child controller specified
777                                    by RemainingDevicePath are both supported by this
778                                    bus driver.
779 
780   @retval EFI_SUCCESS              The device specified by ControllerHandle and
781                                    RemainingDevicePath is supported by the driver specified by This.
782   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
783                                    RemainingDevicePath is already being managed by the driver
784                                    specified by This.
785   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
786                                    RemainingDevicePath is already being managed by a different
787                                    driver or an application that requires exclusive access.
788                                    Currently not implemented.
789   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
790                                    RemainingDevicePath is not supported by the driver specified by This.
791 **/
792 EFI_STATUS
793 EFIAPI
HttpBootIp6DxeDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)794 HttpBootIp6DxeDriverBindingSupported (
795   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
796   IN EFI_HANDLE                   ControllerHandle,
797   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
798   )
799 {
800   EFI_STATUS                    Status;
801 
802   //
803   // Try to open the DHCP6, HTTP and Device Path protocol.
804   //
805   Status = gBS->OpenProtocol (
806                   ControllerHandle,
807                   &gEfiDhcp6ServiceBindingProtocolGuid,
808                   NULL,
809                   This->DriverBindingHandle,
810                   ControllerHandle,
811                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
812                   );
813   if (EFI_ERROR (Status)) {
814     return Status;
815   }
816 
817   Status = gBS->OpenProtocol (
818                   ControllerHandle,
819                   &gEfiHttpServiceBindingProtocolGuid,
820                   NULL,
821                   This->DriverBindingHandle,
822                   ControllerHandle,
823                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
824                   );
825   if (EFI_ERROR (Status)) {
826     return Status;
827   }
828 
829   Status = gBS->OpenProtocol (
830                   ControllerHandle,
831                   &gEfiDevicePathProtocolGuid,
832                   NULL,
833                   This->DriverBindingHandle,
834                   ControllerHandle,
835                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
836                   );
837 
838   return Status;
839 
840 }
841 
842 /**
843   Starts a device controller or a bus controller.
844 
845   The Start() function is designed to be invoked from the EFI boot service ConnectController().
846   As a result, much of the error checking on the parameters to Start() has been moved into this
847   common boot service. It is legal to call Start() from other locations,
848   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
849   1. ControllerHandle must be a valid EFI_HANDLE.
850   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
851      EFI_DEVICE_PATH_PROTOCOL.
852   3. Prior to calling Start(), the Supported() function for the driver specified by This must
853      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
854 
855   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
856   @param[in]  ControllerHandle     The handle of the controller to start. This handle
857                                    must support a protocol interface that supplies
858                                    an I/O abstraction to the driver.
859   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
860                                    parameter is ignored by device drivers, and is optional for bus
861                                    drivers. For a bus driver, if this parameter is NULL, then handles
862                                    for all the children of Controller are created by this driver.
863                                    If this parameter is not NULL and the first Device Path Node is
864                                    not the End of Device Path Node, then only the handle for the
865                                    child device specified by the first Device Path Node of
866                                    RemainingDevicePath is created by this driver.
867                                    If the first Device Path Node of RemainingDevicePath is
868                                    the End of Device Path Node, no child handle is created by this
869                                    driver.
870 
871   @retval EFI_SUCCESS              The device was started.
872   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
873   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
874   @retval Others                   The driver failded to start the device.
875 
876 **/
877 EFI_STATUS
878 EFIAPI
HttpBootIp6DxeDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)879 HttpBootIp6DxeDriverBindingStart (
880   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
881   IN EFI_HANDLE                   ControllerHandle,
882   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
883   )
884 {
885   EFI_STATUS                 Status;
886   HTTP_BOOT_PRIVATE_DATA     *Private;
887   EFI_DEV_PATH               *Node;
888   EFI_DEVICE_PATH_PROTOCOL   *DevicePath;
889   UINT32                     *Id;
890   BOOLEAN                    Ipv6Available;
891   BOOLEAN                    FirstStart;
892 
893   FirstStart = FALSE;
894 
895   Status = gBS->OpenProtocol (
896                   ControllerHandle,
897                   &gEfiCallerIdGuid,
898                   (VOID **) &Id,
899                   This->DriverBindingHandle,
900                   ControllerHandle,
901                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
902                   );
903 
904   if (!EFI_ERROR (Status)) {
905     Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id);
906   } else {
907     FirstStart = TRUE;
908 
909     //
910     // Initialize the private data structure.
911     //
912     Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA));
913     if (Private == NULL) {
914       return EFI_OUT_OF_RESOURCES;
915     }
916     Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;
917     Private->Controller = ControllerHandle;
918     InitializeListHead (&Private->CacheList);
919     //
920     // Get the NII interface if it exists, it's not required.
921     //
922     Status = gBS->OpenProtocol (
923                     ControllerHandle,
924                     &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
925                     (VOID **) &Private->Nii,
926                     This->DriverBindingHandle,
927                     ControllerHandle,
928                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
929                     );
930     if (EFI_ERROR (Status)) {
931       Private->Nii = NULL;
932     }
933 
934     //
935     // Open Device Path Protocol to prepare for appending IP and URI node.
936     //
937     Status = gBS->OpenProtocol (
938                     ControllerHandle,
939                     &gEfiDevicePathProtocolGuid,
940                     (VOID **) &Private->ParentDevicePath,
941                     This->DriverBindingHandle,
942                     ControllerHandle,
943                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
944                     );
945     if (EFI_ERROR (Status)) {
946       goto ON_ERROR;
947     }
948 
949     //
950     // Initialize the HII configuration form.
951     //
952     Status = HttpBootConfigFormInit (Private);
953     if (EFI_ERROR (Status)) {
954       goto ON_ERROR;
955     }
956 
957     //
958     // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between
959     // NIC handle and the private data.
960     //
961     Status = gBS->InstallProtocolInterface (
962                     &ControllerHandle,
963                     &gEfiCallerIdGuid,
964                     EFI_NATIVE_INTERFACE,
965                     &Private->Id
966                     );
967     if (EFI_ERROR (Status)) {
968       goto ON_ERROR;
969     }
970 
971   }
972 
973   //
974   // Set IPv6 available flag.
975   //
976   Status = HttpBootCheckIpv6Support (Private, &Ipv6Available);
977   if (EFI_ERROR (Status)) {
978     //
979     // Fail to get the data whether UNDI supports IPv6.
980     // Set default value to TRUE.
981     //
982     Ipv6Available = TRUE;
983   }
984 
985   if (!Ipv6Available) {
986     Status = EFI_UNSUPPORTED;
987     goto ON_ERROR;
988   }
989 
990   if (Private->Ip6Nic != NULL) {
991     //
992     // Already created before
993     //
994     return EFI_SUCCESS;
995   }
996 
997   Private->Ip6Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC));
998   if (Private->Ip6Nic == NULL) {
999     Status = EFI_OUT_OF_RESOURCES;
1000     goto ON_ERROR;
1001   }
1002   Private->Ip6Nic->Private     = Private;
1003   Private->Ip6Nic->ImageHandle = This->DriverBindingHandle;
1004   Private->Ip6Nic->Signature   = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;
1005 
1006   //
1007   // Create Dhcp6 child and open Dhcp6 protocol
1008   Status = NetLibCreateServiceChild (
1009              ControllerHandle,
1010              This->DriverBindingHandle,
1011              &gEfiDhcp6ServiceBindingProtocolGuid,
1012              &Private->Dhcp6Child
1013              );
1014   if (EFI_ERROR (Status)) {
1015     goto ON_ERROR;
1016   }
1017 
1018   Status = gBS->OpenProtocol (
1019                   Private->Dhcp6Child,
1020                   &gEfiDhcp6ProtocolGuid,
1021                   (VOID **) &Private->Dhcp6,
1022                   This->DriverBindingHandle,
1023                   ControllerHandle,
1024                   EFI_OPEN_PROTOCOL_BY_DRIVER
1025                   );
1026   if (EFI_ERROR (Status)) {
1027     goto ON_ERROR;
1028   }
1029 
1030   //
1031   // Create Ip6 child and open Ip6 protocol for background ICMP packets.
1032   //
1033   Status = NetLibCreateServiceChild (
1034               ControllerHandle,
1035               This->DriverBindingHandle,
1036               &gEfiIp6ServiceBindingProtocolGuid,
1037               &Private->Ip6Child
1038               );
1039   if (EFI_ERROR (Status)) {
1040     goto ON_ERROR;
1041   }
1042 
1043   Status = gBS->OpenProtocol (
1044                   Private->Ip6Child,
1045                   &gEfiIp6ProtocolGuid,
1046                   (VOID **) &Private->Ip6,
1047                   This->DriverBindingHandle,
1048                   ControllerHandle,
1049                   EFI_OPEN_PROTOCOL_BY_DRIVER
1050                   );
1051   if (EFI_ERROR (Status)) {
1052     goto ON_ERROR;
1053   }
1054 
1055   //
1056   // Locate Ip6Config protocol, it's required to configure the default gateway address.
1057   //
1058   Status = gBS->OpenProtocol (
1059                   ControllerHandle,
1060                   &gEfiIp6ConfigProtocolGuid,
1061                   (VOID **) &Private->Ip6Config,
1062                   This->DriverBindingHandle,
1063                   ControllerHandle,
1064                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
1065                   );
1066   if (EFI_ERROR (Status)) {
1067     goto ON_ERROR;
1068   }
1069 
1070   //
1071   // Append IPv6 device path node.
1072   //
1073   Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH));
1074   if (Node == NULL) {
1075     Status = EFI_OUT_OF_RESOURCES;
1076     goto ON_ERROR;
1077   }
1078   Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH;
1079   Node->Ipv6.Header.SubType = MSG_IPv6_DP;
1080   Node->Ipv6.PrefixLength = IP6_PREFIX_LENGTH;
1081   SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH));
1082   DevicePath = AppendDevicePathNode(Private->ParentDevicePath, (EFI_DEVICE_PATH*) Node);
1083   FreePool(Node);
1084   if (DevicePath == NULL) {
1085     Status = EFI_OUT_OF_RESOURCES;
1086     goto ON_ERROR;
1087   }
1088 
1089   //
1090   // Append URI device path node.
1091   //
1092   Node = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL));
1093   if (Node == NULL) {
1094     Status = EFI_OUT_OF_RESOURCES;
1095     goto ON_ERROR;
1096   }
1097   Node->DevPath.Type = MESSAGING_DEVICE_PATH;
1098   Node->DevPath.SubType = MSG_URI_DP;
1099   SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL));
1100   Private->Ip6Nic->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
1101   FreePool (Node);
1102   FreePool (DevicePath);
1103   if (Private->Ip6Nic->DevicePath == NULL) {
1104     Status = EFI_OUT_OF_RESOURCES;
1105     goto ON_ERROR;
1106   }
1107 
1108   //
1109   // Create a child handle for the HTTP boot and install DevPath and Load file protocol on it.
1110   //
1111   CopyMem (&Private->Ip6Nic->LoadFile, &gHttpBootDxeLoadFile, sizeof (Private->LoadFile));
1112   Status = gBS->InstallMultipleProtocolInterfaces (
1113                   &Private->Ip6Nic->Controller,
1114                   &gEfiLoadFileProtocolGuid,
1115                   &Private->Ip6Nic->LoadFile,
1116                   &gEfiDevicePathProtocolGuid,
1117                   Private->Ip6Nic->DevicePath,
1118                   NULL
1119                   );
1120   if (EFI_ERROR (Status)) {
1121     goto ON_ERROR;
1122   }
1123 
1124   //
1125   // Open the Caller Id child to setup a parent-child relationship between
1126   // real NIC handle and the HTTP boot child handle.
1127   //
1128   Status = gBS->OpenProtocol (
1129                   ControllerHandle,
1130                   &gEfiCallerIdGuid,
1131                   (VOID **) &Id,
1132                   This->DriverBindingHandle,
1133                   Private->Ip6Nic->Controller,
1134                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1135                   );
1136   if (EFI_ERROR (Status)) {
1137     goto ON_ERROR;
1138   }
1139 
1140   return EFI_SUCCESS;
1141 
1142 ON_ERROR:
1143   if (Private != NULL) {
1144     if (FirstStart) {
1145       gBS->UninstallProtocolInterface (
1146              ControllerHandle,
1147              &gEfiCallerIdGuid,
1148              &Private->Id
1149              );
1150     }
1151 
1152     HttpBootDestroyIp6Children(This, Private);
1153     HttpBootConfigFormUnload (Private);
1154 
1155     if (FirstStart) {
1156       FreePool (Private);
1157     }
1158   }
1159 
1160   return Status;
1161 }
1162 
1163 /**
1164   Stops a device controller or a bus controller.
1165 
1166   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
1167   As a result, much of the error checking on the parameters to Stop() has been moved
1168   into this common boot service. It is legal to call Stop() from other locations,
1169   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
1170   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
1171      same driver's Start() function.
1172   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
1173      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
1174      Start() function, and the Start() function must have called OpenProtocol() on
1175      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1176 
1177   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1178   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
1179                                 support a bus specific I/O protocol for the driver
1180                                 to use to stop the device.
1181   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
1182   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
1183                                 if NumberOfChildren is 0.
1184 
1185   @retval EFI_SUCCESS           The device was stopped.
1186   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
1187 
1188 **/
1189 EFI_STATUS
1190 EFIAPI
HttpBootIp6DxeDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)1191 HttpBootIp6DxeDriverBindingStop (
1192   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
1193   IN EFI_HANDLE                   ControllerHandle,
1194   IN UINTN                        NumberOfChildren,
1195   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
1196   )
1197 {
1198   EFI_STATUS                      Status;
1199   EFI_LOAD_FILE_PROTOCOL          *LoadFile;
1200   HTTP_BOOT_PRIVATE_DATA          *Private;
1201   EFI_HANDLE                      NicHandle;
1202   UINT32                          *Id;
1203 
1204   //
1205   // Try to get the Load File Protocol from the controller handle.
1206   //
1207   Status = gBS->OpenProtocol (
1208                   ControllerHandle,
1209                   &gEfiLoadFileProtocolGuid,
1210                   (VOID **) &LoadFile,
1211                   This->DriverBindingHandle,
1212                   ControllerHandle,
1213                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
1214                   );
1215   if (EFI_ERROR (Status)) {
1216     //
1217     // If failed, try to find the NIC handle for this controller.
1218     //
1219     NicHandle = HttpBootGetNicByIp6Children (ControllerHandle);
1220     if (NicHandle == NULL) {
1221       return EFI_SUCCESS;
1222     }
1223 
1224     //
1225     // Try to retrieve the private data by the Caller Id Guid.
1226     //
1227     Status = gBS->OpenProtocol (
1228                     NicHandle,
1229                     &gEfiCallerIdGuid,
1230                     (VOID **) &Id,
1231                     This->DriverBindingHandle,
1232                     ControllerHandle,
1233                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
1234                     );
1235     if (EFI_ERROR (Status)) {
1236       return Status;
1237     }
1238     Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID (Id);
1239   } else {
1240     Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (LoadFile);
1241     NicHandle = Private->Controller;
1242   }
1243 
1244   //
1245   // Disable the HTTP boot function.
1246   //
1247   Status = HttpBootStop (Private);
1248   if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) {
1249     return Status;
1250   }
1251 
1252   //
1253   // Destory all child instance and uninstall protocol interface.
1254   //
1255   HttpBootDestroyIp6Children (This, Private);
1256 
1257   if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) {
1258     //
1259     // Release the cached data.
1260     //
1261     HttpBootFreeCacheList (Private);
1262 
1263     //
1264     // Unload the config form.
1265     //
1266     HttpBootConfigFormUnload (Private);
1267 
1268     gBS->UninstallProtocolInterface (
1269            NicHandle,
1270            &gEfiCallerIdGuid,
1271            &Private->Id
1272            );
1273     FreePool (Private);
1274 
1275   }
1276 
1277   return EFI_SUCCESS;
1278 }
1279 /**
1280   This is the declaration of an EFI image entry point. This entry point is
1281   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
1282   both device drivers and bus drivers.
1283 
1284   @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.
1285   @param[in]  SystemTable       A pointer to the EFI System Table.
1286 
1287   @retval EFI_SUCCESS           The operation completed successfully.
1288   @retval Others                An unexpected error occurred.
1289 
1290 **/
1291 EFI_STATUS
1292 EFIAPI
HttpBootDxeDriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1293 HttpBootDxeDriverEntryPoint (
1294   IN EFI_HANDLE        ImageHandle,
1295   IN EFI_SYSTEM_TABLE  *SystemTable
1296   )
1297 {
1298   EFI_STATUS   Status;
1299 
1300   //
1301   // Install UEFI Driver Model protocol(s).
1302   //
1303   Status = EfiLibInstallDriverBindingComponentName2 (
1304              ImageHandle,
1305              SystemTable,
1306              &gHttpBootIp4DxeDriverBinding,
1307              ImageHandle,
1308              &gHttpBootDxeComponentName,
1309              &gHttpBootDxeComponentName2
1310              );
1311   if (EFI_ERROR (Status)) {
1312     return Status;
1313   }
1314 
1315   Status = EfiLibInstallDriverBindingComponentName2 (
1316              ImageHandle,
1317              SystemTable,
1318              &gHttpBootIp6DxeDriverBinding,
1319              NULL,
1320              &gHttpBootDxeComponentName,
1321              &gHttpBootDxeComponentName2
1322              );
1323   if (EFI_ERROR (Status)) {
1324     EfiLibUninstallDriverBindingComponentName2(
1325       &gHttpBootIp4DxeDriverBinding,
1326       &gHttpBootDxeComponentName,
1327       &gHttpBootDxeComponentName2
1328       );
1329   }
1330   return Status;
1331 }
1332 
1333