diff options
-rw-r--r-- | src/include/ipxe/efi/efi_null.h | 2 | ||||
-rw-r--r-- | src/include/ipxe/efi/efi_snp.h | 3 | ||||
-rw-r--r-- | src/include/ipxe/vlan.h | 2 | ||||
-rw-r--r-- | src/interface/efi/efi_null.c | 42 | ||||
-rw-r--r-- | src/interface/efi/efi_snp.c | 179 | ||||
-rw-r--r-- | src/net/vlan.c | 3 |
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 297457081..d23d36349 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 c278b1d4c..96373b57d 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 e4baf4cf0..8bf79234b 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 29ca5b9b6..d0f0428cc 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 6649eb1b0..088a3fdbd 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 fe4488614..81ec623f2 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; |