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