Skip to content

Commit f58b510

Browse files
committed
[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 <[email protected]> Tested-by: Andreas Hammarskjöld <[email protected]> Signed-off-by: Michael Brown <[email protected]>
1 parent 614c3f4 commit f58b510

File tree

2 files changed

+144
-28
lines changed

2 files changed

+144
-28
lines changed

src/core/acpimac.c

Lines changed: 125 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,79 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4646
/** MACA signature */
4747
#define MACA_SIGNATURE ACPI_SIGNATURE ( 'M', 'A', 'C', 'A' )
4848

49-
/** Maximum number of bytes to skip after AMAC/MACA signature
49+
/** RTMA signature */
50+
#define RTMA_SIGNATURE ACPI_SIGNATURE ( 'R', 'T', 'M', 'A' )
51+
52+
/** Maximum number of bytes to skip after ACPI signature
5053
*
5154
* This is entirely empirical.
5255
*/
53-
#define AUXMAC_MAX_SKIP 8
56+
#define ACPIMAC_MAX_SKIP 8
57+
58+
/** An ACPI MAC extraction mechanism */
59+
struct acpimac_extractor {
60+
/** Prefix string */
61+
const char *prefix;
62+
/** Encoded MAC length */
63+
size_t len;
64+
/** Decode MAC
65+
*
66+
* @v mac Encoded MAC
67+
* @v hw_addr MAC address to fill in
68+
* @ret rc Return status code
69+
*/
70+
int ( * decode ) ( const char *mac, uint8_t *hw_addr );
71+
};
72+
73+
/**
74+
* Decode Base16-encoded MAC address
75+
*
76+
* @v mac Encoded MAC
77+
* @v hw_addr MAC address to fill in
78+
* @ret rc Return status code
79+
*/
80+
static int acpimac_decode_base16 ( const char *mac, uint8_t *hw_addr ) {
81+
int len;
82+
int rc;
83+
84+
/* Attempt to base16-decode MAC address */
85+
len = base16_decode ( mac, hw_addr, ETH_ALEN );
86+
if ( len < 0 ) {
87+
rc = len;
88+
DBGC ( colour, "ACPI could not decode base16 MAC \"%s\": %s\n",
89+
mac, strerror ( rc ) );
90+
return rc;
91+
}
92+
93+
return 0;
94+
}
95+
96+
/**
97+
* Decode raw MAC address
98+
*
99+
* @v mac Encoded MAC
100+
* @v hw_addr MAC address to fill in
101+
* @ret rc Return status code
102+
*/
103+
static int acpimac_decode_raw ( const char *mac, uint8_t *hw_addr ) {
104+
105+
memcpy ( hw_addr, mac, ETH_ALEN );
106+
return 0;
107+
}
108+
109+
/** "_AUXMAC_" extraction mechanism */
110+
static struct acpimac_extractor acpimac_auxmac = {
111+
.prefix = "_AUXMAC_#",
112+
.len = ( ETH_ALEN * 2 ),
113+
.decode = acpimac_decode_base16,
114+
};
115+
116+
/** "_RTXMAC_" extraction mechanism */
117+
static struct acpimac_extractor acpimac_rtxmac = {
118+
.prefix = "_RTXMAC_#",
119+
.len = ETH_ALEN,
120+
.decode = acpimac_decode_raw,
121+
};
54122

55123
/**
56124
* Extract MAC address from DSDT/SSDT
@@ -59,6 +127,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
59127
* @v len Length of DSDT/SSDT
60128
* @v offset Offset of signature within DSDT/SSDT
61129
* @v data Data buffer
130+
* @v extractor ACPI MAC address extractor
62131
* @ret rc Return status code
63132
*
64133
* Some vendors provide a "system MAC address" within the DSDT/SSDT,
@@ -72,51 +141,44 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
72141
* string that appears shortly after an "AMAC" or "MACA" signature.
73142
* This should work for most implementations encountered in practice.
74143
*/
75-
static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset,
76-
void *data ) {
77-
static const char prefix[9] = "_AUXMAC_#";
144+
static int acpimac_extract ( userptr_t zsdt, size_t len, size_t offset,
145+
void *data, struct acpimac_extractor *extractor ){
146+
size_t prefix_len = strlen ( extractor->prefix );
78147
uint8_t *hw_addr = data;
79148
size_t skip = 0;
80-
char auxmac[ sizeof ( prefix ) /* "_AUXMAC_#" */ +
81-
( ETH_ALEN * 2 ) /* MAC */ + 1 /* "#" */ + 1 /* NUL */ ];
82-
char *mac = &auxmac[ sizeof ( prefix ) ];
83-
int decoded_len;
149+
char buf[ prefix_len + extractor->len + 1 /* "#" */ + 1 /* NUL */ ];
150+
char *mac = &buf[prefix_len];
84151
int rc;
85152

86153
/* Skip signature and at least one tag byte */
87154
offset += ( 4 /* signature */ + 1 /* tag byte */ );
88155

89-
/* Scan for "_AUXMAC_#.....#" close to signature */
156+
/* Scan for suitable string close to signature */
90157
for ( skip = 0 ;
91-
( ( skip < AUXMAC_MAX_SKIP ) &&
92-
( offset + skip + sizeof ( auxmac ) ) < len ) ;
158+
( ( skip < ACPIMAC_MAX_SKIP ) &&
159+
( offset + skip + sizeof ( buf ) ) <= len ) ;
93160
skip++ ) {
94161

95162
/* Read value */
96-
copy_from_user ( auxmac, zsdt, ( offset + skip ),
97-
sizeof ( auxmac ) );
163+
copy_from_user ( buf, zsdt, ( offset + skip ),
164+
sizeof ( buf ) );
98165

99166
/* Check for expected format */
100-
if ( memcmp ( auxmac, prefix, sizeof ( prefix ) ) != 0 )
167+
if ( memcmp ( buf, extractor->prefix, prefix_len ) != 0 )
101168
continue;
102-
if ( auxmac[ sizeof ( auxmac ) - 2 ] != '#' )
169+
if ( buf[ sizeof ( buf ) - 2 ] != '#' )
103170
continue;
104-
if ( auxmac[ sizeof ( auxmac ) - 1 ] != '\0' )
171+
if ( buf[ sizeof ( buf ) - 1 ] != '\0' )
105172
continue;
106-
DBGC ( colour, "ACPI found MAC string \"%s\"\n", auxmac );
173+
DBGC ( colour, "ACPI found MAC:\n" );
174+
DBGC_HDA ( colour, ( offset + skip ), buf, sizeof ( buf ) );
107175

108176
/* Terminate MAC address string */
109-
mac = &auxmac[ sizeof ( prefix ) ];
110-
mac[ ETH_ALEN * 2 ] = '\0';
177+
mac[extractor->len] = '\0';
111178

112179
/* Decode MAC address */
113-
decoded_len = base16_decode ( mac, hw_addr, ETH_ALEN );
114-
if ( decoded_len < 0 ) {
115-
rc = decoded_len;
116-
DBGC ( colour, "ACPI could not decode MAC \"%s\": %s\n",
117-
mac, strerror ( rc ) );
180+
if ( ( rc = extractor->decode ( mac, hw_addr ) ) != 0 )
118181
return rc;
119-
}
120182

121183
/* Check MAC address validity */
122184
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,
131193
return -ENOENT;
132194
}
133195

196+
/**
197+
* Extract "_AUXMAC_" MAC address from DSDT/SSDT
198+
*
199+
* @v zsdt DSDT or SSDT
200+
* @v len Length of DSDT/SSDT
201+
* @v offset Offset of signature within DSDT/SSDT
202+
* @v data Data buffer
203+
* @ret rc Return status code
204+
*/
205+
static int acpimac_extract_auxmac ( userptr_t zsdt, size_t len, size_t offset,
206+
void *data ) {
207+
208+
return acpimac_extract ( zsdt, len, offset, data, &acpimac_auxmac );
209+
}
210+
211+
/**
212+
* Extract "_RTXMAC_" MAC address from DSDT/SSDT
213+
*
214+
* @v zsdt DSDT or SSDT
215+
* @v len Length of DSDT/SSDT
216+
* @v offset Offset of signature within DSDT/SSDT
217+
* @v data Data buffer
218+
* @ret rc Return status code
219+
*/
220+
static int acpimac_extract_rtxmac ( userptr_t zsdt, size_t len, size_t offset,
221+
void *data ) {
222+
223+
return acpimac_extract ( zsdt, len, offset, data, &acpimac_rtxmac );
224+
}
225+
134226
/**
135227
* Extract MAC address from DSDT/SSDT
136228
*
@@ -142,12 +234,17 @@ int acpi_mac ( uint8_t *hw_addr ) {
142234

143235
/* Look for an "AMAC" address */
144236
if ( ( rc = acpi_extract ( AMAC_SIGNATURE, hw_addr,
145-
acpi_extract_mac ) ) == 0 )
237+
acpimac_extract_auxmac ) ) == 0 )
146238
return 0;
147239

148240
/* Look for a "MACA" address */
149241
if ( ( rc = acpi_extract ( MACA_SIGNATURE, hw_addr,
150-
acpi_extract_mac ) ) == 0 )
242+
acpimac_extract_auxmac ) ) == 0 )
243+
return 0;
244+
245+
/* Look for a "RTMA" address */
246+
if ( ( rc = acpi_extract ( RTMA_SIGNATURE, hw_addr,
247+
acpimac_extract_rtxmac ) ) == 0 )
151248
return 0;
152249

153250
return -ENOENT;

src/tests/acpi_test.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,24 @@ ACPI_TABLES ( maca_tables, &maca_ssdt1, &maca_ssdt2 );
159159
ACPI_MAC ( maca, &maca_tables,
160160
DATA ( 0x52, 0x54, 0x00, 0x11, 0x22, 0x33 ) );
161161

162+
/** "RTMA" SSDT */
163+
ACPI_TABLE ( rtma_ssdt, "SSDT",
164+
DATA ( 0x53, 0x53, 0x44, 0x54, 0x44, 0x00, 0x00, 0x00, 0x02,
165+
0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167+
0x00, 0x49, 0x4e, 0x54, 0x4c, 0x04, 0x06, 0x21, 0x20,
168+
0x10, 0x1f, 0x5c, 0x5f, 0x53, 0x42, 0x5f, 0x14, 0x18,
169+
0x52, 0x54, 0x4d, 0x41, 0x08, 0x0d, 0x5f, 0x52, 0x54,
170+
0x58, 0x4d, 0x41, 0x43, 0x5f, 0x23, 0x52, 0x54, 0x30,
171+
0x30, 0x30, 0x31, 0x23, 0x00 ) );
172+
173+
/** "RTMA" test tables */
174+
ACPI_TABLES ( rtma_tables, &rtma_ssdt );
175+
176+
/** "RTMA" test */
177+
ACPI_MAC ( rtma, &rtma_tables,
178+
DATA ( 0x52, 0x54, 0x30, 0x30, 0x30, 0x31 ) );
179+
162180
/** Current ACPI test table set */
163181
static struct acpi_test_tables *acpi_test_tables;
164182

@@ -229,6 +247,7 @@ static void acpi_test_exec ( void ) {
229247
/* MAC extraction tests */
230248
acpi_mac_ok ( &amac );
231249
acpi_mac_ok ( &maca );
250+
acpi_mac_ok ( &rtma );
232251
}
233252

234253
/** ACPI self-test */

0 commit comments

Comments
 (0)