aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/ipxe/efi/efi_null.h2
-rw-r--r--src/include/ipxe/efi/efi_snp.h3
-rw-r--r--src/include/ipxe/vlan.h2
-rw-r--r--src/interface/efi/efi_null.c42
-rw-r--r--src/interface/efi/efi_snp.c179
-rw-r--r--src/net/vlan.c3
6 files changed, 227 insertions, 4 deletions
diff --git a/src/include/ipxe/efi/efi_null.h b/src/include/ipxe/efi/efi_null.h
index 2974570..d23d363 100644
--- a/src/include/ipxe/efi/efi_null.h
+++ b/src/include/ipxe/efi/efi_null.h
@@ -19,9 +19,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/Protocol/PxeBaseCode.h>
#include <ipxe/efi/Protocol/SimpleNetwork.h>
#include <ipxe/efi/Protocol/UsbIo.h>
+#include <ipxe/efi/Protocol/VlanConfig.h>
extern void efi_nullify_snp ( EFI_SIMPLE_NETWORK_PROTOCOL *snp );
extern void efi_nullify_nii ( EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *nii );
+extern void efi_nullify_vlan ( EFI_VLAN_CONFIG_PROTOCOL *vcfg );
extern void efi_nullify_name2 ( EFI_COMPONENT_NAME2_PROTOCOL *name2 );
extern void efi_nullify_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file );
extern void efi_nullify_hii ( EFI_HII_CONFIG_ACCESS_PROTOCOL *hii );
diff --git a/src/include/ipxe/efi/efi_snp.h b/src/include/ipxe/efi/efi_snp.h
index c278b1d..96373b5 100644
--- a/src/include/ipxe/efi/efi_snp.h
+++ b/src/include/ipxe/efi/efi_snp.h
@@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/efi/Protocol/HiiConfigAccess.h>
#include <ipxe/efi/Protocol/HiiDatabase.h>
#include <ipxe/efi/Protocol/LoadFile.h>
+#include <ipxe/efi/Protocol/VlanConfig.h>
/** SNP transmit completion ring size */
#define EFI_SNP_NUM_TX 32
@@ -51,6 +52,8 @@ struct efi_snp_device {
struct list_head rx;
/** The network interface identifier */
EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
+ /** VLAN configuration protocol */
+ EFI_VLAN_CONFIG_PROTOCOL vcfg;
/** Component name protocol */
EFI_COMPONENT_NAME2_PROTOCOL name2;
/** Load file protocol handle */
diff --git a/src/include/ipxe/vlan.h b/src/include/ipxe/vlan.h
index e4baf4c..8bf7923 100644
--- a/src/include/ipxe/vlan.h
+++ b/src/include/ipxe/vlan.h
@@ -74,6 +74,8 @@ vlan_tag ( struct net_device *netdev ) {
return VLAN_TAG ( vlan_tci ( netdev ) );
}
+extern struct net_device * vlan_find ( struct net_device *trunk,
+ unsigned int tag );
extern int vlan_can_be_trunk ( struct net_device *trunk );
extern int vlan_create ( struct net_device *trunk, unsigned int tag,
unsigned int priority );
diff --git a/src/interface/efi/efi_null.c b/src/interface/efi/efi_null.c
index 29ca5b9..d0f0428 100644
--- a/src/interface/efi/efi_null.c
+++ b/src/interface/efi/efi_null.c
@@ -195,6 +195,48 @@ void efi_nullify_nii ( EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *nii ) {
/******************************************************************************
*
+ * VLAN configuration protocol
+ *
+ ******************************************************************************
+ */
+
+static EFI_STATUS EFIAPI
+efi_null_vlan_set ( EFI_VLAN_CONFIG_PROTOCOL *vcfg __unused,
+ UINT16 tag __unused, UINT8 priority __unused ) {
+ return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_vlan_find ( EFI_VLAN_CONFIG_PROTOCOL *vcfg __unused,
+ UINT16 *filter __unused, UINT16 *count __unused,
+ EFI_VLAN_FIND_DATA **entries __unused ) {
+ return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_vlan_remove ( EFI_VLAN_CONFIG_PROTOCOL *vcfg __unused,
+ UINT16 tag __unused ) {
+ return EFI_UNSUPPORTED;
+}
+
+static EFI_VLAN_CONFIG_PROTOCOL efi_null_vlan = {
+ .Set = efi_null_vlan_set,
+ .Find = efi_null_vlan_find,
+ .Remove = efi_null_vlan_remove,
+};
+
+/**
+ * Nullify VLAN configuration interface
+ *
+ * @v vcfg VLAN configuration protocol
+ */
+void efi_nullify_vlan ( EFI_VLAN_CONFIG_PROTOCOL *vcfg ) {
+
+ memcpy ( vcfg, &efi_null_vlan, sizeof ( *vcfg ) );
+}
+
+/******************************************************************************
+ *
* Component name protocol
*
******************************************************************************
diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c
index 6649eb1..088a3fd 100644
--- a/src/interface/efi/efi_snp.c
+++ b/src/interface/efi/efi_snp.c
@@ -1490,6 +1490,164 @@ static EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL efi_snp_device_nii = {
/******************************************************************************
*
+ * VLAN configuration protocol
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Create or modify VLAN device
+ *
+ * @v vcfg VLAN configuration protocol
+ * @v tag VLAN tag
+ * @v priority Default VLAN priority
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI efi_vlan_set ( EFI_VLAN_CONFIG_PROTOCOL *vcfg,
+ UINT16 tag, UINT8 priority ) {
+ struct efi_snp_device *snpdev =
+ container_of ( vcfg, struct efi_snp_device, vcfg );
+ struct net_device *trunk = snpdev->netdev;
+ struct efi_saved_tpl tpl;
+ int rc;
+
+ /* Raise TPL */
+ efi_raise_tpl ( &tpl );
+
+ /* Create or modify VLAN device */
+ if ( ( rc = vlan_create ( trunk, tag, priority ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not create VLAN tag %d: %s\n",
+ snpdev, tag, strerror ( rc ) );
+ goto err_create;
+ }
+ DBGC ( snpdev, "SNPDEV %p created VLAN tag %d priority %d\n",
+ snpdev, tag, priority );
+
+ err_create:
+ efi_restore_tpl ( &tpl );
+ return EFIRC ( rc );
+}
+
+/**
+ * Find VLAN device(s)
+ *
+ * @v vcfg VLAN configuration protocol
+ * @v filter VLAN tag, or NULL to find all VLANs
+ * @v count Number of VLANs
+ * @v entries List of VLANs
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI efi_vlan_find ( EFI_VLAN_CONFIG_PROTOCOL *vcfg,
+ UINT16 *filter, UINT16 *count,
+ EFI_VLAN_FIND_DATA **entries ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_snp_device *snpdev =
+ container_of ( vcfg, struct efi_snp_device, vcfg );
+ struct net_device *trunk = snpdev->netdev;
+ struct net_device *vlan;
+ struct efi_saved_tpl tpl;
+ EFI_VLAN_FIND_DATA *entry;
+ VOID *buffer;
+ unsigned int tag;
+ unsigned int tci;
+ size_t len;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Raise TPL */
+ efi_raise_tpl ( &tpl );
+
+ /* Count number of matching VLANs */
+ *count = 0;
+ for ( tag = 1 ; VLAN_TAG_IS_VALID ( tag ) ; tag++ ) {
+ if ( filter && ( tag != *filter ) )
+ continue;
+ if ( ! ( vlan = vlan_find ( trunk, tag ) ) )
+ continue;
+ (*count)++;
+ }
+
+ /* Allocate buffer to hold results */
+ len = ( (*count) * sizeof ( *entry ) );
+ if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, len,
+ &buffer ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ goto err_alloc;
+ }
+
+ /* Fill in buffer */
+ *entries = buffer;
+ entry = *entries;
+ for ( tag = 1 ; VLAN_TAG_IS_VALID ( tag ) ; tag++ ) {
+ if ( filter && ( tag != *filter ) )
+ continue;
+ if ( ! ( vlan = vlan_find ( trunk, tag ) ) )
+ continue;
+ tci = vlan_tci ( vlan );
+ entry->VlanId = VLAN_TAG ( tci );
+ entry->Priority = VLAN_PRIORITY ( tci );
+ assert ( entry->VlanId == tag );
+ entry++;
+ }
+ assert ( entry == &(*entries)[*count] );
+
+ /* Success */
+ rc = 0;
+
+ err_alloc:
+ efi_restore_tpl ( &tpl );
+ return EFIRC ( rc );
+}
+
+/**
+ * Remove VLAN device
+ *
+ * @v vcfg VLAN configuration protocol
+ * @v tag VLAN tag
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI efi_vlan_remove ( EFI_VLAN_CONFIG_PROTOCOL *vcfg,
+ UINT16 tag ) {
+ struct efi_snp_device *snpdev =
+ container_of ( vcfg, struct efi_snp_device, vcfg );
+ struct net_device *trunk = snpdev->netdev;
+ struct net_device *vlan;
+ struct efi_saved_tpl tpl;
+ int rc;
+
+ /* Raise TPL */
+ efi_raise_tpl ( &tpl );
+
+ /* Identify VLAN device */
+ vlan = vlan_find ( trunk, tag );
+ if ( ! vlan ) {
+ DBGC ( snpdev, "SNPDEV %p could not find VLAN tag %d\n",
+ snpdev, tag );
+ rc = -ENOENT;
+ goto err_find;
+ }
+
+ /* Remove VLAN device */
+ vlan_destroy ( vlan );
+ DBGC ( snpdev, "SNPDEV %p removed VLAN tag %d\n", snpdev, tag );
+
+ /* Success */
+ rc = 0;
+
+ err_find:
+ efi_restore_tpl ( &tpl );
+ return EFIRC ( rc );
+}
+
+/** VLAN configuration protocol */
+static EFI_VLAN_CONFIG_PROTOCOL efi_vlan = {
+ .Set = efi_vlan_set,
+ .Find = efi_vlan_find,
+ .Remove = efi_vlan_remove,
+};
+
+/******************************************************************************
+ *
* Component name protocol
*
******************************************************************************
@@ -1627,6 +1785,8 @@ static int efi_snp_probe ( struct net_device *netdev ) {
struct efi_snp_device *snpdev;
unsigned int ifcnt;
void *interface;
+ unsigned int tci;
+ char vlan_name[ 12 /* ", VLAN xxxx" + NUL */ ];
int leak = 0;
EFI_STATUS efirc;
int rc;
@@ -1687,17 +1847,27 @@ static int efi_snp_probe ( struct net_device *netdev ) {
efi_snp_undi.Fudge -= efi_undi_checksum ( &efi_snp_undi,
sizeof ( efi_snp_undi ) );
+ /* Populate the VLAN configuration protocol */
+ memcpy ( &snpdev->vcfg, &efi_vlan, sizeof ( snpdev->vcfg ) );
+
/* Populate the component name structure */
efi_snprintf ( snpdev->driver_name,
( sizeof ( snpdev->driver_name ) /
sizeof ( snpdev->driver_name[0] ) ),
"%s %s", product_short_name, netdev->dev->driver_name );
+ tci = vlan_tci ( netdev );
+ if ( tci ) {
+ snprintf ( vlan_name, sizeof ( vlan_name ), ", VLAN %d",
+ VLAN_TAG ( tci ) );
+ } else {
+ vlan_name[0] = '\0';
+ }
efi_snprintf ( snpdev->controller_name,
( sizeof ( snpdev->controller_name ) /
sizeof ( snpdev->controller_name[0] ) ),
- "%s %s (%s, %s)", product_short_name,
+ "%s %s (%s, %s%s)", product_short_name,
netdev->dev->driver_name, netdev->dev->name,
- netdev_addr ( netdev ) );
+ netdev_addr ( netdev ), vlan_name );
snpdev->name2.GetDriverName = efi_snp_get_driver_name;
snpdev->name2.GetControllerName = efi_snp_get_controller_name;
snpdev->name2.SupportedLanguages = "en";
@@ -1725,6 +1895,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
&efi_device_path_protocol_guid, snpdev->path,
&efi_nii_protocol_guid, &snpdev->nii,
&efi_nii31_protocol_guid, &snpdev->nii,
+ &efi_vlan_config_protocol_guid, &snpdev->vcfg,
&efi_component_name2_protocol_guid, &snpdev->name2,
&efi_load_file_protocol_guid, &snpdev->load_file,
NULL ) ) != 0 ) {
@@ -1811,6 +1982,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
&efi_device_path_protocol_guid, snpdev->path,
&efi_nii_protocol_guid, &snpdev->nii,
&efi_nii31_protocol_guid, &snpdev->nii,
+ &efi_vlan_config_protocol_guid, &snpdev->vcfg,
&efi_component_name2_protocol_guid, &snpdev->name2,
&efi_load_file_protocol_guid, &snpdev->load_file,
NULL ) ) != 0 ) {
@@ -1820,6 +1992,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
}
efi_nullify_snp ( &snpdev->snp );
efi_nullify_nii ( &snpdev->nii );
+ efi_nullify_vlan ( &snpdev->vcfg );
efi_nullify_name2 ( &snpdev->name2 );
efi_nullify_load_file ( &snpdev->load_file );
err_install_protocol_interface:
@@ -1899,6 +2072,7 @@ static void efi_snp_remove ( struct net_device *netdev ) {
&efi_device_path_protocol_guid, snpdev->path,
&efi_nii_protocol_guid, &snpdev->nii,
&efi_nii31_protocol_guid, &snpdev->nii,
+ &efi_vlan_config_protocol_guid, &snpdev->vcfg,
&efi_component_name2_protocol_guid, &snpdev->name2,
&efi_load_file_protocol_guid, &snpdev->load_file,
NULL ) ) != 0 ) ) {
@@ -1908,6 +2082,7 @@ static void efi_snp_remove ( struct net_device *netdev ) {
}
efi_nullify_snp ( &snpdev->snp );
efi_nullify_nii ( &snpdev->nii );
+ efi_nullify_vlan ( &snpdev->vcfg );
efi_nullify_name2 ( &snpdev->name2 );
efi_nullify_load_file ( &snpdev->load_file );
if ( ! leak )
diff --git a/src/net/vlan.c b/src/net/vlan.c
index fe44886..81ec623 100644
--- a/src/net/vlan.c
+++ b/src/net/vlan.c
@@ -199,8 +199,7 @@ static void vlan_sync ( struct net_device *netdev ) {
* @v tag VLAN tag
* @ret netdev VLAN device, if any
*/
-static struct net_device * vlan_find ( struct net_device *trunk,
- unsigned int tag ) {
+struct net_device * vlan_find ( struct net_device *trunk, unsigned int tag ) {
struct net_device *netdev;
struct vlan_device *vlan;