1e11938eaSJason Hobbs /* 2e11938eaSJason Hobbs * Copyright 2011 Calxeda, Inc. 3e11938eaSJason Hobbs * 41a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 5e11938eaSJason Hobbs */ 6e11938eaSJason Hobbs 7e11938eaSJason Hobbs #include <linux/ctype.h> 8a96a0e61SPrzemyslaw Marczak #include <errno.h> 9a96a0e61SPrzemyslaw Marczak #include <common.h> 10d718ded0SPrzemyslaw Marczak #include <asm/io.h> 11d718ded0SPrzemyslaw Marczak #include <part_efi.h> 12d718ded0SPrzemyslaw Marczak #include <malloc.h> 13e11938eaSJason Hobbs 14e11938eaSJason Hobbs /* 15a96a0e61SPrzemyslaw Marczak * UUID - Universally Unique IDentifier - 128 bits unique number. 16a96a0e61SPrzemyslaw Marczak * There are 5 versions and one variant of UUID defined by RFC4122 17*4e4815feSPrzemyslaw Marczak * specification. A UUID contains a set of fields. The set varies 18*4e4815feSPrzemyslaw Marczak * depending on the version of the UUID, as shown below: 19*4e4815feSPrzemyslaw Marczak * - time, MAC address(v1), 20*4e4815feSPrzemyslaw Marczak * - user ID(v2), 21*4e4815feSPrzemyslaw Marczak * - MD5 of name or URL(v3), 22*4e4815feSPrzemyslaw Marczak * - random data(v4), 23*4e4815feSPrzemyslaw Marczak * - SHA-1 of name or URL(v5), 24*4e4815feSPrzemyslaw Marczak * 25*4e4815feSPrzemyslaw Marczak * Layout of UUID: 26*4e4815feSPrzemyslaw Marczak * timestamp - 60-bit: time_low, time_mid, time_hi_and_version 27*4e4815feSPrzemyslaw Marczak * version - 4 bit (bit 4 through 7 of the time_hi_and_version) 28*4e4815feSPrzemyslaw Marczak * clock seq - 14 bit: clock_seq_hi_and_reserved, clock_seq_low 29*4e4815feSPrzemyslaw Marczak * variant: - bit 6 and 7 of clock_seq_hi_and_reserved 30*4e4815feSPrzemyslaw Marczak * node - 48 bit 31*4e4815feSPrzemyslaw Marczak * 32*4e4815feSPrzemyslaw Marczak * source: https://www.ietf.org/rfc/rfc4122.txt 33e11938eaSJason Hobbs * 34a96a0e61SPrzemyslaw Marczak * UUID binary format (16 bytes): 35a96a0e61SPrzemyslaw Marczak * 36a96a0e61SPrzemyslaw Marczak * 4B-2B-2B-2B-6B (big endian - network byte order) 37a96a0e61SPrzemyslaw Marczak * 38a96a0e61SPrzemyslaw Marczak * UUID string is 36 length of characters (36 bytes): 39e11938eaSJason Hobbs * 40e11938eaSJason Hobbs * 0 9 14 19 24 41e11938eaSJason Hobbs * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 42a96a0e61SPrzemyslaw Marczak * be be be be be 43a96a0e61SPrzemyslaw Marczak * 44a96a0e61SPrzemyslaw Marczak * where x is a hexadecimal character. Fields are separated by '-'s. 45a96a0e61SPrzemyslaw Marczak * When converting to a binary UUID, le means the field should be converted 46a96a0e61SPrzemyslaw Marczak * to little endian and be means it should be converted to big endian. 47a96a0e61SPrzemyslaw Marczak * 48a96a0e61SPrzemyslaw Marczak * UUID is also used as GUID (Globally Unique Identifier) with the same binary 49a96a0e61SPrzemyslaw Marczak * format but it differs in string format like below. 50a96a0e61SPrzemyslaw Marczak * 51a96a0e61SPrzemyslaw Marczak * GUID: 52a96a0e61SPrzemyslaw Marczak * 0 9 14 19 24 53a96a0e61SPrzemyslaw Marczak * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 54e11938eaSJason Hobbs * le le le be be 55a96a0e61SPrzemyslaw Marczak * 56a96a0e61SPrzemyslaw Marczak * GUID is used e.g. in GPT (GUID Partition Table) as a partiions unique id. 57e11938eaSJason Hobbs */ 58e11938eaSJason Hobbs int uuid_str_valid(const char *uuid) 59e11938eaSJason Hobbs { 60e11938eaSJason Hobbs int i, valid; 61e11938eaSJason Hobbs 62e11938eaSJason Hobbs if (uuid == NULL) 63e11938eaSJason Hobbs return 0; 64e11938eaSJason Hobbs 65e11938eaSJason Hobbs for (i = 0, valid = 1; uuid[i] && valid; i++) { 66e11938eaSJason Hobbs switch (i) { 67e11938eaSJason Hobbs case 8: case 13: case 18: case 23: 68e11938eaSJason Hobbs valid = (uuid[i] == '-'); 69e11938eaSJason Hobbs break; 70e11938eaSJason Hobbs default: 71e11938eaSJason Hobbs valid = isxdigit(uuid[i]); 72e11938eaSJason Hobbs break; 73e11938eaSJason Hobbs } 74e11938eaSJason Hobbs } 75e11938eaSJason Hobbs 76d718ded0SPrzemyslaw Marczak if (i != UUID_STR_LEN || !valid) 77e11938eaSJason Hobbs return 0; 78e11938eaSJason Hobbs 79e11938eaSJason Hobbs return 1; 80e11938eaSJason Hobbs } 81e11938eaSJason Hobbs 82d718ded0SPrzemyslaw Marczak /* 83d718ded0SPrzemyslaw Marczak * uuid_str_to_bin() - convert string UUID or GUID to big endian binary data. 84d718ded0SPrzemyslaw Marczak * 85d718ded0SPrzemyslaw Marczak * @param uuid_str - pointer to UUID or GUID string [37B] 86d718ded0SPrzemyslaw Marczak * @param uuid_bin - pointer to allocated array for big endian output [16B] 87d718ded0SPrzemyslaw Marczak * @str_format - UUID string format: 0 - UUID; 1 - GUID 88d718ded0SPrzemyslaw Marczak */ 89d718ded0SPrzemyslaw Marczak int uuid_str_to_bin(char *uuid_str, unsigned char *uuid_bin, int str_format) 90e11938eaSJason Hobbs { 91e11938eaSJason Hobbs uint16_t tmp16; 92e11938eaSJason Hobbs uint32_t tmp32; 93e11938eaSJason Hobbs uint64_t tmp64; 94e11938eaSJason Hobbs 95d718ded0SPrzemyslaw Marczak if (!uuid_str_valid(uuid_str)) 96a96a0e61SPrzemyslaw Marczak return -EINVAL; 97a96a0e61SPrzemyslaw Marczak 98d718ded0SPrzemyslaw Marczak if (str_format == UUID_STR_FORMAT_STD) { 99d718ded0SPrzemyslaw Marczak tmp32 = cpu_to_be32(simple_strtoul(uuid_str, NULL, 16)); 100d718ded0SPrzemyslaw Marczak memcpy(uuid_bin, &tmp32, 4); 101e11938eaSJason Hobbs 102d718ded0SPrzemyslaw Marczak tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 9, NULL, 16)); 103d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 4, &tmp16, 2); 104e11938eaSJason Hobbs 105d718ded0SPrzemyslaw Marczak tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 14, NULL, 16)); 106d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 6, &tmp16, 2); 107d718ded0SPrzemyslaw Marczak } else { 108d718ded0SPrzemyslaw Marczak tmp32 = cpu_to_le32(simple_strtoul(uuid_str, NULL, 16)); 109d718ded0SPrzemyslaw Marczak memcpy(uuid_bin, &tmp32, 4); 110e11938eaSJason Hobbs 111d718ded0SPrzemyslaw Marczak tmp16 = cpu_to_le16(simple_strtoul(uuid_str + 9, NULL, 16)); 112d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 4, &tmp16, 2); 113e11938eaSJason Hobbs 114d718ded0SPrzemyslaw Marczak tmp16 = cpu_to_le16(simple_strtoul(uuid_str + 14, NULL, 16)); 115d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 6, &tmp16, 2); 116d718ded0SPrzemyslaw Marczak } 117e11938eaSJason Hobbs 118d718ded0SPrzemyslaw Marczak tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 19, NULL, 16)); 119d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 8, &tmp16, 2); 120d718ded0SPrzemyslaw Marczak 121d718ded0SPrzemyslaw Marczak tmp64 = cpu_to_be64(simple_strtoull(uuid_str + 24, NULL, 16)); 122d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 10, (char *)&tmp64 + 2, 6); 123a96a0e61SPrzemyslaw Marczak 124a96a0e61SPrzemyslaw Marczak return 0; 125a96a0e61SPrzemyslaw Marczak } 126a96a0e61SPrzemyslaw Marczak 127d718ded0SPrzemyslaw Marczak /* 128d718ded0SPrzemyslaw Marczak * uuid_bin_to_str() - convert big endian binary data to string UUID or GUID. 129d718ded0SPrzemyslaw Marczak * 130d718ded0SPrzemyslaw Marczak * @param uuid_bin - pointer to binary data of UUID (big endian) [16B] 131d718ded0SPrzemyslaw Marczak * @param uuid_str - pointer to allocated array for output string [37B] 132d718ded0SPrzemyslaw Marczak * @str_format - UUID string format: 0 - UUID; 1 - GUID 133d718ded0SPrzemyslaw Marczak */ 134d718ded0SPrzemyslaw Marczak void uuid_bin_to_str(unsigned char *uuid_bin, char *uuid_str, int str_format) 135a96a0e61SPrzemyslaw Marczak { 136d718ded0SPrzemyslaw Marczak const u8 uuid_char_order[UUID_BIN_LEN] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 137d718ded0SPrzemyslaw Marczak 9, 10, 11, 12, 13, 14, 15}; 138d718ded0SPrzemyslaw Marczak const u8 guid_char_order[UUID_BIN_LEN] = {3, 2, 1, 0, 5, 4, 7, 6, 8, 139d718ded0SPrzemyslaw Marczak 9, 10, 11, 12, 13, 14, 15}; 140d718ded0SPrzemyslaw Marczak const u8 *char_order; 141a96a0e61SPrzemyslaw Marczak int i; 142a96a0e61SPrzemyslaw Marczak 143d718ded0SPrzemyslaw Marczak /* 144d718ded0SPrzemyslaw Marczak * UUID and GUID bin data - always in big endian: 145d718ded0SPrzemyslaw Marczak * 4B-2B-2B-2B-6B 146d718ded0SPrzemyslaw Marczak * be be be be be 147d718ded0SPrzemyslaw Marczak */ 148d718ded0SPrzemyslaw Marczak if (str_format == UUID_STR_FORMAT_STD) 149d718ded0SPrzemyslaw Marczak char_order = uuid_char_order; 150d718ded0SPrzemyslaw Marczak else 151d718ded0SPrzemyslaw Marczak char_order = guid_char_order; 152d718ded0SPrzemyslaw Marczak 153a96a0e61SPrzemyslaw Marczak for (i = 0; i < 16; i++) { 154d718ded0SPrzemyslaw Marczak sprintf(uuid_str, "%02x", uuid_bin[char_order[i]]); 155d718ded0SPrzemyslaw Marczak uuid_str += 2; 156a96a0e61SPrzemyslaw Marczak switch (i) { 157a96a0e61SPrzemyslaw Marczak case 3: 158a96a0e61SPrzemyslaw Marczak case 5: 159a96a0e61SPrzemyslaw Marczak case 7: 160a96a0e61SPrzemyslaw Marczak case 9: 161d718ded0SPrzemyslaw Marczak *uuid_str++ = '-'; 162a96a0e61SPrzemyslaw Marczak break; 163a96a0e61SPrzemyslaw Marczak } 164a96a0e61SPrzemyslaw Marczak } 165e11938eaSJason Hobbs } 166*4e4815feSPrzemyslaw Marczak 167*4e4815feSPrzemyslaw Marczak /* 168*4e4815feSPrzemyslaw Marczak * gen_rand_uuid() - this function generates a random binary UUID version 4. 169*4e4815feSPrzemyslaw Marczak * In this version all fields beside 4 bits of version and 170*4e4815feSPrzemyslaw Marczak * 2 bits of variant are randomly generated. 171*4e4815feSPrzemyslaw Marczak * 172*4e4815feSPrzemyslaw Marczak * @param uuid_bin - pointer to allocated array [16B]. Output is in big endian. 173*4e4815feSPrzemyslaw Marczak */ 174*4e4815feSPrzemyslaw Marczak #ifdef CONFIG_RANDOM_UUID 175*4e4815feSPrzemyslaw Marczak void gen_rand_uuid(unsigned char *uuid_bin) 176*4e4815feSPrzemyslaw Marczak { 177*4e4815feSPrzemyslaw Marczak struct uuid uuid; 178*4e4815feSPrzemyslaw Marczak unsigned int *ptr = (unsigned int *)&uuid; 179*4e4815feSPrzemyslaw Marczak int i; 180*4e4815feSPrzemyslaw Marczak 181*4e4815feSPrzemyslaw Marczak /* Set all fields randomly */ 182*4e4815feSPrzemyslaw Marczak for (i = 0; i < sizeof(struct uuid) / sizeof(*ptr); i++) 183*4e4815feSPrzemyslaw Marczak *(ptr + i) = cpu_to_be32(rand()); 184*4e4815feSPrzemyslaw Marczak 185*4e4815feSPrzemyslaw Marczak clrsetbits_be16(&uuid.time_hi_and_version, 186*4e4815feSPrzemyslaw Marczak UUID_VERSION_MASK, 187*4e4815feSPrzemyslaw Marczak UUID_VERSION << UUID_VERSION_SHIFT); 188*4e4815feSPrzemyslaw Marczak 189*4e4815feSPrzemyslaw Marczak clrsetbits_8(&uuid.clock_seq_hi_and_reserved, 190*4e4815feSPrzemyslaw Marczak UUID_VARIANT_MASK, 191*4e4815feSPrzemyslaw Marczak UUID_VARIANT << UUID_VARIANT_SHIFT); 192*4e4815feSPrzemyslaw Marczak 193*4e4815feSPrzemyslaw Marczak memcpy(uuid_bin, &uuid, sizeof(struct uuid)); 194*4e4815feSPrzemyslaw Marczak } 195*4e4815feSPrzemyslaw Marczak 196*4e4815feSPrzemyslaw Marczak /* 197*4e4815feSPrzemyslaw Marczak * gen_rand_uuid_str() - this function generates UUID v4 (random) in two string 198*4e4815feSPrzemyslaw Marczak * formats UUID or GUID. 199*4e4815feSPrzemyslaw Marczak * 200*4e4815feSPrzemyslaw Marczak * @param uuid_str - pointer to allocated array [37B]. 201*4e4815feSPrzemyslaw Marczak * @param - uuid output type: UUID - 0, GUID - 1 202*4e4815feSPrzemyslaw Marczak */ 203*4e4815feSPrzemyslaw Marczak void gen_rand_uuid_str(char *uuid_str, int str_format) 204*4e4815feSPrzemyslaw Marczak { 205*4e4815feSPrzemyslaw Marczak unsigned char uuid_bin[UUID_BIN_LEN]; 206*4e4815feSPrzemyslaw Marczak 207*4e4815feSPrzemyslaw Marczak /* Generate UUID (big endian) */ 208*4e4815feSPrzemyslaw Marczak gen_rand_uuid(uuid_bin); 209*4e4815feSPrzemyslaw Marczak 210*4e4815feSPrzemyslaw Marczak /* Convert UUID bin to UUID or GUID formated STRING */ 211*4e4815feSPrzemyslaw Marczak uuid_bin_to_str(uuid_bin, uuid_str, str_format); 212*4e4815feSPrzemyslaw Marczak } 213*4e4815feSPrzemyslaw Marczak #endif 214