blob: 17f9c25741e922cfdb37392dd0e6bf1d26f03794 [file] [log] [blame]
/* Copyright 2010, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* binary_blob.c: helper functions for handling binary blobs
*/
#include <stdlib.h>
#include <uuid/uuid.h>
#include "mosys/alloc.h"
#include "mosys/log.h"
#include "mosys/output.h" /* FIXME: for print_buffer() */
#include "lib/string.h"
#include "lib/vpd_tables.h"
#include "lib/vpd_binary_blob.h"
enum google_blob_v2_0_field_type {
GOOGLE_BLOB_V2_0_TERMINATOR = 0x00,
GOOGLE_BLOB_V2_0_STRING = 0x01,
} type;
int print_agz_blob_v3(uint8_t *data, uint32_t size, struct kv_pair *kv)
{
struct agz_blob_0_3 *agz_blob;
char s[37];
char *s2;
if (!data)
return -1;
agz_blob = (struct agz_blob_0_3 *)data;
if (size != sizeof(*agz_blob)) {
lprintf(LOG_DEBUG, "AGZ binary blob expected size: %lx, "
"got: %x\n", sizeof(*agz_blob), size);
return -1;
}
kv_pair_add(kv, "blob_type", "agz_blob");
snprintf(s, sizeof(agz_blob->product_name) + 1, "%s", agz_blob->product_name);
kv_pair_add(kv, "product_name", s);
snprintf(s, sizeof(agz_blob->product_manufacturer) + 1,
"%s", agz_blob->product_manufacturer);
kv_pair_add(kv, "product_manufacturer", s);
uuid_unparse(agz_blob->uuid, s);
kv_pair_add(kv, "product_uuid", s);
s2 = buf2str(agz_blob->motherboard_serial_number,
sizeof(agz_blob->motherboard_serial_number));
kv_pair_add(kv, "motherboard_serial_number", s2);
free(s2);
s2 = buf2nicid(agz_blob->esn_3g, NIC_ID_IMEI);
kv_pair_add(kv, "3g_esn", s2);
free(s2);
s2 = buf2nicid(agz_blob->wlan_mac_id, NIC_ID_IEEE802);
kv_pair_add(kv, "wlan_macid", s2);
free(s2);
snprintf(s, sizeof(agz_blob->country_code) + 1,
"%s", agz_blob->country_code);
kv_pair_add(kv, "country_code", s);
snprintf(s, sizeof( agz_blob->product_serial_number) + 1,
"%s", agz_blob->product_serial_number);
kv_pair_fmt(kv, "product_serial_number", s);
return 0;
}
int print_agz_blob_v5(uint8_t *data, uint32_t size, struct kv_pair *kv)
{
struct agz_blob_0_5 *agz_blob;
char s[37];
char *s2;
if (!data)
return -1;
agz_blob = (struct agz_blob_0_5 *)data;
if (size != sizeof(*agz_blob)) {
lprintf(LOG_DEBUG, "AGZ binary blob expected size: %lu, "
"got: %x\n", sizeof(*agz_blob), size);
return -1;
}
kv_pair_add(kv, "blob_type", "agz_blob");
snprintf(s, sizeof(agz_blob->product_name) + 1, "%s", agz_blob->product_name);
kv_pair_add(kv, "product_name", s);
snprintf(s, sizeof(agz_blob->product_manufacturer) + 1,
"%s", agz_blob->product_manufacturer);
kv_pair_add(kv, "product_manufacturer", s);
uuid_unparse(agz_blob->uuid, s);
kv_pair_add(kv, "product_uuid", s);
snprintf(s, sizeof(agz_blob->motherboard_serial_number) + 1,
"%s", agz_blob->motherboard_serial_number);
kv_pair_add(kv, "motherboard_serial_number", s);
snprintf(s, sizeof(agz_blob->esn_3g) + 1, "%s", agz_blob->esn_3g);
kv_pair_add(kv, "3g_esn", s);
s2 = buf2nicid(agz_blob->wlan_mac_id, NIC_ID_IEEE802);
kv_pair_add(kv, "wlan_macid", s2);
free(s2);
snprintf(s, sizeof(agz_blob->country_code) + 1,
"%s", agz_blob->country_code);
kv_pair_add(kv, "country_code", s);
snprintf(s, sizeof( agz_blob->product_serial_number) + 1,
"%s", agz_blob->product_serial_number);
kv_pair_fmt(kv, "product_serial_number", s);
return 0;
}
int print_google_blob_v1_1(uint8_t *data, uint32_t size, struct kv_pair *kv)
{
struct google_blob_1_1 *google_blob;
char s[37];
char *s2;
if (!data)
return -1;
google_blob = (struct google_blob_1_1 *)data;
if (size != sizeof(*google_blob)) {
lprintf(LOG_DEBUG, "Google binary blob expected size: %lu, "
"got: %x\n", sizeof(*google_blob), size);
return -1;
}
kv_pair_add(kv, "blob_type", "google_blob");
snprintf(s, sizeof(google_blob->product_serial_number) + 1,
"%s", google_blob->product_serial_number);
kv_pair_add(kv, "product_serial_number", s);
snprintf(s, sizeof(google_blob->product_sku) + 1,
"%s", google_blob->product_sku);
kv_pair_add(kv, "product_sku", s);
uuid_unparse(google_blob->uuid, s);
kv_pair_add(kv, "product_uuid", s);
snprintf(s, sizeof(google_blob->motherboard_serial_number) + 1,
"%s", google_blob->motherboard_serial_number);
kv_pair_add(kv, "motherboard_serial_number", s);
snprintf(s, sizeof(google_blob->imei_3g) + 1, "%s", google_blob->imei_3g);
kv_pair_add(kv, "imei_esn", s);
snprintf(s, sizeof(google_blob->ssd_serial_number) + 1,
"%s", google_blob->ssd_serial_number);
kv_pair_fmt(kv, "ssd_serial_number", s);
snprintf(s, sizeof(google_blob->memory_serial_number) + 1,
"%s", google_blob->memory_serial_number);
kv_pair_fmt(kv, "memory_serial_number", s);
s2 = buf2nicid(google_blob->wlan_mac_id, NIC_ID_IEEE802);
kv_pair_add(kv, "wlan_macid", s2);
free(s2);
return 0;
}
/* sets *p to point at the beginning of the string and returns string length */
static int get_string(uint8_t **p)
{
int len = 0, shiftwidth = 0;
do {
/* if highest bit is set, then continue to interpret bits
6:0 of the next byte as the next 7 significant bits */
#if defined CONFIG_BIG_ENDIAN && CONFIG_BIG_ENDIAN == 1
len = len + ((**p & ~0x80) << shiftwidth);
#elif defined CONFIG_LITTLE_ENDIAN && CONFIG_LITTLE_ENDIAN == 1
len = (len << shiftwidth) | (**p & ~0x80);
#endif
(*p)++;
shiftwidth += 7;
} while (**p & 0x80);
return len;
}
struct entry {
enum google_blob_v2_0_field_type type;
int key_length;
uint8_t *key;
int value_length;
uint8_t *value;
};
static int get_entry(const uint8_t *src, struct entry *entry)
{
uint8_t *p = (uint8_t *)src;
if (*p == GOOGLE_BLOB_V2_0_TERMINATOR)
return 1;
if (*p != GOOGLE_BLOB_V2_0_STRING)
return -1;
entry->type = *p;
p++;
entry->key_length = get_string(&p);
entry->key = p;
p += entry->key_length;
entry->value_length = get_string(&p);
entry->value = p;
p += entry->value_length;
return p - src;
}
/*
* get_google_blob_v2_0 - Copy the google blob from "data" to "result"
*
* @data: pointer to beginning of blob data
* @result: buffer to store the google blob in
*
* This function will allocate memory which the caller must free.
*
* returns the size of the result to indicate success
* returns <0 to indicate error
*/
int get_google_blob_v2_0(uint8_t **dst, const uint8_t *src, int max_len)
{
int len = 0, entry_len;
struct entry entry;
while ((entry_len = get_entry(src + len, &entry)) > 1) {
len += entry_len;
if (len > max_len)
return -1;
}
len++; /* for terminator */
*dst= mosys_malloc(len);
memcpy((void *)*dst, src, len);
return len;
}
/*
* print_google_blob_v2_0 - print google blob version 2.0
*
* @data: pointer to the beginning of blob data
* @size: this argument is ignored -- it exists only to match function
* signatures for this type of callback.
* @kv_pair: key=value pair
*
* The version 2.0 Google blob is different; it does not use a fixed format.
* Instead, it is to be interpreted from a key-value format. The format is:
* |--------------------------------------------------------------|
* | type | key length | key string | value length | value string |
* |--------------------------------------------------------------|
* 1 byte 1 byte varies 1 byte varies
*
* Note: Strings are not NULL-terminated
*
*/
int print_google_blob_v2_0(uint8_t *data, uint32_t size, struct kv_pair *kv)
{
struct entry entry;
int len = 0, entry_len;
kv_pair_add(kv, "blob_type", "google_blob");
while ((entry_len = get_entry(data + len, &entry)) > 1) {
char *key, *value;
key = mosys_malloc(entry.key_length + 1);
snprintf(key, entry.key_length + 1, "%s", entry.key);
value = mosys_malloc(entry.value_length + 1);
snprintf(value, entry.value_length + 1, "%s", entry.value);
kv_pair_fmt(kv, key, value);
free(key);
free(value);
len += entry_len;
}
return 0;
}