diff --git a/sys/include/uuid.h b/sys/include/uuid.h new file mode 100644 index 0000000000..aa6ef59029 --- /dev/null +++ b/sys/include/uuid.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2017 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup sys_uuid (Locally) Unique ID Generator + * @ingroup sys + * @brief Generate system wide unique IDs + * + * This module generates system wide, variable length unique IDs based on on the + * cpuid module. If the cpuid module is not present, the module falls back to a + * pre-defined, constant seed for creating unique ids. + * + * The main purpose of this module is to have a unified way for e.g. creating + * hardware addresses and similar. + * + * The IDs generated by this module are base created from a constant base part + * and a dynamic portion, which is XORed into the base ID. If the cpuid module + * is present, the base ID is created from the CPU's unique ID. If not, the + * base ID is created by simple 'memsetting' the base ID with the defined + * backup seed value. + * + * Once the base ID is generated, a UUID is generated by (i) XORing a counter + * value with the LSB of the base ID, or (ii) by XORing the least significant + * byes with a value given by the user. + * + * Example: Calling `uuid_base(&buf, 8)` will always yield an identical value, + * independent how often the function is called. But calling + * `uuid_base(&buf, 2)` afterwards will results in a different value, if the + * cpuid module is present, and in the same (but shorter) value if not. + * + * Example: Calling `uuid_get(&buf, 8)` four times in a row, will yield four + * different IDs, differing in their LSB. + * + * Example: Calling `uuid_custom(&buf, 8, 123)` will always yield the same + * value, but calling `uuid_custom(&buf, 8, 124)` will differ. + * + * @note This module generates unique IDs without any guarantees on their + * structure. These UUIDs are not compatible nor conform to the + * UUIDs as defined in RFC4122. + * + * @{ + * @file + * @brief Header of the unique ID generation module + * + * @author Hauke Petersen + */ + +#ifndef UUID_H_ +#define UUID_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Value used as based for the UUIDs in case the cpuid module is not + * present + */ +#ifndef UUID_BACKUP_SEED +#define UUID_BACKUP_SEED 0x23 +#endif + +/** + * @brief Get a unique ID + * + * The resulting ID is built from the base ID generated with uuid_base(), which + * isXORed with an 8-bit incrementing counter value into the most significant + * byte. + * + * @note The resulting UUID will repeat after 255 calls. + * + * @param[out] buf memory location to copy the UUID into. MUST be able to + * hold at least @p len bytes + * @param[in] len length of the UUID in bytes + */ +void uuid_get(void *buf, size_t len); + +/** + * @brief Get a custom unique ID based on a user given generator value + * + * The resulting ID is built from the base ID XORed with @p gen in the base + * ID's most significant bytes. + * + * @note Calling this function with identical values for @p gen and @p len + * will always result in identical UUIDs. + * + * @param[out] buf memory location to copy the UUID into. MUST be able to + * hold at least @p len bytes + * @param[in] len length of the UUID in bytes + * @param[in] gen custom UUID generator value + */ +void uuid_custom(void *buf, size_t len, int gen); + +/** + * @brief Get a UUID base value + * + * The uuid module creates the value dependent on the given @p len value using + * the cpuid module if present or a static seed value (@ref UUID_BACKUP_SEED) if + * not. + * + * @param[out] buf memory location to copy the UUID into. MUST be able to + * hold at least @p len bytes + * @param[in] len length of the UUID in bytes + */ +void uuid_base(void *buf, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* UUID_H_ */ +/** @} */ diff --git a/sys/uuid/Makefile b/sys/uuid/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/uuid/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/uuid/uuid.c b/sys/uuid/uuid.c new file mode 100644 index 0000000000..07e901a177 --- /dev/null +++ b/sys/uuid/uuid.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2017 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_uuid + * @{ + * + * @file + * @brief UUID module implementation + * + * @author Hauke Petersen + * + * @} + */ + +#include +#include + +#include "assert.h" +#include "periph/cpuid.h" + +#include "uuid.h" + +static uint8_t lastused = 1; + +void uuid_get(void *buf, size_t len) +{ + uuid_base(buf, len); + + ((uint8_t *)buf)[0] ^= lastused++; +} + +void uuid_custom(void *buf, size_t len, int gen) +{ + uuid_base(buf, len); + + for (int i = 0; i < sizeof(gen); i++) { + ((uint8_t *)buf)[i % len] ^= ((gen >> (i * 8)) & 0xff); + } +} + +void uuid_base(void *buf, size_t len) +{ + assert(buf && (len > 0)); + + memset(buf, UUID_BACKUP_SEED, len); + +#if CPUID_LEN + uint8_t *out = (uint8_t *)buf; + uint8_t cid[CPUID_LEN]; + + cpuid_get(cid); + for (size_t i = 0; i < CPUID_LEN; i++) { + out[i % len] ^= cid[i]; + } +#endif +}