mirror of https://github.com/ipxe/ipxe.git
[acpi] Support the "_RTXMAC_" format for ACPI-based MAC addresses
Some newer HP products expose the host-based MAC (HBMAC) address using an ACPI method named "RTMA" returning a part-binary string of the form "_RTXMAC_#<mac>#", where "<mac>" comprises the raw MAC address bytes. Extend the existing support to handle this format alongside the older "_AUXMAC_" format (which uses a base16-encoded MAC address). Reported-by: Andreas Hammarskjöld <junior@2PintSoftware.com> Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/631/head
parent
614c3f43a1
commit
f58b5109f4
|
@ -46,11 +46,79 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
/** MACA signature */
|
||||
#define MACA_SIGNATURE ACPI_SIGNATURE ( 'M', 'A', 'C', 'A' )
|
||||
|
||||
/** Maximum number of bytes to skip after AMAC/MACA signature
|
||||
/** RTMA signature */
|
||||
#define RTMA_SIGNATURE ACPI_SIGNATURE ( 'R', 'T', 'M', 'A' )
|
||||
|
||||
/** Maximum number of bytes to skip after ACPI signature
|
||||
*
|
||||
* This is entirely empirical.
|
||||
*/
|
||||
#define AUXMAC_MAX_SKIP 8
|
||||
#define ACPIMAC_MAX_SKIP 8
|
||||
|
||||
/** An ACPI MAC extraction mechanism */
|
||||
struct acpimac_extractor {
|
||||
/** Prefix string */
|
||||
const char *prefix;
|
||||
/** Encoded MAC length */
|
||||
size_t len;
|
||||
/** Decode MAC
|
||||
*
|
||||
* @v mac Encoded MAC
|
||||
* @v hw_addr MAC address to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int ( * decode ) ( const char *mac, uint8_t *hw_addr );
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode Base16-encoded MAC address
|
||||
*
|
||||
* @v mac Encoded MAC
|
||||
* @v hw_addr MAC address to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int acpimac_decode_base16 ( const char *mac, uint8_t *hw_addr ) {
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Attempt to base16-decode MAC address */
|
||||
len = base16_decode ( mac, hw_addr, ETH_ALEN );
|
||||
if ( len < 0 ) {
|
||||
rc = len;
|
||||
DBGC ( colour, "ACPI could not decode base16 MAC \"%s\": %s\n",
|
||||
mac, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode raw MAC address
|
||||
*
|
||||
* @v mac Encoded MAC
|
||||
* @v hw_addr MAC address to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int acpimac_decode_raw ( const char *mac, uint8_t *hw_addr ) {
|
||||
|
||||
memcpy ( hw_addr, mac, ETH_ALEN );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** "_AUXMAC_" extraction mechanism */
|
||||
static struct acpimac_extractor acpimac_auxmac = {
|
||||
.prefix = "_AUXMAC_#",
|
||||
.len = ( ETH_ALEN * 2 ),
|
||||
.decode = acpimac_decode_base16,
|
||||
};
|
||||
|
||||
/** "_RTXMAC_" extraction mechanism */
|
||||
static struct acpimac_extractor acpimac_rtxmac = {
|
||||
.prefix = "_RTXMAC_#",
|
||||
.len = ETH_ALEN,
|
||||
.decode = acpimac_decode_raw,
|
||||
};
|
||||
|
||||
/**
|
||||
* Extract MAC address from DSDT/SSDT
|
||||
|
@ -59,6 +127,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
* @v len Length of DSDT/SSDT
|
||||
* @v offset Offset of signature within DSDT/SSDT
|
||||
* @v data Data buffer
|
||||
* @v extractor ACPI MAC address extractor
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* Some vendors provide a "system MAC address" within the DSDT/SSDT,
|
||||
|
@ -72,51 +141,44 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
* string that appears shortly after an "AMAC" or "MACA" signature.
|
||||
* This should work for most implementations encountered in practice.
|
||||
*/
|
||||
static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset,
|
||||
void *data ) {
|
||||
static const char prefix[9] = "_AUXMAC_#";
|
||||
static int acpimac_extract ( userptr_t zsdt, size_t len, size_t offset,
|
||||
void *data, struct acpimac_extractor *extractor ){
|
||||
size_t prefix_len = strlen ( extractor->prefix );
|
||||
uint8_t *hw_addr = data;
|
||||
size_t skip = 0;
|
||||
char auxmac[ sizeof ( prefix ) /* "_AUXMAC_#" */ +
|
||||
( ETH_ALEN * 2 ) /* MAC */ + 1 /* "#" */ + 1 /* NUL */ ];
|
||||
char *mac = &auxmac[ sizeof ( prefix ) ];
|
||||
int decoded_len;
|
||||
char buf[ prefix_len + extractor->len + 1 /* "#" */ + 1 /* NUL */ ];
|
||||
char *mac = &buf[prefix_len];
|
||||
int rc;
|
||||
|
||||
/* Skip signature and at least one tag byte */
|
||||
offset += ( 4 /* signature */ + 1 /* tag byte */ );
|
||||
|
||||
/* Scan for "_AUXMAC_#.....#" close to signature */
|
||||
/* Scan for suitable string close to signature */
|
||||
for ( skip = 0 ;
|
||||
( ( skip < AUXMAC_MAX_SKIP ) &&
|
||||
( offset + skip + sizeof ( auxmac ) ) < len ) ;
|
||||
( ( skip < ACPIMAC_MAX_SKIP ) &&
|
||||
( offset + skip + sizeof ( buf ) ) <= len ) ;
|
||||
skip++ ) {
|
||||
|
||||
/* Read value */
|
||||
copy_from_user ( auxmac, zsdt, ( offset + skip ),
|
||||
sizeof ( auxmac ) );
|
||||
copy_from_user ( buf, zsdt, ( offset + skip ),
|
||||
sizeof ( buf ) );
|
||||
|
||||
/* Check for expected format */
|
||||
if ( memcmp ( auxmac, prefix, sizeof ( prefix ) ) != 0 )
|
||||
if ( memcmp ( buf, extractor->prefix, prefix_len ) != 0 )
|
||||
continue;
|
||||
if ( auxmac[ sizeof ( auxmac ) - 2 ] != '#' )
|
||||
if ( buf[ sizeof ( buf ) - 2 ] != '#' )
|
||||
continue;
|
||||
if ( auxmac[ sizeof ( auxmac ) - 1 ] != '\0' )
|
||||
if ( buf[ sizeof ( buf ) - 1 ] != '\0' )
|
||||
continue;
|
||||
DBGC ( colour, "ACPI found MAC string \"%s\"\n", auxmac );
|
||||
DBGC ( colour, "ACPI found MAC:\n" );
|
||||
DBGC_HDA ( colour, ( offset + skip ), buf, sizeof ( buf ) );
|
||||
|
||||
/* Terminate MAC address string */
|
||||
mac = &auxmac[ sizeof ( prefix ) ];
|
||||
mac[ ETH_ALEN * 2 ] = '\0';
|
||||
mac[extractor->len] = '\0';
|
||||
|
||||
/* Decode MAC address */
|
||||
decoded_len = base16_decode ( mac, hw_addr, ETH_ALEN );
|
||||
if ( decoded_len < 0 ) {
|
||||
rc = decoded_len;
|
||||
DBGC ( colour, "ACPI could not decode MAC \"%s\": %s\n",
|
||||
mac, strerror ( rc ) );
|
||||
if ( ( rc = extractor->decode ( mac, hw_addr ) ) != 0 )
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Check MAC address validity */
|
||||
if ( ! is_valid_ether_addr ( hw_addr ) ) {
|
||||
|
@ -131,6 +193,36 @@ static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset,
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract "_AUXMAC_" MAC address from DSDT/SSDT
|
||||
*
|
||||
* @v zsdt DSDT or SSDT
|
||||
* @v len Length of DSDT/SSDT
|
||||
* @v offset Offset of signature within DSDT/SSDT
|
||||
* @v data Data buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int acpimac_extract_auxmac ( userptr_t zsdt, size_t len, size_t offset,
|
||||
void *data ) {
|
||||
|
||||
return acpimac_extract ( zsdt, len, offset, data, &acpimac_auxmac );
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract "_RTXMAC_" MAC address from DSDT/SSDT
|
||||
*
|
||||
* @v zsdt DSDT or SSDT
|
||||
* @v len Length of DSDT/SSDT
|
||||
* @v offset Offset of signature within DSDT/SSDT
|
||||
* @v data Data buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int acpimac_extract_rtxmac ( userptr_t zsdt, size_t len, size_t offset,
|
||||
void *data ) {
|
||||
|
||||
return acpimac_extract ( zsdt, len, offset, data, &acpimac_rtxmac );
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract MAC address from DSDT/SSDT
|
||||
*
|
||||
|
@ -142,12 +234,17 @@ int acpi_mac ( uint8_t *hw_addr ) {
|
|||
|
||||
/* Look for an "AMAC" address */
|
||||
if ( ( rc = acpi_extract ( AMAC_SIGNATURE, hw_addr,
|
||||
acpi_extract_mac ) ) == 0 )
|
||||
acpimac_extract_auxmac ) ) == 0 )
|
||||
return 0;
|
||||
|
||||
/* Look for a "MACA" address */
|
||||
if ( ( rc = acpi_extract ( MACA_SIGNATURE, hw_addr,
|
||||
acpi_extract_mac ) ) == 0 )
|
||||
acpimac_extract_auxmac ) ) == 0 )
|
||||
return 0;
|
||||
|
||||
/* Look for a "RTMA" address */
|
||||
if ( ( rc = acpi_extract ( RTMA_SIGNATURE, hw_addr,
|
||||
acpimac_extract_rtxmac ) ) == 0 )
|
||||
return 0;
|
||||
|
||||
return -ENOENT;
|
||||
|
|
|
@ -159,6 +159,24 @@ ACPI_TABLES ( maca_tables, &maca_ssdt1, &maca_ssdt2 );
|
|||
ACPI_MAC ( maca, &maca_tables,
|
||||
DATA ( 0x52, 0x54, 0x00, 0x11, 0x22, 0x33 ) );
|
||||
|
||||
/** "RTMA" SSDT */
|
||||
ACPI_TABLE ( rtma_ssdt, "SSDT",
|
||||
DATA ( 0x53, 0x53, 0x44, 0x54, 0x44, 0x00, 0x00, 0x00, 0x02,
|
||||
0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x49, 0x4e, 0x54, 0x4c, 0x04, 0x06, 0x21, 0x20,
|
||||
0x10, 0x1f, 0x5c, 0x5f, 0x53, 0x42, 0x5f, 0x14, 0x18,
|
||||
0x52, 0x54, 0x4d, 0x41, 0x08, 0x0d, 0x5f, 0x52, 0x54,
|
||||
0x58, 0x4d, 0x41, 0x43, 0x5f, 0x23, 0x52, 0x54, 0x30,
|
||||
0x30, 0x30, 0x31, 0x23, 0x00 ) );
|
||||
|
||||
/** "RTMA" test tables */
|
||||
ACPI_TABLES ( rtma_tables, &rtma_ssdt );
|
||||
|
||||
/** "RTMA" test */
|
||||
ACPI_MAC ( rtma, &rtma_tables,
|
||||
DATA ( 0x52, 0x54, 0x30, 0x30, 0x30, 0x31 ) );
|
||||
|
||||
/** Current ACPI test table set */
|
||||
static struct acpi_test_tables *acpi_test_tables;
|
||||
|
||||
|
@ -229,6 +247,7 @@ static void acpi_test_exec ( void ) {
|
|||
/* MAC extraction tests */
|
||||
acpi_mac_ok ( &amac );
|
||||
acpi_mac_ok ( &maca );
|
||||
acpi_mac_ok ( &rtma );
|
||||
}
|
||||
|
||||
/** ACPI self-test */
|
||||
|
|
Loading…
Reference in New Issue