[efi] Veto the VirtualBox E1kNetDxe driver

The VirtualBox E1kNetDxe driver has a Stop() method that relies on
being passed its own child device handle.  Unfortunately, the same
driver's Start() method never opens the parent device handle with
BY_CHILD_CONTROLLER attributes on behalf of the newly installed child
device handle, with the result that the UEFI device model is
completely unaware of the nominal parent-child relationship.  This
omission can be observed via the UEFI shell "devtree" command, which
will show the child SNP device handle as a standalone top-level device
handle, with no relationship to its underlying parent PCI device
handle.

The upshot of this omission is that the VirtualBox E1kNetDxe driver's
Stop() method is a pure no-op.  Calling DisconnectController() on the
PCI device handle will return successfully, but will not have actually
disconnected anything.  A subsequent attempt to open the handle on
behalf of iPXE's native Intel driver will get stuck in an infinite
loop inside OpenProtocol(), as the firmware repeatedly calls
DisconnectController() in an attempt to disconnect the E1kNetDxe
driver from the PCI device handle.

Work around this problem by adding the buggy VirtualBox E1kNetDxe
driver to the veto list.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c
index a3b60d6..40dce9d 100644
--- a/src/interface/efi/efi_veto.c
+++ b/src/interface/efi/efi_veto.c
@@ -494,6 +494,37 @@
 	return 1;
 }
 
+/**
+ * Veto VirtualBox E1kNetDxe driver
+ *
+ * @v binding		Driver binding protocol
+ * @v loaded		Loaded image protocol
+ * @v wtf		Component name protocol, if present
+ * @v manufacturer	Manufacturer name, if present
+ * @v name		Driver name, if present
+ * @ret vetoed		Driver is to be vetoed
+ */
+static int
+efi_veto_vbox_e1knet ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
+		       EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
+		       EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
+		       const char *manufacturer, const CHAR16 *name ) {
+	static const CHAR16 e1knet[] = L"E1000 network interface card Driver";
+	static const char *vbox = "innotek GmbH";
+
+	/* Check manufacturer and driver name */
+	if ( ! manufacturer )
+		return 0;
+	if ( ! name )
+		return 0;
+	if ( strcmp ( manufacturer, vbox ) != 0 )
+		return 0;
+	if ( memcmp ( name, e1knet, sizeof ( e1knet ) ) != 0 )
+		return 0;
+
+	return 1;
+}
+
 /** Driver vetoes */
 static struct efi_veto_candidate efi_vetoes[] = {
 	{
@@ -508,6 +539,10 @@
 		.name = "VMware UefiPxeBc",
 		.veto = efi_veto_vmware_uefipxebc,
 	},
+	{
+		.name = "VirtualBox E1kNetDxe",
+		.veto = efi_veto_vbox_e1knet,
+	},
 };
 
 /**