text: /*
   * 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);
  }
  