1 /** @file
2   Driver Binding functions implementation for UEFI HTTP boot.
3 
4 Copyright (c) 2015, 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     Private->Image = This->ImageHandle;
336     InitializeListHead (&Private->CacheList);
337     //
338     // Get the NII interface if it exists, it's not required.
339     //
340     Status = gBS->OpenProtocol (
341                     ControllerHandle,
342                     &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
343                     (VOID **) &Private->Nii,
344                     This->DriverBindingHandle,
345                     ControllerHandle,
346                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
347                     );
348     if (EFI_ERROR (Status)) {
349       Private->Nii = NULL;
350     }
351 
352     //
353     // Open Device Path Protocol to prepare for appending IP and URI node.
354     //
355     Status = gBS->OpenProtocol (
356                     ControllerHandle,
357                     &gEfiDevicePathProtocolGuid,
358                     (VOID **) &Private->ParentDevicePath,
359                     This->DriverBindingHandle,
360                     ControllerHandle,
361                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
362                     );
363     if (EFI_ERROR (Status)) {
364       goto ON_ERROR;
365     }
366 
367     //
368     // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between
369     // NIC handle and the private data.
370     //
371     Status = gBS->InstallProtocolInterface (
372                     &ControllerHandle,
373                     &gEfiCallerIdGuid,
374                     EFI_NATIVE_INTERFACE,
375                     &Private->Id
376                     );
377     if (EFI_ERROR (Status)) {
378       goto ON_ERROR;
379     }
380 
381   }
382 
383   if (Private->Ip4Nic != NULL) {
384     //
385     // Already created before
386     //
387     return EFI_SUCCESS;
388   }
389 
390   Private->Ip4Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC));
391   if (Private->Ip4Nic == NULL) {
392     return EFI_OUT_OF_RESOURCES;
393   }
394   Private->Ip4Nic->Private   = Private;
395   Private->Ip4Nic->Signature = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;
396 
397   //
398   // Create DHCP4 child instance.
399   //
400   Status = NetLibCreateServiceChild (
401              ControllerHandle,
402              This->DriverBindingHandle,
403              &gEfiDhcp4ServiceBindingProtocolGuid,
404              &Private->Dhcp4Child
405              );
406   if (EFI_ERROR (Status)) {
407     goto ON_ERROR;
408   }
409 
410   Status = gBS->OpenProtocol (
411                   Private->Dhcp4Child,
412                   &gEfiDhcp4ProtocolGuid,
413                   (VOID **) &Private->Dhcp4,
414                   This->DriverBindingHandle,
415                   ControllerHandle,
416                   EFI_OPEN_PROTOCOL_BY_DRIVER
417                   );
418   if (EFI_ERROR (Status)) {
419     goto ON_ERROR;
420   }
421 
422   //
423   // Get the Ip4Config2 protocol, it's required to configure the default gateway address.
424   //
425   Status = gBS->OpenProtocol (
426                   ControllerHandle,
427                   &gEfiIp4Config2ProtocolGuid,
428                   (VOID **) &Private->Ip4Config2,
429                   This->DriverBindingHandle,
430                   ControllerHandle,
431                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
432                   );
433   if (EFI_ERROR (Status)) {
434     goto ON_ERROR;
435   }
436 
437   //
438   // Append IPv4 device path node.
439   //
440   Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH));
441   if (Node == NULL) {
442     Status = EFI_OUT_OF_RESOURCES;
443     goto ON_ERROR;
444   }
445   Node->Ipv4.Header.Type = MESSAGING_DEVICE_PATH;
446   Node->Ipv4.Header.SubType = MSG_IPv4_DP;
447   SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH));
448   Node->Ipv4.StaticIpAddress = FALSE;
449   DevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
450   FreePool (Node);
451   if (DevicePath == NULL) {
452     Status = EFI_OUT_OF_RESOURCES;
453     goto ON_ERROR;
454   }
455 
456   //
457   // Append URI device path node.
458   //
459   Node = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL));
460   if (Node == NULL) {
461     Status = EFI_OUT_OF_RESOURCES;
462     goto ON_ERROR;
463   }
464   Node->DevPath.Type = MESSAGING_DEVICE_PATH;
465   Node->DevPath.SubType = MSG_URI_DP;
466   SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL));
467   Private->Ip4Nic->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
468   FreePool (Node);
469   FreePool (DevicePath);
470   if (Private->Ip4Nic->DevicePath == NULL) {
471     Status = EFI_OUT_OF_RESOURCES;
472     goto ON_ERROR;
473   }
474 
475   //
476   // Create a child handle for the HTTP boot and install DevPath and Load file protocol on it.
477   //
478   CopyMem (&Private->Ip4Nic->LoadFile, &gHttpBootDxeLoadFile, sizeof (EFI_LOAD_FILE_PROTOCOL));
479   Status = gBS->InstallMultipleProtocolInterfaces (
480                   &Private->Ip4Nic->Controller,
481                   &gEfiLoadFileProtocolGuid,
482                   &Private->Ip4Nic->LoadFile,
483                   &gEfiDevicePathProtocolGuid,
484                   Private->Ip4Nic->DevicePath,
485                   NULL
486                   );
487   if (EFI_ERROR (Status)) {
488     goto ON_ERROR;
489   }
490 
491   //
492   // Open the Caller Id child to setup a parent-child relationship between
493   // real NIC handle and the HTTP boot Ipv4 NIC handle.
494   //
495   Status = gBS->OpenProtocol (
496                   ControllerHandle,
497                   &gEfiCallerIdGuid,
498                   (VOID **) &Id,
499                   This->DriverBindingHandle,
500                   Private->Ip4Nic->Controller,
501                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
502                   );
503   if (EFI_ERROR (Status)) {
504     goto ON_ERROR;
505   }
506 
507   return EFI_SUCCESS;
508 
509 
510 ON_ERROR:
511 
512   HttpBootDestroyIp4Children (This, Private);
513   FreePool (Private);
514 
515   return Status;
516 }
517 
518 
519 /**
520   Stops a device controller or a bus controller.
521 
522   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
523   As a result, much of the error checking on the parameters to Stop() has been moved
524   into this common boot service. It is legal to call Stop() from other locations,
525   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
526   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
527      same driver's Start() function.
528   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
529      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
530      Start() function, and the Start() function must have called OpenProtocol() on
531      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
532 
533   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
534   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
535                                 support a bus specific I/O protocol for the driver
536                                 to use to stop the device.
537   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
538   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
539                                 if NumberOfChildren is 0.
540 
541   @retval EFI_SUCCESS           The device was stopped.
542   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
543 
544 **/
545 EFI_STATUS
546 EFIAPI
HttpBootIp4DxeDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)547 HttpBootIp4DxeDriverBindingStop (
548   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
549   IN EFI_HANDLE                   ControllerHandle,
550   IN UINTN                        NumberOfChildren,
551   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
552   )
553 {
554   EFI_STATUS                      Status;
555   EFI_LOAD_FILE_PROTOCOL          *LoadFile;
556   HTTP_BOOT_PRIVATE_DATA          *Private;
557   EFI_HANDLE                      NicHandle;
558   UINT32                          *Id;
559 
560   //
561   // Try to get the Load File Protocol from the controller handle.
562   //
563   Status = gBS->OpenProtocol (
564                   ControllerHandle,
565                   &gEfiLoadFileProtocolGuid,
566                   (VOID **) &LoadFile,
567                   This->DriverBindingHandle,
568                   ControllerHandle,
569                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
570                   );
571   if (EFI_ERROR (Status)) {
572     //
573     // If failed, try to find the NIC handle for this controller.
574     //
575     NicHandle = HttpBootGetNicByIp4Children (ControllerHandle);
576     if (NicHandle == NULL) {
577       return EFI_SUCCESS;
578     }
579 
580     //
581     // Try to retrieve the private data by the Caller Id Guid.
582     //
583     Status = gBS->OpenProtocol (
584                     NicHandle,
585                     &gEfiCallerIdGuid,
586                     (VOID **) &Id,
587                     This->DriverBindingHandle,
588                     ControllerHandle,
589                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
590                     );
591     if (EFI_ERROR (Status)) {
592       return Status;
593     }
594     Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID (Id);
595   } else {
596     Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (LoadFile);
597     NicHandle = Private->Controller;
598   }
599 
600   //
601   // Disable the HTTP boot function.
602   //
603   Status = HttpBootStop (Private);
604   if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) {
605     return Status;
606   }
607 
608   //
609   // Destory all child instance and uninstall protocol interface.
610   //
611   HttpBootDestroyIp4Children (This, Private);
612 
613   if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) {
614     //
615     // Release the cached data.
616     //
617     HttpBootFreeCacheList (Private);
618 
619     gBS->UninstallProtocolInterface (
620            NicHandle,
621            &gEfiCallerIdGuid,
622            &Private->Id
623            );
624     FreePool (Private);
625 
626   }
627 
628   return EFI_SUCCESS;
629 }
630 
631 /**
632   Tests to see if this driver supports a given controller. If a child device is provided,
633   it further tests to see if this driver supports creating a handle for the specified child device.
634 
635   This function checks to see if the driver specified by This supports the device specified by
636   ControllerHandle. Drivers will typically use the device path attached to
637   ControllerHandle and/or the services from the bus I/O abstraction attached to
638   ControllerHandle to determine if the driver supports ControllerHandle. This function
639   may be called many times during platform initialization. In order to reduce boot times, the tests
640   performed by this function must be very small, and take as little time as possible to execute. This
641   function must not change the state of any hardware devices, and this function must be aware that the
642   device specified by ControllerHandle may already be managed by the same driver or a
643   different driver. This function must match its calls to AllocatePages() with FreePages(),
644   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
645   Because ControllerHandle may have been previously started by the same driver, if a protocol is
646   already in the opened state, then it must not be closed with CloseProtocol(). This is required
647   to guarantee the state of ControllerHandle is not modified by this function.
648 
649   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
650   @param[in]  ControllerHandle     The handle of the controller to test. This handle
651                                    must support a protocol interface that supplies
652                                    an I/O abstraction to the driver.
653   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
654                                    parameter is ignored by device drivers, and is optional for bus
655                                    drivers. For bus drivers, if this parameter is not NULL, then
656                                    the bus driver must determine if the bus controller specified
657                                    by ControllerHandle and the child controller specified
658                                    by RemainingDevicePath are both supported by this
659                                    bus driver.
660 
661   @retval EFI_SUCCESS              The device specified by ControllerHandle and
662                                    RemainingDevicePath is supported by the driver specified by This.
663   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
664                                    RemainingDevicePath is already being managed by the driver
665                                    specified by This.
666   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
667                                    RemainingDevicePath is already being managed by a different
668                                    driver or an application that requires exclusive access.
669                                    Currently not implemented.
670   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
671                                    RemainingDevicePath is not supported by the driver specified by This.
672 **/
673 EFI_STATUS
674 EFIAPI
HttpBootIp6DxeDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)675 HttpBootIp6DxeDriverBindingSupported (
676   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
677   IN EFI_HANDLE                   ControllerHandle,
678   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
679   )
680 {
681   EFI_STATUS                    Status;
682 
683   //
684   // Try to open the DHCP6, HTTP and Device Path protocol.
685   //
686   Status = gBS->OpenProtocol (
687                   ControllerHandle,
688                   &gEfiDhcp6ServiceBindingProtocolGuid,
689                   NULL,
690                   This->DriverBindingHandle,
691                   ControllerHandle,
692                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
693                   );
694   if (EFI_ERROR (Status)) {
695     return Status;
696   }
697 
698   Status = gBS->OpenProtocol (
699                   ControllerHandle,
700                   &gEfiHttpServiceBindingProtocolGuid,
701                   NULL,
702                   This->DriverBindingHandle,
703                   ControllerHandle,
704                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
705                   );
706   if (EFI_ERROR (Status)) {
707     return Status;
708   }
709 
710   Status = gBS->OpenProtocol (
711                   ControllerHandle,
712                   &gEfiDevicePathProtocolGuid,
713                   NULL,
714                   This->DriverBindingHandle,
715                   ControllerHandle,
716                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
717                   );
718 
719   return Status;
720 
721 }
722 
723 /**
724   Starts a device controller or a bus controller.
725 
726   The Start() function is designed to be invoked from the EFI boot service ConnectController().
727   As a result, much of the error checking on the parameters to Start() has been moved into this
728   common boot service. It is legal to call Start() from other locations,
729   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
730   1. ControllerHandle must be a valid EFI_HANDLE.
731   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
732      EFI_DEVICE_PATH_PROTOCOL.
733   3. Prior to calling Start(), the Supported() function for the driver specified by This must
734      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
735 
736   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
737   @param[in]  ControllerHandle     The handle of the controller to start. This handle
738                                    must support a protocol interface that supplies
739                                    an I/O abstraction to the driver.
740   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
741                                    parameter is ignored by device drivers, and is optional for bus
742                                    drivers. For a bus driver, if this parameter is NULL, then handles
743                                    for all the children of Controller are created by this driver.
744                                    If this parameter is not NULL and the first Device Path Node is
745                                    not the End of Device Path Node, then only the handle for the
746                                    child device specified by the first Device Path Node of
747                                    RemainingDevicePath is created by this driver.
748                                    If the first Device Path Node of RemainingDevicePath is
749                                    the End of Device Path Node, no child handle is created by this
750                                    driver.
751 
752   @retval EFI_SUCCESS              The device was started.
753   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
754   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
755   @retval Others                   The driver failded to start the device.
756 
757 **/
758 EFI_STATUS
759 EFIAPI
HttpBootIp6DxeDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)760 HttpBootIp6DxeDriverBindingStart (
761   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
762   IN EFI_HANDLE                   ControllerHandle,
763   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
764   )
765 {
766   EFI_STATUS                 Status;
767   HTTP_BOOT_PRIVATE_DATA     *Private;
768   EFI_DEV_PATH               *Node;
769   EFI_DEVICE_PATH_PROTOCOL   *DevicePath;
770   UINT32                     *Id;
771 
772   Status = gBS->OpenProtocol (
773                   ControllerHandle,
774                   &gEfiCallerIdGuid,
775                   (VOID **) &Id,
776                   This->DriverBindingHandle,
777                   ControllerHandle,
778                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
779                   );
780 
781   if (!EFI_ERROR (Status)) {
782       Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id);
783   } else {
784     //
785     // Initialize the private data structure.
786     //
787     Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA));
788     if (Private == NULL) {
789       return EFI_OUT_OF_RESOURCES;
790     }
791     Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;
792     Private->Controller = ControllerHandle;
793     Private->Image = This->ImageHandle;
794     InitializeListHead (&Private->CacheList);
795     //
796     // Get the NII interface if it exists, it's not required.
797     //
798     Status = gBS->OpenProtocol (
799                     ControllerHandle,
800                     &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
801                     (VOID **) &Private->Nii,
802                     This->DriverBindingHandle,
803                     ControllerHandle,
804                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
805                     );
806     if (EFI_ERROR (Status)) {
807       Private->Nii = NULL;
808     }
809 
810     //
811     // Open Device Path Protocol to prepare for appending IP and URI node.
812     //
813     Status = gBS->OpenProtocol (
814                     ControllerHandle,
815                     &gEfiDevicePathProtocolGuid,
816                     (VOID **) &Private->ParentDevicePath,
817                     This->DriverBindingHandle,
818                     ControllerHandle,
819                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
820                     );
821     if (EFI_ERROR (Status)) {
822       goto ON_ERROR;
823     }
824 
825     //
826     // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between
827     // NIC handle and the private data.
828     //
829     Status = gBS->InstallProtocolInterface (
830                     &ControllerHandle,
831                     &gEfiCallerIdGuid,
832                     EFI_NATIVE_INTERFACE,
833                     &Private->Id
834                     );
835     if (EFI_ERROR (Status)) {
836       goto ON_ERROR;
837     }
838 
839   }
840 
841   if (Private->Ip6Nic != NULL) {
842     //
843     // Already created before
844     //
845     return EFI_SUCCESS;
846   }
847 
848   Private->Ip6Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC));
849   if (Private->Ip6Nic == NULL) {
850     return EFI_OUT_OF_RESOURCES;
851   }
852   Private->Ip6Nic->Private   = Private;
853   Private->Ip6Nic->Signature = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;
854 
855   //
856   // Create Dhcp6 child and open Dhcp6 protocol
857   Status = NetLibCreateServiceChild (
858              ControllerHandle,
859              This->DriverBindingHandle,
860              &gEfiDhcp6ServiceBindingProtocolGuid,
861              &Private->Dhcp6Child
862              );
863   if (EFI_ERROR (Status)) {
864     goto ON_ERROR;
865   }
866 
867   Status = gBS->OpenProtocol (
868                   Private->Dhcp6Child,
869                   &gEfiDhcp6ProtocolGuid,
870                   (VOID **) &Private->Dhcp6,
871                   This->DriverBindingHandle,
872                   ControllerHandle,
873                   EFI_OPEN_PROTOCOL_BY_DRIVER
874                   );
875   if (EFI_ERROR (Status)) {
876     goto ON_ERROR;
877   }
878 
879   //
880   // Create Ip6 child and open Ip6 protocol for background ICMP packets.
881   //
882   Status = NetLibCreateServiceChild (
883               ControllerHandle,
884               This->DriverBindingHandle,
885               &gEfiIp6ServiceBindingProtocolGuid,
886               &Private->Ip6Child
887               );
888   if (EFI_ERROR (Status)) {
889     goto ON_ERROR;
890   }
891 
892   Status = gBS->OpenProtocol (
893                   Private->Ip6Child,
894                   &gEfiIp6ProtocolGuid,
895                   (VOID **) &Private->Ip6,
896                   This->DriverBindingHandle,
897                   ControllerHandle,
898                   EFI_OPEN_PROTOCOL_BY_DRIVER
899                   );
900   if (EFI_ERROR (Status)) {
901     goto ON_ERROR;
902   }
903 
904   //
905   // Locate Ip6Config protocol, it's required to configure the default gateway address.
906   //
907   Status = gBS->OpenProtocol (
908                   ControllerHandle,
909                   &gEfiIp6ConfigProtocolGuid,
910                   (VOID **) &Private->Ip6Config,
911                   This->DriverBindingHandle,
912                   ControllerHandle,
913                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
914                   );
915   if (EFI_ERROR (Status)) {
916     goto ON_ERROR;
917   }
918 
919   //
920   // Append IPv6 device path node.
921   //
922   Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH));
923   if (Node == NULL) {
924     Status = EFI_OUT_OF_RESOURCES;
925     goto ON_ERROR;
926   }
927   Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH;
928   Node->Ipv6.Header.SubType = MSG_IPv6_DP;
929   Node->Ipv6.PrefixLength = IP6_PREFIX_LENGTH;
930   SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH));
931   DevicePath = AppendDevicePathNode(Private->ParentDevicePath, (EFI_DEVICE_PATH*) Node);
932   FreePool(Node);
933   if (DevicePath == NULL) {
934     Status = EFI_OUT_OF_RESOURCES;
935     goto ON_ERROR;
936   }
937 
938   //
939   // Append URI device path node.
940   //
941   Node = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL));
942   if (Node == NULL) {
943     Status = EFI_OUT_OF_RESOURCES;
944     goto ON_ERROR;
945   }
946   Node->DevPath.Type = MESSAGING_DEVICE_PATH;
947   Node->DevPath.SubType = MSG_URI_DP;
948   SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL));
949   Private->Ip6Nic->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
950   FreePool (Node);
951   FreePool (DevicePath);
952   if (Private->Ip6Nic->DevicePath == NULL) {
953     Status = EFI_OUT_OF_RESOURCES;
954     goto ON_ERROR;
955   }
956 
957   //
958   // Create a child handle for the HTTP boot and install DevPath and Load file protocol on it.
959   //
960   CopyMem (&Private->Ip6Nic->LoadFile, &gHttpBootDxeLoadFile, sizeof (Private->LoadFile));
961   Status = gBS->InstallMultipleProtocolInterfaces (
962                   &Private->Ip6Nic->Controller,
963                   &gEfiLoadFileProtocolGuid,
964                   &Private->Ip6Nic->LoadFile,
965                   &gEfiDevicePathProtocolGuid,
966                   Private->Ip6Nic->DevicePath,
967                   NULL
968                   );
969   if (EFI_ERROR (Status)) {
970     goto ON_ERROR;
971   }
972 
973   //
974   // Open the Caller Id child to setup a parent-child relationship between
975   // real NIC handle and the HTTP boot child handle.
976   //
977   Status = gBS->OpenProtocol (
978                   ControllerHandle,
979                   &gEfiCallerIdGuid,
980                   (VOID **) &Id,
981                   This->DriverBindingHandle,
982                   Private->Ip6Nic->Controller,
983                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
984                   );
985   if (EFI_ERROR (Status)) {
986     goto ON_ERROR;
987   }
988 
989   return EFI_SUCCESS;
990 
991 ON_ERROR:
992 
993  HttpBootDestroyIp6Children(This, Private);
994  FreePool (Private);
995 
996  return Status;
997 
998 }
999 
1000 /**
1001   Stops a device controller or a bus controller.
1002 
1003   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
1004   As a result, much of the error checking on the parameters to Stop() has been moved
1005   into this common boot service. It is legal to call Stop() from other locations,
1006   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
1007   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
1008      same driver's Start() function.
1009   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
1010      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
1011      Start() function, and the Start() function must have called OpenProtocol() on
1012      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1013 
1014   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1015   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
1016                                 support a bus specific I/O protocol for the driver
1017                                 to use to stop the device.
1018   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
1019   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
1020                                 if NumberOfChildren is 0.
1021 
1022   @retval EFI_SUCCESS           The device was stopped.
1023   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
1024 
1025 **/
1026 EFI_STATUS
1027 EFIAPI
HttpBootIp6DxeDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)1028 HttpBootIp6DxeDriverBindingStop (
1029   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
1030   IN EFI_HANDLE                   ControllerHandle,
1031   IN UINTN                        NumberOfChildren,
1032   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
1033   )
1034 {
1035   EFI_STATUS                      Status;
1036   EFI_LOAD_FILE_PROTOCOL          *LoadFile;
1037   HTTP_BOOT_PRIVATE_DATA          *Private;
1038   EFI_HANDLE                      NicHandle;
1039   UINT32                          *Id;
1040 
1041   //
1042   // Try to get the Load File Protocol from the controller handle.
1043   //
1044   Status = gBS->OpenProtocol (
1045                   ControllerHandle,
1046                   &gEfiLoadFileProtocolGuid,
1047                   (VOID **) &LoadFile,
1048                   This->DriverBindingHandle,
1049                   ControllerHandle,
1050                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
1051                   );
1052   if (EFI_ERROR (Status)) {
1053     //
1054     // If failed, try to find the NIC handle for this controller.
1055     //
1056     NicHandle = HttpBootGetNicByIp6Children (ControllerHandle);
1057     if (NicHandle == NULL) {
1058       return EFI_SUCCESS;
1059     }
1060 
1061     //
1062     // Try to retrieve the private data by the Caller Id Guid.
1063     //
1064     Status = gBS->OpenProtocol (
1065                     NicHandle,
1066                     &gEfiCallerIdGuid,
1067                     (VOID **) &Id,
1068                     This->DriverBindingHandle,
1069                     ControllerHandle,
1070                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
1071                     );
1072     if (EFI_ERROR (Status)) {
1073       return Status;
1074     }
1075     Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID (Id);
1076   } else {
1077     Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (LoadFile);
1078     NicHandle = Private->Controller;
1079   }
1080 
1081   //
1082   // Disable the HTTP boot function.
1083   //
1084   Status = HttpBootStop (Private);
1085   if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) {
1086     return Status;
1087   }
1088 
1089   //
1090   // Destory all child instance and uninstall protocol interface.
1091   //
1092   HttpBootDestroyIp6Children (This, Private);
1093 
1094   if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) {
1095     //
1096     // Release the cached data.
1097     //
1098     HttpBootFreeCacheList (Private);
1099 
1100     gBS->UninstallProtocolInterface (
1101            NicHandle,
1102            &gEfiCallerIdGuid,
1103            &Private->Id
1104            );
1105     FreePool (Private);
1106 
1107   }
1108 
1109   return EFI_SUCCESS;
1110 }
1111 /**
1112   This is the declaration of an EFI image entry point. This entry point is
1113   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
1114   both device drivers and bus drivers.
1115 
1116   @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.
1117   @param[in]  SystemTable       A pointer to the EFI System Table.
1118 
1119   @retval EFI_SUCCESS           The operation completed successfully.
1120   @retval Others                An unexpected error occurred.
1121 
1122 **/
1123 EFI_STATUS
1124 EFIAPI
HttpBootDxeDriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1125 HttpBootDxeDriverEntryPoint (
1126   IN EFI_HANDLE        ImageHandle,
1127   IN EFI_SYSTEM_TABLE  *SystemTable
1128   )
1129 {
1130   EFI_STATUS   Status;
1131   //
1132   // Install UEFI Driver Model protocol(s).
1133   //
1134   Status = EfiLibInstallDriverBindingComponentName2 (
1135              ImageHandle,
1136              SystemTable,
1137              &gHttpBootIp4DxeDriverBinding,
1138              ImageHandle,
1139              &gHttpBootDxeComponentName,
1140              &gHttpBootDxeComponentName2
1141              );
1142   if (EFI_ERROR (Status)) {
1143     return Status;
1144   }
1145 
1146   Status = EfiLibInstallDriverBindingComponentName2 (
1147              ImageHandle,
1148              SystemTable,
1149              &gHttpBootIp6DxeDriverBinding,
1150              NULL,
1151              &gHttpBootDxeComponentName,
1152              &gHttpBootDxeComponentName2
1153              );
1154   if (EFI_ERROR (Status)) {
1155     gBS->UninstallMultipleProtocolInterfaces(
1156            ImageHandle,
1157            &gEfiDriverBindingProtocolGuid,
1158            &gHttpBootIp4DxeDriverBinding,
1159            &gEfiComponentName2ProtocolGuid,
1160            &gHttpBootDxeComponentName2,
1161            &gEfiComponentNameProtocolGuid,
1162            &gHttpBootDxeComponentName,
1163            NULL
1164            );
1165   }
1166   return Status;
1167 }
1168 
1169