]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpBootDxe/HttpBootDxe.c
9fb33bbb53abf20e874f4ea240543577ab2870d1
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootDxe.c
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
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
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
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
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
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
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
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
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
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