blob: 061997453aff429610df041ee39284302e14d474 [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* Copyright 2014 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <boot/coreboot_tables.h>
#include <console/console.h>
#include <string.h>
#include <vendorcode/google/chromeos/cros_vpd.h>
/*
* Decode string representation of the MAC address (a string of 12 hex
* symbols) into binary. 'key_name' is the name of the VPD field, it's used if
* it is necessary to report an input data format problem.
*/
static void decode_mac(struct mac_address *mac,
const char *mac_addr_str,
const char *key_name)
{
int i;
for (i = 0; i < sizeof(mac->mac_addr); i++) {
int j;
uint8_t n = 0;
for (j = 0; j < 2; j++) {
char c = mac_addr_str[i * 2 + j];
if (isxdigit(c)) {
if (isdigit(c))
c -= '0';
else
c = tolower(c) - 'a' + 10;
} else {
printk(BIOS_ERR, "%s: non hexadecimal symbol "
"%#2.2x in the VPD field %s:%s\n",
__func__, (uint8_t)c, key_name,
mac_addr_str);
c = 0;
}
n <<= 4;
n |= c;
}
mac->mac_addr[i] = n;
}
}
void lb_table_add_macs_from_vpd(struct lb_header *header)
{
/*
* Mac addresses in the VPD can be stored in two groups, for ethernet
* and WiFi, with keys 'ethernet_macX and wifi_macX.
*/
const char *mac_addr_key_bases[] = {"ethernet_mac0", "wifi_mac0"};
char mac_addr_key[20]; /* large enough for either key */
char mac_addr_str[13]; /* 12 symbols and the trailing zero. */
int i, count;
struct lb_macs *macs = NULL;
/* Make sure the copy is always zero terminated. */
mac_addr_key[sizeof(mac_addr_key) - 1] = '\0';
count = 0;
for (i = 0; i < ARRAY_SIZE(mac_addr_key_bases); i++) {
int index_of_index;
strncpy(mac_addr_key, mac_addr_key_bases[i],
sizeof(mac_addr_key) - 1);
index_of_index = strlen(mac_addr_key) - 1;
do {
/*
* If there are no more MAC addresses of this template
* in the VPD - move on.
*/
if (!cros_vpd_gets(mac_addr_key, mac_addr_str,
sizeof(mac_addr_str)))
break;
if (!macs) {
macs = (struct lb_macs *)lb_new_record(header);
macs->tag = LB_TAG_MAC_ADDRS;
}
decode_mac(macs->mac_addrs + count,
mac_addr_str,
mac_addr_key);
count++;
mac_addr_key[index_of_index]++;
} while (count < 10);
}
if (!count)
return; /* No MAC addresses in the VPD. */
macs->count = count;
macs->size = sizeof(*macs) + count * sizeof(struct mac_address);
}