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