]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c
Adopt new IPv4/IPv6 device path for network modules.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDriver.c
1 /** @file
2 Driver Binding functions implementationfor for UefiPxeBc Driver.
3
4 Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "PxeBcImpl.h"
17
18
19 EFI_DRIVER_BINDING_PROTOCOL gPxeBcDriverBinding = {
20 PxeBcDriverBindingSupported,
21 PxeBcDriverBindingStart,
22 PxeBcDriverBindingStop,
23 0xa,
24 NULL,
25 NULL
26 };
27
28 /**
29 Get the Nic handle using any child handle in the IPv4 stack.
30
31 @param[in] ControllerHandle Pointer to child handle over IPv4.
32
33 @return NicHandle The pointer to the Nic handle.
34
35 **/
36 EFI_HANDLE
37 PxeBcGetNicByIp4Children (
38 IN EFI_HANDLE ControllerHandle
39 )
40 {
41 EFI_HANDLE NicHandle;
42
43 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
44 if (NicHandle == NULL) {
45 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp4ProtocolGuid);
46 if (NicHandle == NULL) {
47 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);
48 if (NicHandle == NULL) {
49 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);
50 if (NicHandle == NULL) {
51 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiMtftp4ProtocolGuid);
52 if (NicHandle == NULL) {
53 return NULL;
54 }
55 }
56 }
57 }
58 }
59
60 return NicHandle;
61 }
62
63
64 /**
65 Get the Nic handle using any child handle in the IPv6 stack.
66
67 @param[in] ControllerHandle Pointer to child handle over IPv6.
68
69 @return NicHandle The pointer to the Nic handle.
70
71 **/
72 EFI_HANDLE
73 PxeBcGetNicByIp6Children (
74 IN EFI_HANDLE ControllerHandle
75 )
76 {
77 EFI_HANDLE NicHandle;
78
79 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp6ProtocolGuid);
80 if (NicHandle == NULL) {
81 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp6ProtocolGuid);
82 if (NicHandle == NULL) {
83 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);
84 if (NicHandle == NULL) {
85 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiMtftp6ProtocolGuid);
86 if (NicHandle == NULL) {
87 return NULL;
88 }
89 }
90 }
91 }
92
93 return NicHandle;
94 }
95
96
97 /**
98 Destroy the opened instances based on IPv4.
99
100 @param[in] This Pointer to the EFI_DRIVER_BINDING_PROTOCOL.
101 @param[in] Private Pointer to PXEBC_PRIVATE_DATA.
102
103 **/
104 VOID
105 PxeBcDestroyIp4Children (
106 IN EFI_DRIVER_BINDING_PROTOCOL *This,
107 IN PXEBC_PRIVATE_DATA *Private
108 )
109 {
110 ASSERT(Private != NULL);
111
112 if (Private->ArpChild != NULL) {
113 //
114 // Close Arp for PxeBc->Arp and destroy the instance.
115 //
116 gBS->CloseProtocol (
117 Private->ArpChild,
118 &gEfiArpProtocolGuid,
119 This->DriverBindingHandle,
120 Private->Controller
121 );
122
123 NetLibDestroyServiceChild (
124 Private->Controller,
125 This->DriverBindingHandle,
126 &gEfiArpServiceBindingProtocolGuid,
127 Private->ArpChild
128 );
129 }
130
131 if (Private->Ip4Child != NULL) {
132 //
133 // Close Ip4 for background ICMP error message and destroy the instance.
134 //
135 gBS->CloseProtocol (
136 Private->Ip4Child,
137 &gEfiIp4ProtocolGuid,
138 This->DriverBindingHandle,
139 Private->Controller
140 );
141
142 NetLibDestroyServiceChild (
143 Private->Controller,
144 This->DriverBindingHandle,
145 &gEfiIp4ServiceBindingProtocolGuid,
146 Private->Ip4Child
147 );
148 }
149
150 if (Private->Udp4WriteChild != NULL) {
151 //
152 // Close Udp4 for PxeBc->UdpWrite and destroy the instance.
153 //
154 gBS->CloseProtocol (
155 Private->Udp4WriteChild,
156 &gEfiUdp4ProtocolGuid,
157 This->DriverBindingHandle,
158 Private->Controller
159 );
160
161 NetLibDestroyServiceChild (
162 Private->Controller,
163 This->DriverBindingHandle,
164 &gEfiUdp4ServiceBindingProtocolGuid,
165 Private->Udp4WriteChild
166 );
167 }
168
169 if (Private->Udp4ReadChild != NULL) {
170 //
171 // Close Udp4 for PxeBc->UdpRead and destroy the instance.
172 //
173 gBS->CloseProtocol (
174 Private->Udp4ReadChild,
175 &gEfiUdp4ProtocolGuid,
176 This->DriverBindingHandle,
177 Private->Controller
178 );
179
180 NetLibDestroyServiceChild (
181 Private->Controller,
182 This->DriverBindingHandle,
183 &gEfiUdp4ServiceBindingProtocolGuid,
184 Private->Udp4ReadChild
185 );
186 }
187
188 if (Private->Mtftp4Child != NULL) {
189 //
190 // Close Mtftp4 for PxeBc->Mtftp4 and destroy the instance.
191 //
192 gBS->CloseProtocol (
193 Private->Mtftp4Child,
194 &gEfiMtftp4ProtocolGuid,
195 This->DriverBindingHandle,
196 Private->Controller
197 );
198
199 NetLibDestroyServiceChild (
200 Private->Controller,
201 This->DriverBindingHandle,
202 &gEfiMtftp4ServiceBindingProtocolGuid,
203 Private->Mtftp4Child
204 );
205 }
206
207 if (Private->Dhcp4Child != NULL) {
208 //
209 // Close Dhcp4 for PxeBc->Dhcp4 and destroy the instance.
210 //
211 gBS->CloseProtocol (
212 Private->Dhcp4Child,
213 &gEfiDhcp4ProtocolGuid,
214 This->DriverBindingHandle,
215 Private->Controller
216 );
217
218 NetLibDestroyServiceChild (
219 Private->Controller,
220 This->DriverBindingHandle,
221 &gEfiDhcp4ServiceBindingProtocolGuid,
222 Private->Dhcp4Child
223 );
224 }
225
226 if (Private->Ip4Nic != NULL) {
227 //
228 // Close PxeBcPrivate from the parent Nic handle and destroy the virtual handle.
229 //
230 gBS->CloseProtocol (
231 Private->Controller,
232 &gEfiCallerIdGuid,
233 This->DriverBindingHandle,
234 Private->Ip4Nic->Controller
235 );
236
237 gBS->UninstallMultipleProtocolInterfaces (
238 Private->Ip4Nic->Controller,
239 &gEfiDevicePathProtocolGuid,
240 Private->Ip4Nic->DevicePath,
241 &gEfiLoadFileProtocolGuid,
242 &Private->Ip4Nic->LoadFile,
243 &gEfiPxeBaseCodeProtocolGuid,
244 &Private->PxeBc,
245 NULL
246 );
247
248 if (Private->Snp != NULL) {
249 //
250 // Close SNP from the child virtual handle
251 //
252 gBS->CloseProtocol (
253 Private->Ip4Nic->Controller,
254 &gEfiSimpleNetworkProtocolGuid,
255 This->DriverBindingHandle,
256 Private->Ip4Nic->Controller
257 );
258
259 gBS->UninstallProtocolInterface (
260 Private->Ip4Nic->Controller,
261 &gEfiSimpleNetworkProtocolGuid,
262 Private->Snp
263 );
264 }
265 FreePool (Private->Ip4Nic);
266 }
267
268 Private->ArpChild = NULL;
269 Private->Ip4Child = NULL;
270 Private->Udp4WriteChild = NULL;
271 Private->Udp4ReadChild = NULL;
272 Private->Mtftp4Child = NULL;
273 Private->Dhcp4Child = NULL;
274 Private->Ip4Nic = NULL;
275 }
276
277
278 /**
279 Destroy the opened instances based on IPv6.
280
281 @param[in] This Pointer to the EFI_DRIVER_BINDING_PROTOCOL.
282 @param[in] Private Pointer to PXEBC_PRIVATE_DATA.
283
284 **/
285 VOID
286 PxeBcDestroyIp6Children (
287 IN EFI_DRIVER_BINDING_PROTOCOL *This,
288 IN PXEBC_PRIVATE_DATA *Private
289 )
290 {
291 ASSERT(Private != NULL);
292
293 if (Private->Ip6Child != NULL) {
294 //
295 // Close Ip6 for Ip6->Ip6Config and destroy the instance.
296 //
297 gBS->CloseProtocol (
298 Private->Ip6Child,
299 &gEfiIp6ProtocolGuid,
300 This->DriverBindingHandle,
301 Private->Controller
302 );
303
304 NetLibDestroyServiceChild (
305 Private->Controller,
306 This->DriverBindingHandle,
307 &gEfiIp6ServiceBindingProtocolGuid,
308 Private->Ip6Child
309 );
310 }
311
312 if (Private->Udp6WriteChild != NULL) {
313 //
314 // Close Udp6 for PxeBc->UdpWrite and destroy the instance.
315 //
316 gBS->CloseProtocol (
317 Private->Udp6WriteChild,
318 &gEfiUdp6ProtocolGuid,
319 This->DriverBindingHandle,
320 Private->Controller
321 );
322 NetLibDestroyServiceChild (
323 Private->Controller,
324 This->DriverBindingHandle,
325 &gEfiUdp6ServiceBindingProtocolGuid,
326 Private->Udp6WriteChild
327 );
328 }
329
330 if (Private->Udp6ReadChild != NULL) {
331 //
332 // Close Udp6 for PxeBc->UdpRead and destroy the instance.
333 //
334 gBS->CloseProtocol (
335 Private->Udp6ReadChild,
336 &gEfiUdp6ProtocolGuid,
337 This->DriverBindingHandle,
338 Private->Controller
339 );
340 NetLibDestroyServiceChild (
341 Private->Controller,
342 This->DriverBindingHandle,
343 &gEfiUdp6ServiceBindingProtocolGuid,
344 Private->Udp6ReadChild
345 );
346 }
347
348 if (Private->Mtftp6Child != NULL) {
349 //
350 // Close Mtftp6 for PxeBc->Mtftp and destroy the instance.
351 //
352 gBS->CloseProtocol (
353 Private->Mtftp6Child,
354 &gEfiMtftp6ProtocolGuid,
355 This->DriverBindingHandle,
356 Private->Controller
357 );
358
359 NetLibDestroyServiceChild (
360 Private->Controller,
361 This->DriverBindingHandle,
362 &gEfiMtftp6ServiceBindingProtocolGuid,
363 Private->Mtftp6Child
364 );
365 }
366
367 if (Private->Dhcp6Child != NULL) {
368 //
369 // Close Dhcp6 for PxeBc->Dhcp and destroy the instance.
370 //
371 gBS->CloseProtocol (
372 Private->Dhcp6Child,
373 &gEfiDhcp6ProtocolGuid,
374 This->DriverBindingHandle,
375 Private->Controller
376 );
377
378 NetLibDestroyServiceChild (
379 Private->Controller,
380 This->DriverBindingHandle,
381 &gEfiDhcp6ServiceBindingProtocolGuid,
382 Private->Dhcp6Child
383 );
384 }
385
386 if (Private->Ip6Nic != NULL) {
387 //
388 // Close PxeBcPrivate from the parent Nic handle and destroy the virtual handle.
389 //
390 gBS->CloseProtocol (
391 Private->Controller,
392 &gEfiCallerIdGuid,
393 This->DriverBindingHandle,
394 Private->Ip6Nic->Controller
395 );
396
397 gBS->UninstallMultipleProtocolInterfaces (
398 Private->Ip6Nic->Controller,
399 &gEfiDevicePathProtocolGuid,
400 Private->Ip6Nic->DevicePath,
401 &gEfiLoadFileProtocolGuid,
402 &Private->Ip6Nic->LoadFile,
403 &gEfiPxeBaseCodeProtocolGuid,
404 &Private->PxeBc,
405 NULL
406 );
407 if (Private->Snp != NULL) {
408 //
409 // Close SNP from the child virtual handle
410 //
411 gBS->CloseProtocol (
412 Private->Ip6Nic->Controller,
413 &gEfiSimpleNetworkProtocolGuid,
414 This->DriverBindingHandle,
415 Private->Ip6Nic->Controller
416 );
417 gBS->UninstallProtocolInterface (
418 Private->Ip6Nic->Controller,
419 &gEfiSimpleNetworkProtocolGuid,
420 Private->Snp
421 );
422 }
423 FreePool (Private->Ip6Nic);
424 }
425
426 Private->Ip6Child = NULL;
427 Private->Udp6WriteChild = NULL;
428 Private->Udp6ReadChild = NULL;
429 Private->Mtftp6Child = NULL;
430 Private->Dhcp6Child = NULL;
431 Private->Ip6Nic = NULL;
432 Private->Mode.Ipv6Available = FALSE;
433 }
434
435
436 /**
437 Create the opened instances based on IPv4.
438
439 @param[in] This Pointer to EFI_DRIVER_BINDING_PROTOCOL.
440 @param[in] ControllerHandle Handle of the child to destroy.
441 @param[in] Private Handle Pointer to PXEBC_PRIVATE_DATA.
442
443 @retval EFI_SUCCESS The instances based on IPv4 were all created successfully.
444 @retval Others An unexpected error occurred.
445
446 **/
447 EFI_STATUS
448 PxeBcCreateIp4Children (
449 IN EFI_DRIVER_BINDING_PROTOCOL *This,
450 IN EFI_HANDLE ControllerHandle,
451 IN PXEBC_PRIVATE_DATA *Private
452 )
453 {
454 EFI_STATUS Status;
455 IPv4_DEVICE_PATH Ip4Node;
456 EFI_PXE_BASE_CODE_MODE *Mode;
457 EFI_UDP4_CONFIG_DATA *Udp4CfgData;
458 EFI_IP4_CONFIG_DATA *Ip4CfgData;
459 EFI_IP4_MODE_DATA Ip4ModeData;
460 PXEBC_PRIVATE_PROTOCOL *Id;
461 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
462
463 if (Private->Ip4Nic != NULL) {
464 //
465 // Already created before.
466 //
467 return EFI_SUCCESS;
468 }
469
470 //
471 // Create Dhcp4 child and open Dhcp4 protocol for PxeBc->Dhcp.
472 //
473 Status = NetLibCreateServiceChild (
474 ControllerHandle,
475 This->DriverBindingHandle,
476 &gEfiDhcp4ServiceBindingProtocolGuid,
477 &Private->Dhcp4Child
478 );
479 if (EFI_ERROR (Status)) {
480 goto ON_ERROR;
481 }
482
483 Status = gBS->OpenProtocol (
484 Private->Dhcp4Child,
485 &gEfiDhcp4ProtocolGuid,
486 (VOID **) &Private->Dhcp4,
487 This->DriverBindingHandle,
488 ControllerHandle,
489 EFI_OPEN_PROTOCOL_BY_DRIVER
490 );
491 if (EFI_ERROR (Status)) {
492 goto ON_ERROR;
493 }
494
495 //
496 // Create Mtftp4 child and open Mtftp4 protocol for PxeBc->Mtftp.
497 //
498 Status = NetLibCreateServiceChild (
499 ControllerHandle,
500 This->DriverBindingHandle,
501 &gEfiMtftp4ServiceBindingProtocolGuid,
502 &Private->Mtftp4Child
503 );
504 if (EFI_ERROR (Status)) {
505 goto ON_ERROR;
506 }
507
508 Status = gBS->OpenProtocol (
509 Private->Mtftp4Child,
510 &gEfiMtftp4ProtocolGuid,
511 (VOID **) &Private->Mtftp4,
512 This->DriverBindingHandle,
513 ControllerHandle,
514 EFI_OPEN_PROTOCOL_BY_DRIVER
515 );
516 if (EFI_ERROR (Status)) {
517 goto ON_ERROR;
518 }
519
520 //
521 // Create Udp4 child and open Udp4 protocol for PxeBc->UdpRead.
522 //
523 Status = NetLibCreateServiceChild (
524 ControllerHandle,
525 This->DriverBindingHandle,
526 &gEfiUdp4ServiceBindingProtocolGuid,
527 &Private->Udp4ReadChild
528 );
529 if (EFI_ERROR (Status)) {
530 goto ON_ERROR;
531 }
532
533 Status = gBS->OpenProtocol (
534 Private->Udp4ReadChild,
535 &gEfiUdp4ProtocolGuid,
536 (VOID **) &Private->Udp4Read,
537 This->DriverBindingHandle,
538 ControllerHandle,
539 EFI_OPEN_PROTOCOL_BY_DRIVER
540 );
541 if (EFI_ERROR (Status)) {
542 goto ON_ERROR;
543 }
544
545 //
546 // Create Udp4 child and open Udp4 protocol for PxeBc->UdpWrite.
547 //
548 Status = NetLibCreateServiceChild (
549 ControllerHandle,
550 This->DriverBindingHandle,
551 &gEfiUdp4ServiceBindingProtocolGuid,
552 &Private->Udp4WriteChild
553 );
554 if (EFI_ERROR (Status)) {
555 goto ON_ERROR;
556 }
557
558 Status = gBS->OpenProtocol (
559 Private->Udp4WriteChild,
560 &gEfiUdp4ProtocolGuid,
561 (VOID **) &Private->Udp4Write,
562 This->DriverBindingHandle,
563 ControllerHandle,
564 EFI_OPEN_PROTOCOL_BY_DRIVER
565 );
566 if (EFI_ERROR (Status)) {
567 goto ON_ERROR;
568 }
569
570 //
571 // Create Arp child and open Arp protocol for PxeBc->Arp.
572 //
573 Status = NetLibCreateServiceChild (
574 ControllerHandle,
575 This->DriverBindingHandle,
576 &gEfiArpServiceBindingProtocolGuid,
577 &Private->ArpChild
578 );
579 if (EFI_ERROR (Status)) {
580 goto ON_ERROR;
581 }
582
583 Status = gBS->OpenProtocol (
584 Private->ArpChild,
585 &gEfiArpProtocolGuid,
586 (VOID **) &Private->Arp,
587 This->DriverBindingHandle,
588 ControllerHandle,
589 EFI_OPEN_PROTOCOL_BY_DRIVER
590 );
591 if (EFI_ERROR (Status)) {
592 goto ON_ERROR;
593 }
594
595 //
596 // Create Ip4 child and open Ip4 protocol for background ICMP packets.
597 //
598 Status = NetLibCreateServiceChild (
599 ControllerHandle,
600 This->DriverBindingHandle,
601 &gEfiIp4ServiceBindingProtocolGuid,
602 &Private->Ip4Child
603 );
604 if (EFI_ERROR (Status)) {
605 goto ON_ERROR;
606 }
607
608 Status = gBS->OpenProtocol (
609 Private->Ip4Child,
610 &gEfiIp4ProtocolGuid,
611 (VOID **) &Private->Ip4,
612 This->DriverBindingHandle,
613 ControllerHandle,
614 EFI_OPEN_PROTOCOL_BY_DRIVER
615 );
616 if (EFI_ERROR (Status)) {
617 goto ON_ERROR;
618 }
619
620 //
621 // Get max packet size from Ip4 to calculate block size for Tftp later.
622 //
623 Status = Private->Ip4->GetModeData (Private->Ip4, &Ip4ModeData, NULL, NULL);
624 if (EFI_ERROR (Status)) {
625 goto ON_ERROR;
626 }
627
628 Private->Ip4MaxPacketSize = Ip4ModeData.MaxPacketSize;
629
630 Private->Ip4Nic = AllocateZeroPool (sizeof (PXEBC_VIRTUAL_NIC));
631 if (Private->Ip4Nic == NULL) {
632 return EFI_OUT_OF_RESOURCES;
633 }
634
635 Private->Ip4Nic->Private = Private;
636 Private->Ip4Nic->Signature = PXEBC_VIRTUAL_NIC_SIGNATURE;
637
638 //
639 // Create a device path node for Ipv4 virtual nic, and append it.
640 //
641 ZeroMem (&Ip4Node, sizeof (IPv4_DEVICE_PATH));
642 Ip4Node.Header.Type = MESSAGING_DEVICE_PATH;
643 Ip4Node.Header.SubType = MSG_IPv4_DP;
644 Ip4Node.StaticIpAddress = FALSE;
645
646 SetDevicePathNodeLength (&Ip4Node.Header, sizeof (Ip4Node));
647
648 Private->Ip4Nic->DevicePath = AppendDevicePathNode (Private->DevicePath, &Ip4Node.Header);
649
650 if (Private->Ip4Nic->DevicePath == NULL) {
651 Status = EFI_OUT_OF_RESOURCES;
652 goto ON_ERROR;
653 }
654
655 CopyMem (
656 &Private->Ip4Nic->LoadFile,
657 &gLoadFileProtocolTemplate,
658 sizeof (EFI_LOAD_FILE_PROTOCOL)
659 );
660
661 //
662 // Create a new handle for IPv4 virtual nic,
663 // and install PxeBaseCode, LoadFile and DevicePath protocols.
664 //
665 Status = gBS->InstallMultipleProtocolInterfaces (
666 &Private->Ip4Nic->Controller,
667 &gEfiDevicePathProtocolGuid,
668 Private->Ip4Nic->DevicePath,
669 &gEfiLoadFileProtocolGuid,
670 &Private->Ip4Nic->LoadFile,
671 &gEfiPxeBaseCodeProtocolGuid,
672 &Private->PxeBc,
673 NULL
674 );
675 if (EFI_ERROR (Status)) {
676 goto ON_ERROR;
677 }
678
679 if (Private->Snp != NULL) {
680 //
681 // Install SNP protocol on purpose is for some OS loader backward
682 // compatibility consideration.
683 //
684 Status = gBS->InstallProtocolInterface (
685 &Private->Ip4Nic->Controller,
686 &gEfiSimpleNetworkProtocolGuid,
687 EFI_NATIVE_INTERFACE,
688 Private->Snp
689 );
690 if (EFI_ERROR (Status)) {
691 goto ON_ERROR;
692 }
693
694 //
695 // Open SNP on the child handle BY_DRIVER. It will prevent any additionally
696 // layering to perform the experiment.
697 //
698 Status = gBS->OpenProtocol (
699 Private->Ip4Nic->Controller,
700 &gEfiSimpleNetworkProtocolGuid,
701 (VOID **) &Snp,
702 This->DriverBindingHandle,
703 Private->Ip4Nic->Controller,
704 EFI_OPEN_PROTOCOL_BY_DRIVER
705 );
706 if (EFI_ERROR (Status)) {
707 goto ON_ERROR;
708 }
709 }
710
711 //
712 // Open PxeBaseCodePrivate protocol by child to setup a parent-child relationship between
713 // real NIC handle and the virtual IPv4 NIC handle.
714 //
715 Status = gBS->OpenProtocol (
716 ControllerHandle,
717 &gEfiCallerIdGuid,
718 (VOID **) &Id,
719 This->DriverBindingHandle,
720 Private->Ip4Nic->Controller,
721 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
722 );
723 if (EFI_ERROR (Status)) {
724 goto ON_ERROR;
725 }
726
727 //
728 // Set default configure data for Udp4Read and Ip4 instance.
729 //
730 Mode = Private->PxeBc.Mode;
731 Udp4CfgData = &Private->Udp4CfgData;
732 Ip4CfgData = &Private->Ip4CfgData;
733
734 Udp4CfgData->AcceptBroadcast = FALSE;
735 Udp4CfgData->AcceptAnyPort = TRUE;
736 Udp4CfgData->AllowDuplicatePort = TRUE;
737 Udp4CfgData->TypeOfService = Mode->ToS;
738 Udp4CfgData->TimeToLive = Mode->TTL;
739 Udp4CfgData->ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;
740 Udp4CfgData->TransmitTimeout = PXEBC_DEFAULT_LIFETIME;
741
742 Ip4CfgData->AcceptIcmpErrors = TRUE;
743 Ip4CfgData->DefaultProtocol = EFI_IP_PROTO_ICMP;
744 Ip4CfgData->TypeOfService = Mode->ToS;
745 Ip4CfgData->TimeToLive = Mode->TTL;
746 Ip4CfgData->ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;
747 Ip4CfgData->TransmitTimeout = PXEBC_DEFAULT_LIFETIME;
748
749 return EFI_SUCCESS;
750
751 ON_ERROR:
752 PxeBcDestroyIp4Children (This, Private);
753 return Status;
754 }
755
756
757 /**
758 Create the opened instances based on IPv6.
759
760 @param[in] This Pointer to EFI_DRIVER_BINDING_PROTOCOL.
761 @param[in] ControllerHandle Handle of the child to destroy.
762 @param[in] Private Handle Pointer to PXEBC_PRIVATE_DATA.
763
764 @retval EFI_SUCCESS The instances based on IPv6 were all created successfully.
765 @retval Others An unexpected error occurred.
766
767 **/
768 EFI_STATUS
769 PxeBcCreateIp6Children (
770 IN EFI_DRIVER_BINDING_PROTOCOL *This,
771 IN EFI_HANDLE ControllerHandle,
772 IN PXEBC_PRIVATE_DATA *Private
773 )
774 {
775 EFI_STATUS Status;
776 IPv6_DEVICE_PATH Ip6Node;
777 EFI_UDP6_CONFIG_DATA *Udp6CfgData;
778 EFI_IP6_CONFIG_DATA *Ip6CfgData;
779 EFI_IP6_MODE_DATA Ip6ModeData;
780 PXEBC_PRIVATE_PROTOCOL *Id;
781 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
782
783 if (Private->Ip6Nic != NULL) {
784 //
785 // Already created before.
786 //
787 return EFI_SUCCESS;
788 }
789
790 Private->Ip6Nic = AllocateZeroPool (sizeof (PXEBC_VIRTUAL_NIC));
791
792 if (Private->Ip6Nic == NULL) {
793 return EFI_OUT_OF_RESOURCES;
794 }
795
796 Private->Ip6Nic->Private = Private;
797 Private->Ip6Nic->Signature = PXEBC_VIRTUAL_NIC_SIGNATURE;
798
799 //
800 // Create Dhcp6 child and open Dhcp6 protocol for PxeBc->Dhcp.
801 //
802 Status = NetLibCreateServiceChild (
803 ControllerHandle,
804 This->DriverBindingHandle,
805 &gEfiDhcp6ServiceBindingProtocolGuid,
806 &Private->Dhcp6Child
807 );
808 if (EFI_ERROR (Status)) {
809 goto ON_ERROR;
810 }
811
812 Status = gBS->OpenProtocol (
813 Private->Dhcp6Child,
814 &gEfiDhcp6ProtocolGuid,
815 (VOID **) &Private->Dhcp6,
816 This->DriverBindingHandle,
817 ControllerHandle,
818 EFI_OPEN_PROTOCOL_BY_DRIVER
819 );
820 if (EFI_ERROR (Status)) {
821 goto ON_ERROR;
822 }
823
824 //
825 // Create Mtftp6 child and open Mtftp6 protocol for PxeBc->Mtftp.
826 //
827 Status = NetLibCreateServiceChild (
828 ControllerHandle,
829 This->DriverBindingHandle,
830 &gEfiMtftp6ServiceBindingProtocolGuid,
831 &Private->Mtftp6Child
832 );
833 if (EFI_ERROR (Status)) {
834 goto ON_ERROR;
835 }
836
837 Status = gBS->OpenProtocol (
838 Private->Mtftp6Child,
839 &gEfiMtftp6ProtocolGuid,
840 (VOID **) &Private->Mtftp6,
841 This->DriverBindingHandle,
842 ControllerHandle,
843 EFI_OPEN_PROTOCOL_BY_DRIVER
844 );
845 if (EFI_ERROR (Status)) {
846 goto ON_ERROR;
847 }
848
849 //
850 // Create Udp6 child and open Udp6 protocol for PxeBc->UdpRead.
851 //
852 Status = NetLibCreateServiceChild (
853 ControllerHandle,
854 This->DriverBindingHandle,
855 &gEfiUdp6ServiceBindingProtocolGuid,
856 &Private->Udp6ReadChild
857 );
858 if (EFI_ERROR (Status)) {
859 goto ON_ERROR;
860 }
861
862 Status = gBS->OpenProtocol (
863 Private->Udp6ReadChild,
864 &gEfiUdp6ProtocolGuid,
865 (VOID **) &Private->Udp6Read,
866 This->DriverBindingHandle,
867 ControllerHandle,
868 EFI_OPEN_PROTOCOL_BY_DRIVER
869 );
870 if (EFI_ERROR (Status)) {
871 goto ON_ERROR;
872 }
873
874 //
875 // Create Udp6 child and open Udp6 protocol for PxeBc->UdpWrite.
876 //
877 Status = NetLibCreateServiceChild (
878 ControllerHandle,
879 This->DriverBindingHandle,
880 &gEfiUdp6ServiceBindingProtocolGuid,
881 &Private->Udp6WriteChild
882 );
883 if (EFI_ERROR (Status)) {
884 goto ON_ERROR;
885 }
886
887 Status = gBS->OpenProtocol (
888 Private->Udp6WriteChild,
889 &gEfiUdp6ProtocolGuid,
890 (VOID **) &Private->Udp6Write,
891 This->DriverBindingHandle,
892 ControllerHandle,
893 EFI_OPEN_PROTOCOL_BY_DRIVER
894 );
895 if (EFI_ERROR (Status)) {
896 goto ON_ERROR;
897 }
898
899 //
900 // Create Ip6 child and open Ip6 protocol for background ICMP6 packets.
901 //
902 Status = NetLibCreateServiceChild (
903 ControllerHandle,
904 This->DriverBindingHandle,
905 &gEfiIp6ServiceBindingProtocolGuid,
906 &Private->Ip6Child
907 );
908 if (EFI_ERROR (Status)) {
909 goto ON_ERROR;
910 }
911
912 Status = gBS->OpenProtocol (
913 Private->Ip6Child,
914 &gEfiIp6ProtocolGuid,
915 (VOID **) &Private->Ip6,
916 This->DriverBindingHandle,
917 ControllerHandle,
918 EFI_OPEN_PROTOCOL_BY_DRIVER
919 );
920 if (EFI_ERROR (Status)) {
921 goto ON_ERROR;
922 }
923
924 //
925 // Get max packet size from Ip6 to calculate block size for Tftp later.
926 //
927 Status = Private->Ip6->GetModeData (Private->Ip6, &Ip6ModeData, NULL, NULL);
928 if (EFI_ERROR (Status)) {
929 goto ON_ERROR;
930 }
931
932 Private->Ip6MaxPacketSize = Ip6ModeData.MaxPacketSize;
933
934 //
935 // Locate Ip6->Ip6Config and store it for set IPv6 address.
936 //
937 Status = gBS->HandleProtocol (
938 ControllerHandle,
939 &gEfiIp6ConfigProtocolGuid,
940 (VOID **) &Private->Ip6Cfg
941 );
942 if (EFI_ERROR (Status)) {
943 goto ON_ERROR;
944 }
945
946 //
947 // Create a device path node for Ipv6 virtual nic, and append it.
948 //
949 ZeroMem (&Ip6Node, sizeof (IPv6_DEVICE_PATH));
950 Ip6Node.Header.Type = MESSAGING_DEVICE_PATH;
951 Ip6Node.Header.SubType = MSG_IPv6_DP;
952 Ip6Node.PrefixLength = IP6_PREFIX_LENGTH;
953
954 SetDevicePathNodeLength (&Ip6Node.Header, sizeof (Ip6Node));
955
956 Private->Ip6Nic->DevicePath = AppendDevicePathNode (Private->DevicePath, &Ip6Node.Header);
957
958 if (Private->Ip6Nic->DevicePath == NULL) {
959 Status = EFI_OUT_OF_RESOURCES;
960 goto ON_ERROR;
961 }
962
963 CopyMem (
964 &Private->Ip6Nic->LoadFile,
965 &gLoadFileProtocolTemplate,
966 sizeof (EFI_LOAD_FILE_PROTOCOL)
967 );
968
969 //
970 // Create a new handle for IPv6 virtual nic,
971 // and install PxeBaseCode, LoadFile and DevicePath protocols.
972 //
973 Status = gBS->InstallMultipleProtocolInterfaces (
974 &Private->Ip6Nic->Controller,
975 &gEfiDevicePathProtocolGuid,
976 Private->Ip6Nic->DevicePath,
977 &gEfiLoadFileProtocolGuid,
978 &Private->Ip6Nic->LoadFile,
979 &gEfiPxeBaseCodeProtocolGuid,
980 &Private->PxeBc,
981 NULL
982 );
983 if (EFI_ERROR (Status)) {
984 goto ON_ERROR;
985 }
986
987 if (Private->Snp != NULL) {
988 //
989 // Install SNP protocol on purpose is for some OS loader backward
990 // compatibility consideration.
991 //
992 Status = gBS->InstallProtocolInterface (
993 &Private->Ip6Nic->Controller,
994 &gEfiSimpleNetworkProtocolGuid,
995 EFI_NATIVE_INTERFACE,
996 Private->Snp
997 );
998 if (EFI_ERROR (Status)) {
999 goto ON_ERROR;
1000 }
1001
1002 //
1003 // Open SNP on the child handle BY_DRIVER. It will prevent any additionally
1004 // layering to perform the experiment.
1005 //
1006 Status = gBS->OpenProtocol (
1007 Private->Ip6Nic->Controller,
1008 &gEfiSimpleNetworkProtocolGuid,
1009 (VOID **) &Snp,
1010 This->DriverBindingHandle,
1011 Private->Ip6Nic->Controller,
1012 EFI_OPEN_PROTOCOL_BY_DRIVER
1013 );
1014 if (EFI_ERROR (Status)) {
1015 goto ON_ERROR;
1016 }
1017 }
1018
1019 //
1020 // Open PxeBaseCodePrivate protocol by child to setup a parent-child relationship between
1021 // real NIC handle and the virtual IPv6 NIC handle.
1022 //
1023 Status = gBS->OpenProtocol (
1024 ControllerHandle,
1025 &gEfiCallerIdGuid,
1026 (VOID **) &Id,
1027 This->DriverBindingHandle,
1028 Private->Ip6Nic->Controller,
1029 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1030 );
1031 if (EFI_ERROR (Status)) {
1032 goto ON_ERROR;
1033 }
1034
1035 //
1036 // Set IPv6 avaiable flag and set default configure data for
1037 // Udp6Read and Ip6 instance.
1038 //
1039 Private->Mode.Ipv6Available = TRUE;
1040 Udp6CfgData = &Private->Udp6CfgData;
1041 Ip6CfgData = &Private->Ip6CfgData;
1042
1043 Udp6CfgData->AcceptAnyPort = TRUE;
1044 Udp6CfgData->AllowDuplicatePort = TRUE;
1045 Udp6CfgData->HopLimit = PXEBC_DEFAULT_HOPLIMIT;
1046 Udp6CfgData->ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;
1047 Udp6CfgData->TransmitTimeout = PXEBC_DEFAULT_LIFETIME;
1048
1049 Ip6CfgData->AcceptIcmpErrors = TRUE;
1050 Ip6CfgData->DefaultProtocol = IP6_ICMP;
1051 Ip6CfgData->HopLimit = PXEBC_DEFAULT_HOPLIMIT;
1052 Ip6CfgData->ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;
1053 Ip6CfgData->TransmitTimeout = PXEBC_DEFAULT_LIFETIME;
1054
1055 return EFI_SUCCESS;
1056
1057 ON_ERROR:
1058 PxeBcDestroyIp6Children (This, Private);
1059 return Status;
1060 }
1061
1062
1063 /**
1064 The entry point for UefiPxeBc driver that installs the driver
1065 binding and component name protocol on its image.
1066
1067 @param[in] ImageHandle The Image handle of the driver.
1068 @param[in] SystemTable The system table.
1069
1070 @return EFI_SUCCESS
1071 @return Others
1072
1073 **/
1074 EFI_STATUS
1075 EFIAPI
1076 PxeBcDriverEntryPoint (
1077 IN EFI_HANDLE ImageHandle,
1078 IN EFI_SYSTEM_TABLE *SystemTable
1079 )
1080 {
1081 return EfiLibInstallDriverBindingComponentName2 (
1082 ImageHandle,
1083 SystemTable,
1084 &gPxeBcDriverBinding,
1085 ImageHandle,
1086 &gPxeBcComponentName,
1087 &gPxeBcComponentName2
1088 );
1089 }
1090
1091
1092 /**
1093 Test to see if this driver supports ControllerHandle. This service
1094 is called by the EFI boot service ConnectController(). In
1095 order to make drivers as small as possible, there are a few calling
1096 restrictions for this service. ConnectController() must
1097 follow these calling restrictions. If any other agent wishes to call
1098 Supported() it must also follow these calling restrictions.
1099
1100 @param[in] This The pointer to the driver binding protocol.
1101 @param[in] ControllerHandle The handle of device to be tested.
1102 @param[in] RemainingDevicePath Optional parameter used to pick a specific child
1103 device to be started.
1104
1105 @retval EFI_SUCCESS This driver supports this device.
1106 @retval EFI_UNSUPPORTED This driver does not support this device.
1107
1108 **/
1109 EFI_STATUS
1110 EFIAPI
1111 PxeBcDriverBindingSupported (
1112 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1113 IN EFI_HANDLE ControllerHandle,
1114 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1115 )
1116 {
1117 EFI_STATUS Ip4Status;
1118 EFI_STATUS Ip6Status;
1119
1120 //
1121 // Try to open the Mtftp4 and Dhcp4 protocol to test whether IPv4 stack is ready.
1122 //
1123 Ip4Status = gBS->OpenProtocol (
1124 ControllerHandle,
1125 &gEfiDhcp4ServiceBindingProtocolGuid,
1126 NULL,
1127 This->DriverBindingHandle,
1128 ControllerHandle,
1129 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1130 );
1131 if (!EFI_ERROR (Ip4Status)) {
1132 Ip4Status = gBS->OpenProtocol (
1133 ControllerHandle,
1134 &gEfiMtftp4ServiceBindingProtocolGuid,
1135 NULL,
1136 This->DriverBindingHandle,
1137 ControllerHandle,
1138 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1139 );
1140 }
1141
1142 //
1143 // Try to open the Mtftp6 and Dhcp6 protocol to test whether IPv4 stack is ready.
1144 //
1145 Ip6Status = gBS->OpenProtocol (
1146 ControllerHandle,
1147 &gEfiDhcp6ServiceBindingProtocolGuid,
1148 NULL,
1149 This->DriverBindingHandle,
1150 ControllerHandle,
1151 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1152 );
1153 if (!EFI_ERROR (Ip6Status)) {
1154 Ip6Status = gBS->OpenProtocol (
1155 ControllerHandle,
1156 &gEfiMtftp6ServiceBindingProtocolGuid,
1157 NULL,
1158 This->DriverBindingHandle,
1159 ControllerHandle,
1160 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1161 );
1162 }
1163
1164 //
1165 // It's unsupported case if both stack are not ready.
1166 //
1167 if (EFI_ERROR (Ip4Status) && EFI_ERROR (Ip6Status)) {
1168 return EFI_UNSUPPORTED;
1169 }
1170
1171 return EFI_SUCCESS;
1172 }
1173
1174
1175 /**
1176 Start this driver on ControllerHandle. This service is called by the
1177 EFI boot service ConnectController(). In order to make
1178 drivers as small as possible, there are a few calling restrictions for
1179 this service. ConnectController() must follow these
1180 calling restrictions. If any other agent wishes to call Start() it
1181 must also follow these calling restrictions.
1182
1183 @param[in] This The pointer to the driver binding protocol.
1184 @param[in] ControllerHandle The handle of device to be started.
1185 @param[in] RemainingDevicePath Optional parameter used to pick a specific child
1186 device to be started.
1187
1188 @retval EFI_SUCCESS This driver is installed to ControllerHandle.
1189 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
1190 @retval other This driver does not support this device.
1191
1192 **/
1193 EFI_STATUS
1194 EFIAPI
1195 PxeBcDriverBindingStart (
1196 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1197 IN EFI_HANDLE ControllerHandle,
1198 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1199 )
1200 {
1201 PXEBC_PRIVATE_DATA *Private;
1202 EFI_STATUS Status;
1203 EFI_STATUS Ip4Status;
1204 EFI_STATUS Ip6Status;
1205 PXEBC_PRIVATE_PROTOCOL *Id;
1206
1207 Status = gBS->OpenProtocol (
1208 ControllerHandle,
1209 &gEfiCallerIdGuid,
1210 (VOID **) &Id,
1211 This->DriverBindingHandle,
1212 ControllerHandle,
1213 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1214 );
1215 if (!EFI_ERROR (Status)) {
1216 //
1217 // Skip the initialization if the driver has been started already.
1218 //
1219 Private = PXEBC_PRIVATE_DATA_FROM_ID (Id);
1220 } else {
1221 //
1222 // If the driver has not been started yet, it should do initialization.
1223 //
1224 Private = AllocateZeroPool (sizeof (PXEBC_PRIVATE_DATA));
1225 if (Private == NULL) {
1226 return EFI_OUT_OF_RESOURCES;
1227 }
1228
1229 CopyMem (
1230 &Private->PxeBc,
1231 &gPxeBcProtocolTemplate,
1232 sizeof (EFI_PXE_BASE_CODE_PROTOCOL)
1233 );
1234
1235 Private->Signature = PXEBC_PRIVATE_DATA_SIGNATURE;
1236 Private->Controller = ControllerHandle;
1237 Private->Image = This->ImageHandle;
1238 Private->PxeBc.Mode = &Private->Mode;
1239 Private->Mode.Ipv6Supported = TRUE;
1240 Private->Mode.AutoArp = TRUE;
1241 Private->Mode.TTL = DEFAULT_TTL;
1242 Private->Mode.ToS = DEFAULT_ToS;
1243
1244 //
1245 // Open device path to prepare for appending virtual NIC node.
1246 //
1247 Status = gBS->OpenProtocol (
1248 ControllerHandle,
1249 &gEfiDevicePathProtocolGuid,
1250 (VOID **) &Private->DevicePath,
1251 This->DriverBindingHandle,
1252 ControllerHandle,
1253 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1254 );
1255
1256 if (EFI_ERROR (Status)) {
1257 goto ON_ERROR;
1258 }
1259
1260 //
1261 // Get the NII interface if it exists, it's not required.
1262 //
1263 Status = gBS->OpenProtocol (
1264 ControllerHandle,
1265 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
1266 (VOID **) &Private->Nii,
1267 This->DriverBindingHandle,
1268 ControllerHandle,
1269 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1270 );
1271 if (EFI_ERROR (Status)) {
1272 Private->Nii = NULL;
1273 }
1274
1275 //
1276 // Install PxeBaseCodePrivate protocol onto the real NIC handler.
1277 // PxeBaseCodePrivate protocol is only used to keep the relationship between
1278 // NIC handle and virtual child handles.
1279 // gEfiCallerIdGuid will be used as its protocol guid.
1280 //
1281 Status = gBS->InstallProtocolInterface (
1282 &ControllerHandle,
1283 &gEfiCallerIdGuid,
1284 EFI_NATIVE_INTERFACE,
1285 &Private->Id
1286 );
1287 if (EFI_ERROR (Status)) {
1288 goto ON_ERROR;
1289 }
1290
1291 //
1292 // Try to locate SNP protocol.
1293 //
1294 NetLibGetSnpHandle(ControllerHandle, &Private->Snp);
1295 }
1296
1297 //
1298 // Try to create virtual NIC handle for IPv4.
1299 //
1300 Ip4Status = PxeBcCreateIp4Children (This, ControllerHandle, Private);
1301
1302 //
1303 // Try to create virtual NIC handle for IPv6.
1304 //
1305 Ip6Status = PxeBcCreateIp6Children (This, ControllerHandle, Private);
1306
1307 if (EFI_ERROR (Ip4Status) && EFI_ERROR (Ip6Status)) {
1308 //
1309 // Failed to start PXE driver if IPv4 and IPv6 stack are both not available.
1310 //
1311 Status = EFI_DEVICE_ERROR;
1312 goto ON_ERROR;
1313 }
1314
1315 return EFI_SUCCESS;
1316
1317 ON_ERROR:
1318 gBS->UninstallProtocolInterface (
1319 ControllerHandle,
1320 &gEfiCallerIdGuid,
1321 &Private->Id
1322 );
1323 PxeBcDestroyIp4Children (This, Private);
1324 PxeBcDestroyIp6Children (This, Private);
1325 FreePool (Private);
1326
1327 return Status;
1328 }
1329
1330
1331 /**
1332 Stop this driver on ControllerHandle. This service is called by the
1333 EFI boot service DisconnectController(). In order to
1334 make drivers as small as possible, there are a few calling
1335 restrictions for this service. DisconnectController()
1336 must follow these calling restrictions. If any other agent wishes
1337 to call Stop() it must also follow these calling restrictions.
1338
1339 @param[in] This Protocol instance pointer.
1340 @param[in] ControllerHandle Handle of device to stop driver on.
1341 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
1342 children is zero stop the entire bus driver.
1343 @param[in] ChildHandleBuffer List of Child Handles to Stop.
1344
1345 @retval EFI_SUCCESS This driver was removed ControllerHandle.
1346 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
1347 @retval Others This driver was not removed from this device
1348
1349 **/
1350 EFI_STATUS
1351 EFIAPI
1352 PxeBcDriverBindingStop (
1353 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1354 IN EFI_HANDLE ControllerHandle,
1355 IN UINTN NumberOfChildren,
1356 IN EFI_HANDLE *ChildHandleBuffer
1357 )
1358 {
1359 PXEBC_PRIVATE_DATA *Private;
1360 PXEBC_VIRTUAL_NIC *VirtualNic;
1361 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1362 EFI_STATUS Status;
1363 EFI_HANDLE NicHandle;
1364 BOOLEAN IsIpv6;
1365 PXEBC_PRIVATE_PROTOCOL *Id;
1366
1367 Private = NULL;
1368 NicHandle = NULL;
1369 VirtualNic = NULL;
1370 LoadFile = NULL;
1371 Id = NULL;
1372 IsIpv6 = FALSE;
1373
1374 Status = gBS->OpenProtocol (
1375 ControllerHandle,
1376 &gEfiLoadFileProtocolGuid,
1377 (VOID **) &LoadFile,
1378 This->DriverBindingHandle,
1379 ControllerHandle,
1380 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1381 );
1382 if (EFI_ERROR (Status)) {
1383 //
1384 // Get the Nic handle by any pass-over service child handle.
1385 //
1386 NicHandle = PxeBcGetNicByIp4Children (ControllerHandle);
1387 if (NicHandle == NULL) {
1388 NicHandle = PxeBcGetNicByIp6Children (ControllerHandle);
1389 if (NicHandle == NULL) {
1390 return EFI_DEVICE_ERROR;
1391 } else {
1392 IsIpv6 = TRUE;
1393 }
1394 }
1395
1396 //
1397 // Try to retrieve the private data by PxeBcPrivate protocol.
1398 //
1399 Status = gBS->OpenProtocol (
1400 NicHandle,
1401 &gEfiCallerIdGuid,
1402 (VOID **) &Id,
1403 This->DriverBindingHandle,
1404 ControllerHandle,
1405 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1406 );
1407 if (EFI_ERROR (Status)) {
1408 return Status;
1409 }
1410 Private = PXEBC_PRIVATE_DATA_FROM_ID (Id);
1411
1412 } else {
1413 //
1414 // It's a virtual handle with LoadFileProtocol.
1415 //
1416 Status = gBS->OpenProtocol (
1417 ControllerHandle,
1418 &gEfiLoadFileProtocolGuid,
1419 (VOID **) &LoadFile,
1420 This->DriverBindingHandle,
1421 ControllerHandle,
1422 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1423 );
1424 if (EFI_ERROR (Status)) {
1425 return Status;
1426 }
1427
1428 VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (LoadFile);
1429 Private = VirtualNic->Private;
1430 NicHandle = Private->Controller;
1431
1432 if (Private->Ip6Nic == VirtualNic) {
1433 IsIpv6 = TRUE;
1434 }
1435 }
1436
1437 //
1438 // Stop functionality of PXE Base Code protocol
1439 //
1440 Status = Private->PxeBc.Stop (&Private->PxeBc);
1441 if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) {
1442 return Status;
1443 }
1444
1445
1446 if (Private->Ip4Nic != NULL && !IsIpv6) {
1447 PxeBcDestroyIp4Children (This, Private);
1448 }
1449
1450 if (Private->Ip6Nic != NULL && IsIpv6) {
1451 PxeBcDestroyIp6Children (This, Private);
1452 }
1453
1454 if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) {
1455 gBS->UninstallProtocolInterface (
1456 NicHandle,
1457 &gEfiCallerIdGuid,
1458 &Private->Id
1459 );
1460 FreePool (Private);
1461 }
1462
1463 return EFI_SUCCESS;
1464 }