PxeBcDriver.c revision 75dce340624dba5e4a79b2e5b2dbe943bae0d0e9
1/** @file
2  Driver Binding functions implementationfor for UefiPxeBc Driver.
3
4  Copyright (c) 2007 - 2012, 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
19EFI_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**/
36EFI_HANDLE
37PxeBcGetNicByIp4Children (
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**/
72EFI_HANDLE
73PxeBcGetNicByIp6Children (
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**/
104VOID
105PxeBcDestroyIp4Children (
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**/
285VOID
286PxeBcDestroyIp6Children (
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**/
447EFI_STATUS
448PxeBcCreateIp4Children (
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
751ON_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**/
768EFI_STATUS
769PxeBcCreateIp6Children (
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  UINTN                           Index;
783
784  if (Private->Ip6Nic != NULL) {
785    //
786    // Already created before.
787    //
788    return EFI_SUCCESS;
789  }
790
791  Private->Ip6Nic = AllocateZeroPool (sizeof (PXEBC_VIRTUAL_NIC));
792
793  if (Private->Ip6Nic == NULL) {
794    return EFI_OUT_OF_RESOURCES;
795  }
796
797  Private->Ip6Nic->Private   = Private;
798  Private->Ip6Nic->Signature = PXEBC_VIRTUAL_NIC_SIGNATURE;
799
800  //
801  // Create Dhcp6 child and open Dhcp6 protocol for PxeBc->Dhcp.
802  //
803  Status = NetLibCreateServiceChild (
804             ControllerHandle,
805             This->DriverBindingHandle,
806             &gEfiDhcp6ServiceBindingProtocolGuid,
807             &Private->Dhcp6Child
808             );
809  if (EFI_ERROR (Status)) {
810    goto ON_ERROR;
811  }
812
813  Status = gBS->OpenProtocol (
814                  Private->Dhcp6Child,
815                  &gEfiDhcp6ProtocolGuid,
816                  (VOID **) &Private->Dhcp6,
817                  This->DriverBindingHandle,
818                  ControllerHandle,
819                  EFI_OPEN_PROTOCOL_BY_DRIVER
820                  );
821  if (EFI_ERROR (Status)) {
822    goto ON_ERROR;
823  }
824
825  //
826  // Generate a random IAID for the Dhcp6 assigned address.
827  //
828  Private->IaId = NET_RANDOM (NetRandomInitSeed ());
829  if (Private->Snp != NULL) {
830    for (Index = 0; Index < Private->Snp->Mode->HwAddressSize; Index++) {
831      Private->IaId |= (Private->Snp->Mode->CurrentAddress.Addr[Index] << ((Index << 3) & 31));
832    }
833  }
834
835  //
836  // Create Mtftp6 child and open Mtftp6 protocol for PxeBc->Mtftp.
837  //
838  Status = NetLibCreateServiceChild (
839             ControllerHandle,
840             This->DriverBindingHandle,
841             &gEfiMtftp6ServiceBindingProtocolGuid,
842             &Private->Mtftp6Child
843             );
844  if (EFI_ERROR (Status)) {
845    goto ON_ERROR;
846  }
847
848  Status = gBS->OpenProtocol (
849                  Private->Mtftp6Child,
850                  &gEfiMtftp6ProtocolGuid,
851                  (VOID **) &Private->Mtftp6,
852                  This->DriverBindingHandle,
853                  ControllerHandle,
854                  EFI_OPEN_PROTOCOL_BY_DRIVER
855                  );
856  if (EFI_ERROR (Status)) {
857    goto ON_ERROR;
858  }
859
860  //
861  // Create Udp6 child and open Udp6 protocol for PxeBc->UdpRead.
862  //
863  Status = NetLibCreateServiceChild (
864             ControllerHandle,
865             This->DriverBindingHandle,
866             &gEfiUdp6ServiceBindingProtocolGuid,
867             &Private->Udp6ReadChild
868             );
869  if (EFI_ERROR (Status)) {
870    goto ON_ERROR;
871  }
872
873  Status = gBS->OpenProtocol (
874                  Private->Udp6ReadChild,
875                  &gEfiUdp6ProtocolGuid,
876                  (VOID **) &Private->Udp6Read,
877                  This->DriverBindingHandle,
878                  ControllerHandle,
879                  EFI_OPEN_PROTOCOL_BY_DRIVER
880                  );
881  if (EFI_ERROR (Status)) {
882    goto ON_ERROR;
883  }
884
885  //
886  // Create Udp6 child and open Udp6 protocol for PxeBc->UdpWrite.
887  //
888  Status = NetLibCreateServiceChild (
889             ControllerHandle,
890             This->DriverBindingHandle,
891             &gEfiUdp6ServiceBindingProtocolGuid,
892             &Private->Udp6WriteChild
893             );
894  if (EFI_ERROR (Status)) {
895    goto ON_ERROR;
896  }
897
898  Status = gBS->OpenProtocol (
899                  Private->Udp6WriteChild,
900                  &gEfiUdp6ProtocolGuid,
901                  (VOID **) &Private->Udp6Write,
902                  This->DriverBindingHandle,
903                  ControllerHandle,
904                  EFI_OPEN_PROTOCOL_BY_DRIVER
905                  );
906  if (EFI_ERROR (Status)) {
907    goto ON_ERROR;
908  }
909
910  //
911  // Create Ip6 child and open Ip6 protocol for background ICMP6 packets.
912  //
913  Status = NetLibCreateServiceChild (
914             ControllerHandle,
915             This->DriverBindingHandle,
916             &gEfiIp6ServiceBindingProtocolGuid,
917             &Private->Ip6Child
918             );
919  if (EFI_ERROR (Status)) {
920    goto ON_ERROR;
921  }
922
923  Status = gBS->OpenProtocol (
924                  Private->Ip6Child,
925                  &gEfiIp6ProtocolGuid,
926                  (VOID **) &Private->Ip6,
927                  This->DriverBindingHandle,
928                  ControllerHandle,
929                  EFI_OPEN_PROTOCOL_BY_DRIVER
930                  );
931  if (EFI_ERROR (Status)) {
932    goto ON_ERROR;
933  }
934
935  //
936  // Get max packet size from Ip6 to calculate block size for Tftp later.
937  //
938  Status = Private->Ip6->GetModeData (Private->Ip6, &Ip6ModeData, NULL, NULL);
939  if (EFI_ERROR (Status)) {
940    goto ON_ERROR;
941  }
942
943  Private->Ip6MaxPacketSize = Ip6ModeData.MaxPacketSize;
944
945  //
946  // Locate Ip6->Ip6Config and store it for set IPv6 address.
947  //
948  Status = gBS->HandleProtocol (
949                  ControllerHandle,
950                  &gEfiIp6ConfigProtocolGuid,
951                  (VOID **) &Private->Ip6Cfg
952                  );
953  if (EFI_ERROR (Status)) {
954    goto ON_ERROR;
955  }
956
957  //
958  // Create a device path node for Ipv6 virtual nic, and append it.
959  //
960  ZeroMem (&Ip6Node, sizeof (IPv6_DEVICE_PATH));
961  Ip6Node.Header.Type     = MESSAGING_DEVICE_PATH;
962  Ip6Node.Header.SubType  = MSG_IPv6_DP;
963  Ip6Node.PrefixLength    = IP6_PREFIX_LENGTH;
964
965  SetDevicePathNodeLength (&Ip6Node.Header, sizeof (Ip6Node));
966
967  Private->Ip6Nic->DevicePath = AppendDevicePathNode (Private->DevicePath, &Ip6Node.Header);
968
969  if (Private->Ip6Nic->DevicePath == NULL) {
970    Status = EFI_OUT_OF_RESOURCES;
971    goto ON_ERROR;
972  }
973
974  CopyMem (
975    &Private->Ip6Nic->LoadFile,
976    &gLoadFileProtocolTemplate,
977    sizeof (EFI_LOAD_FILE_PROTOCOL)
978    );
979
980  //
981  // Create a new handle for IPv6 virtual nic,
982  // and install PxeBaseCode, LoadFile and DevicePath protocols.
983  //
984  Status = gBS->InstallMultipleProtocolInterfaces (
985                  &Private->Ip6Nic->Controller,
986                  &gEfiDevicePathProtocolGuid,
987                  Private->Ip6Nic->DevicePath,
988                  &gEfiLoadFileProtocolGuid,
989                  &Private->Ip6Nic->LoadFile,
990                  &gEfiPxeBaseCodeProtocolGuid,
991                  &Private->PxeBc,
992                  NULL
993                  );
994  if (EFI_ERROR (Status)) {
995    goto ON_ERROR;
996  }
997
998  if (Private->Snp != NULL) {
999    //
1000    // Install SNP protocol on purpose is for some OS loader backward
1001    // compatibility consideration.
1002    //
1003    Status = gBS->InstallProtocolInterface (
1004                    &Private->Ip6Nic->Controller,
1005                    &gEfiSimpleNetworkProtocolGuid,
1006                    EFI_NATIVE_INTERFACE,
1007                    Private->Snp
1008                    );
1009    if (EFI_ERROR (Status)) {
1010      goto ON_ERROR;
1011    }
1012
1013    //
1014    // Open SNP on the child handle BY_DRIVER. It will prevent any additionally
1015    // layering to perform the experiment.
1016    //
1017    Status = gBS->OpenProtocol (
1018                    Private->Ip6Nic->Controller,
1019                    &gEfiSimpleNetworkProtocolGuid,
1020                    (VOID **) &Snp,
1021                    This->DriverBindingHandle,
1022                    Private->Ip6Nic->Controller,
1023                    EFI_OPEN_PROTOCOL_BY_DRIVER
1024                    );
1025    if (EFI_ERROR (Status)) {
1026      goto ON_ERROR;
1027    }
1028  }
1029
1030  //
1031  // Open PxeBaseCodePrivate protocol by child to setup a parent-child relationship between
1032  // real NIC handle and the virtual IPv6 NIC handle.
1033  //
1034  Status = gBS->OpenProtocol (
1035                  ControllerHandle,
1036                  &gEfiCallerIdGuid,
1037                  (VOID **) &Id,
1038                  This->DriverBindingHandle,
1039                  Private->Ip6Nic->Controller,
1040                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1041                  );
1042  if (EFI_ERROR (Status)) {
1043    goto ON_ERROR;
1044  }
1045
1046  //
1047  // Set IPv6 avaiable flag and set default configure data for
1048  // Udp6Read and Ip6 instance.
1049  //
1050  Private->Mode.Ipv6Available     = TRUE;
1051  Udp6CfgData                     = &Private->Udp6CfgData;
1052  Ip6CfgData                      = &Private->Ip6CfgData;
1053
1054  Udp6CfgData->AcceptAnyPort      = TRUE;
1055  Udp6CfgData->AllowDuplicatePort = TRUE;
1056  Udp6CfgData->HopLimit           = PXEBC_DEFAULT_HOPLIMIT;
1057  Udp6CfgData->ReceiveTimeout     = PXEBC_DEFAULT_LIFETIME;
1058  Udp6CfgData->TransmitTimeout    = PXEBC_DEFAULT_LIFETIME;
1059
1060  Ip6CfgData->AcceptIcmpErrors    = TRUE;
1061  Ip6CfgData->DefaultProtocol     = IP6_ICMP;
1062  Ip6CfgData->HopLimit            = PXEBC_DEFAULT_HOPLIMIT;
1063  Ip6CfgData->ReceiveTimeout      = PXEBC_DEFAULT_LIFETIME;
1064  Ip6CfgData->TransmitTimeout     = PXEBC_DEFAULT_LIFETIME;
1065
1066  return EFI_SUCCESS;
1067
1068ON_ERROR:
1069  PxeBcDestroyIp6Children (This, Private);
1070  return Status;
1071}
1072
1073
1074/**
1075  The entry point for UefiPxeBc driver that installs the driver
1076  binding and component name protocol on its image.
1077
1078  @param[in]  ImageHandle          The Image handle of the driver.
1079  @param[in]  SystemTable          The system table.
1080
1081  @return EFI_SUCCESS
1082  @return Others
1083
1084**/
1085EFI_STATUS
1086EFIAPI
1087PxeBcDriverEntryPoint (
1088  IN EFI_HANDLE             ImageHandle,
1089  IN EFI_SYSTEM_TABLE       *SystemTable
1090  )
1091{
1092  return EfiLibInstallDriverBindingComponentName2 (
1093           ImageHandle,
1094           SystemTable,
1095           &gPxeBcDriverBinding,
1096           ImageHandle,
1097           &gPxeBcComponentName,
1098           &gPxeBcComponentName2
1099           );
1100}
1101
1102
1103/**
1104  Test to see if this driver supports ControllerHandle. This service
1105  is called by the EFI boot service ConnectController(). In
1106  order to make drivers as small as possible, there are a few calling
1107  restrictions for this service. ConnectController() must
1108  follow these calling restrictions. If any other agent wishes to call
1109  Supported() it must also follow these calling restrictions.
1110
1111  @param[in]  This                The pointer to the driver binding protocol.
1112  @param[in]  ControllerHandle    The handle of device to be tested.
1113  @param[in]  RemainingDevicePath Optional parameter used to pick a specific child
1114                                  device to be started.
1115
1116  @retval EFI_SUCCESS         This driver supports this device.
1117  @retval EFI_UNSUPPORTED     This driver does not support this device.
1118
1119**/
1120EFI_STATUS
1121EFIAPI
1122PxeBcDriverBindingSupported (
1123  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
1124  IN EFI_HANDLE                   ControllerHandle,
1125  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
1126  )
1127{
1128  EFI_STATUS                      Ip4Status;
1129  EFI_STATUS                      Ip6Status;
1130
1131  //
1132  // Try to open the Mtftp4 and Dhcp4 protocol to test whether IPv4 stack is ready.
1133  //
1134  Ip4Status = gBS->OpenProtocol (
1135                     ControllerHandle,
1136                     &gEfiDhcp4ServiceBindingProtocolGuid,
1137                     NULL,
1138                     This->DriverBindingHandle,
1139                     ControllerHandle,
1140                     EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1141                     );
1142  if (!EFI_ERROR (Ip4Status)) {
1143    Ip4Status = gBS->OpenProtocol (
1144                       ControllerHandle,
1145                       &gEfiMtftp4ServiceBindingProtocolGuid,
1146                       NULL,
1147                       This->DriverBindingHandle,
1148                       ControllerHandle,
1149                       EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1150                       );
1151  }
1152
1153  //
1154  // Try to open the Mtftp6 and Dhcp6 protocol to test whether IPv4 stack is ready.
1155  //
1156  Ip6Status = gBS->OpenProtocol (
1157                     ControllerHandle,
1158                     &gEfiDhcp6ServiceBindingProtocolGuid,
1159                     NULL,
1160                     This->DriverBindingHandle,
1161                     ControllerHandle,
1162                     EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1163                     );
1164  if (!EFI_ERROR (Ip6Status)) {
1165    Ip6Status = gBS->OpenProtocol (
1166                       ControllerHandle,
1167                       &gEfiMtftp6ServiceBindingProtocolGuid,
1168                       NULL,
1169                       This->DriverBindingHandle,
1170                       ControllerHandle,
1171                       EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1172                       );
1173  }
1174
1175  //
1176  // It's unsupported case if both stack are not ready.
1177  //
1178  if (EFI_ERROR (Ip4Status) && EFI_ERROR (Ip6Status)) {
1179    return EFI_UNSUPPORTED;
1180  }
1181
1182  return EFI_SUCCESS;
1183}
1184
1185
1186/**
1187  Start this driver on ControllerHandle. This service is called by the
1188  EFI boot service ConnectController(). In order to make
1189  drivers as small as possible, there are a few calling restrictions for
1190  this service. ConnectController() must follow these
1191  calling restrictions. If any other agent wishes to call Start() it
1192  must also follow these calling restrictions.
1193
1194  @param[in]  This                 The pointer to the driver binding protocol.
1195  @param[in]  ControllerHandle     The handle of device to be started.
1196  @param[in]  RemainingDevicePath  Optional parameter used to pick a specific child
1197                                   device to be started.
1198
1199  @retval EFI_SUCCESS          This driver is installed to ControllerHandle.
1200  @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle.
1201  @retval other                This driver does not support this device.
1202
1203**/
1204EFI_STATUS
1205EFIAPI
1206PxeBcDriverBindingStart (
1207  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
1208  IN EFI_HANDLE                   ControllerHandle,
1209  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
1210  )
1211{
1212  PXEBC_PRIVATE_DATA              *Private;
1213  EFI_STATUS                      Status;
1214  EFI_STATUS                      Ip4Status;
1215  EFI_STATUS                      Ip6Status;
1216  PXEBC_PRIVATE_PROTOCOL          *Id;
1217
1218  Status = gBS->OpenProtocol (
1219                  ControllerHandle,
1220                  &gEfiCallerIdGuid,
1221                  (VOID **) &Id,
1222                  This->DriverBindingHandle,
1223                  ControllerHandle,
1224                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
1225                  );
1226  if (!EFI_ERROR (Status)) {
1227    //
1228    // Skip the initialization if the driver has been started already.
1229    //
1230    Private = PXEBC_PRIVATE_DATA_FROM_ID (Id);
1231  } else {
1232    //
1233    // If the driver has not been started yet, it should do initialization.
1234    //
1235    Private = AllocateZeroPool (sizeof (PXEBC_PRIVATE_DATA));
1236    if (Private == NULL) {
1237      return EFI_OUT_OF_RESOURCES;
1238    }
1239
1240    CopyMem (
1241      &Private->PxeBc,
1242      &gPxeBcProtocolTemplate,
1243      sizeof (EFI_PXE_BASE_CODE_PROTOCOL)
1244      );
1245
1246    Private->Signature          = PXEBC_PRIVATE_DATA_SIGNATURE;
1247    Private->Controller         = ControllerHandle;
1248    Private->Image              = This->ImageHandle;
1249    Private->PxeBc.Mode         = &Private->Mode;
1250    Private->Mode.Ipv6Supported = TRUE;
1251    Private->Mode.AutoArp       = TRUE;
1252    Private->Mode.TTL           = DEFAULT_TTL;
1253    Private->Mode.ToS           = DEFAULT_ToS;
1254
1255    //
1256    // Open device path to prepare for appending virtual NIC node.
1257    //
1258    Status = gBS->OpenProtocol (
1259                    ControllerHandle,
1260                    &gEfiDevicePathProtocolGuid,
1261                    (VOID **) &Private->DevicePath,
1262                    This->DriverBindingHandle,
1263                    ControllerHandle,
1264                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
1265                    );
1266
1267    if (EFI_ERROR (Status)) {
1268      goto ON_ERROR;
1269    }
1270
1271    //
1272    // Get the NII interface if it exists, it's not required.
1273    //
1274    Status = gBS->OpenProtocol (
1275                    ControllerHandle,
1276                    &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
1277                    (VOID **) &Private->Nii,
1278                    This->DriverBindingHandle,
1279                    ControllerHandle,
1280                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
1281                    );
1282    if (EFI_ERROR (Status)) {
1283      Private->Nii = NULL;
1284    }
1285
1286    //
1287    // Install PxeBaseCodePrivate protocol onto the real NIC handler.
1288    // PxeBaseCodePrivate protocol is only used to keep the relationship between
1289    // NIC handle and virtual child handles.
1290    // gEfiCallerIdGuid will be used as its protocol guid.
1291    //
1292    Status = gBS->InstallProtocolInterface (
1293                    &ControllerHandle,
1294                    &gEfiCallerIdGuid,
1295                    EFI_NATIVE_INTERFACE,
1296                    &Private->Id
1297                    );
1298    if (EFI_ERROR (Status)) {
1299      goto ON_ERROR;
1300    }
1301
1302    //
1303    // Try to locate SNP protocol.
1304    //
1305    NetLibGetSnpHandle(ControllerHandle, &Private->Snp);
1306  }
1307
1308  //
1309  // Try to create virtual NIC handle for IPv4.
1310  //
1311  Ip4Status = PxeBcCreateIp4Children (This, ControllerHandle, Private);
1312
1313  //
1314  // Try to create virtual NIC handle for IPv6.
1315  //
1316  Ip6Status = PxeBcCreateIp6Children (This, ControllerHandle, Private);
1317
1318  if (EFI_ERROR (Ip4Status) && EFI_ERROR (Ip6Status)) {
1319    //
1320    // Failed to start PXE driver if IPv4 and IPv6 stack are both not available.
1321    //
1322    Status = EFI_DEVICE_ERROR;
1323    goto ON_ERROR;
1324  }
1325
1326  return EFI_SUCCESS;
1327
1328ON_ERROR:
1329  gBS->UninstallProtocolInterface (
1330         ControllerHandle,
1331         &gEfiCallerIdGuid,
1332         &Private->Id
1333         );
1334  PxeBcDestroyIp4Children (This, Private);
1335  PxeBcDestroyIp6Children (This, Private);
1336  FreePool (Private);
1337
1338  return Status;
1339}
1340
1341
1342/**
1343  Stop this driver on ControllerHandle. This service is called by the
1344  EFI boot service DisconnectController(). In order to
1345  make drivers as small as possible, there are a few calling
1346  restrictions for this service. DisconnectController()
1347  must follow these calling restrictions. If any other agent wishes
1348  to call Stop() it must also follow these calling restrictions.
1349
1350  @param[in]  This              Protocol instance pointer.
1351  @param[in]  ControllerHandle  Handle of device to stop driver on.
1352  @param[in]  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
1353                                children is zero stop the entire bus driver.
1354  @param[in]  ChildHandleBuffer List of Child Handles to Stop.
1355
1356  @retval EFI_SUCCESS           This driver was removed ControllerHandle.
1357  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
1358  @retval Others                This driver was not removed from this device
1359
1360**/
1361EFI_STATUS
1362EFIAPI
1363PxeBcDriverBindingStop (
1364  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
1365  IN EFI_HANDLE                   ControllerHandle,
1366  IN UINTN                        NumberOfChildren,
1367  IN EFI_HANDLE                   *ChildHandleBuffer
1368  )
1369{
1370  PXEBC_PRIVATE_DATA              *Private;
1371  PXEBC_VIRTUAL_NIC               *VirtualNic;
1372  EFI_LOAD_FILE_PROTOCOL          *LoadFile;
1373  EFI_STATUS                      Status;
1374  EFI_HANDLE                      NicHandle;
1375  BOOLEAN                         IsIpv6;
1376  PXEBC_PRIVATE_PROTOCOL          *Id;
1377
1378  Private    = NULL;
1379  NicHandle  = NULL;
1380  VirtualNic = NULL;
1381  LoadFile   = NULL;
1382  Id         = NULL;
1383  IsIpv6     = FALSE;
1384
1385  Status = gBS->OpenProtocol (
1386                  ControllerHandle,
1387                  &gEfiLoadFileProtocolGuid,
1388                  (VOID **) &LoadFile,
1389                  This->DriverBindingHandle,
1390                  ControllerHandle,
1391                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
1392                  );
1393  if (EFI_ERROR (Status)) {
1394    //
1395    // Get the Nic handle by any pass-over service child handle.
1396    //
1397    NicHandle = PxeBcGetNicByIp4Children (ControllerHandle);
1398    if (NicHandle == NULL) {
1399      NicHandle = PxeBcGetNicByIp6Children (ControllerHandle);
1400      if (NicHandle == NULL) {
1401        return EFI_DEVICE_ERROR;
1402      } else {
1403        IsIpv6 = TRUE;
1404      }
1405    }
1406
1407    //
1408    // Try to retrieve the private data by PxeBcPrivate protocol.
1409    //
1410    Status = gBS->OpenProtocol (
1411                    NicHandle,
1412                    &gEfiCallerIdGuid,
1413                    (VOID **) &Id,
1414                    This->DriverBindingHandle,
1415                    ControllerHandle,
1416                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
1417                    );
1418    if (EFI_ERROR (Status)) {
1419      return Status;
1420    }
1421    Private = PXEBC_PRIVATE_DATA_FROM_ID (Id);
1422
1423  } else {
1424    //
1425    // It's a virtual handle with LoadFileProtocol.
1426    //
1427    Status = gBS->OpenProtocol (
1428                    ControllerHandle,
1429                    &gEfiLoadFileProtocolGuid,
1430                    (VOID **) &LoadFile,
1431                    This->DriverBindingHandle,
1432                    ControllerHandle,
1433                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
1434                    );
1435    if (EFI_ERROR (Status)) {
1436      return Status;
1437    }
1438
1439    VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (LoadFile);
1440    Private    = VirtualNic->Private;
1441    NicHandle  = Private->Controller;
1442
1443    if (Private->Ip6Nic == VirtualNic) {
1444      IsIpv6   = TRUE;
1445    }
1446  }
1447
1448  //
1449  // Stop functionality of PXE Base Code protocol
1450  //
1451  Status = Private->PxeBc.Stop (&Private->PxeBc);
1452  if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) {
1453    return Status;
1454  }
1455
1456
1457  if (Private->Ip4Nic != NULL && !IsIpv6) {
1458    PxeBcDestroyIp4Children (This, Private);
1459  }
1460
1461  if (Private->Ip6Nic != NULL && IsIpv6) {
1462    PxeBcDestroyIp6Children (This, Private);
1463  }
1464
1465  if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) {
1466    gBS->UninstallProtocolInterface (
1467           NicHandle,
1468           &gEfiCallerIdGuid,
1469           &Private->Id
1470           );
1471    FreePool (Private);
1472  }
1473
1474  return EFI_SUCCESS;
1475}
1476