162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Unified UUID/GUID definition
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2009, 2016 Intel Corp.
662306a36Sopenharmony_ci *	Huang Ying <ying.huang@intel.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/ctype.h>
1162306a36Sopenharmony_ci#include <linux/errno.h>
1262306a36Sopenharmony_ci#include <linux/export.h>
1362306a36Sopenharmony_ci#include <linux/uuid.h>
1462306a36Sopenharmony_ci#include <linux/random.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciconst guid_t guid_null;
1762306a36Sopenharmony_ciEXPORT_SYMBOL(guid_null);
1862306a36Sopenharmony_ciconst uuid_t uuid_null;
1962306a36Sopenharmony_ciEXPORT_SYMBOL(uuid_null);
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciconst u8 guid_index[16] = {3,2,1,0,5,4,7,6,8,9,10,11,12,13,14,15};
2262306a36Sopenharmony_ciconst u8 uuid_index[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/**
2562306a36Sopenharmony_ci * generate_random_uuid - generate a random UUID
2662306a36Sopenharmony_ci * @uuid: where to put the generated UUID
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * Random UUID interface
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * Used to create a Boot ID or a filesystem UUID/GUID, but can be
3162306a36Sopenharmony_ci * useful for other kernel drivers.
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_civoid generate_random_uuid(unsigned char uuid[16])
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	get_random_bytes(uuid, 16);
3662306a36Sopenharmony_ci	/* Set UUID version to 4 --- truly random generation */
3762306a36Sopenharmony_ci	uuid[6] = (uuid[6] & 0x0F) | 0x40;
3862306a36Sopenharmony_ci	/* Set the UUID variant to DCE */
3962306a36Sopenharmony_ci	uuid[8] = (uuid[8] & 0x3F) | 0x80;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ciEXPORT_SYMBOL(generate_random_uuid);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_civoid generate_random_guid(unsigned char guid[16])
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	get_random_bytes(guid, 16);
4662306a36Sopenharmony_ci	/* Set GUID version to 4 --- truly random generation */
4762306a36Sopenharmony_ci	guid[7] = (guid[7] & 0x0F) | 0x40;
4862306a36Sopenharmony_ci	/* Set the GUID variant to DCE */
4962306a36Sopenharmony_ci	guid[8] = (guid[8] & 0x3F) | 0x80;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ciEXPORT_SYMBOL(generate_random_guid);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic void __uuid_gen_common(__u8 b[16])
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	get_random_bytes(b, 16);
5662306a36Sopenharmony_ci	/* reversion 0b10 */
5762306a36Sopenharmony_ci	b[8] = (b[8] & 0x3F) | 0x80;
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_civoid guid_gen(guid_t *lu)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	__uuid_gen_common(lu->b);
6362306a36Sopenharmony_ci	/* version 4 : random generation */
6462306a36Sopenharmony_ci	lu->b[7] = (lu->b[7] & 0x0F) | 0x40;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(guid_gen);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_civoid uuid_gen(uuid_t *bu)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	__uuid_gen_common(bu->b);
7162306a36Sopenharmony_ci	/* version 4 : random generation */
7262306a36Sopenharmony_ci	bu->b[6] = (bu->b[6] & 0x0F) | 0x40;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uuid_gen);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/**
7762306a36Sopenharmony_ci * uuid_is_valid - checks if a UUID string is valid
7862306a36Sopenharmony_ci * @uuid:	UUID string to check
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * Description:
8162306a36Sopenharmony_ci * It checks if the UUID string is following the format:
8262306a36Sopenharmony_ci *	xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * where x is a hex digit.
8562306a36Sopenharmony_ci *
8662306a36Sopenharmony_ci * Return: true if input is valid UUID string.
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_cibool uuid_is_valid(const char *uuid)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	unsigned int i;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	for (i = 0; i < UUID_STRING_LEN; i++) {
9362306a36Sopenharmony_ci		if (i == 8 || i == 13 || i == 18 || i == 23) {
9462306a36Sopenharmony_ci			if (uuid[i] != '-')
9562306a36Sopenharmony_ci				return false;
9662306a36Sopenharmony_ci		} else if (!isxdigit(uuid[i])) {
9762306a36Sopenharmony_ci			return false;
9862306a36Sopenharmony_ci		}
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	return true;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ciEXPORT_SYMBOL(uuid_is_valid);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic int __uuid_parse(const char *uuid, __u8 b[16], const u8 ei[16])
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	static const u8 si[16] = {0,2,4,6,9,11,14,16,19,21,24,26,28,30,32,34};
10862306a36Sopenharmony_ci	unsigned int i;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (!uuid_is_valid(uuid))
11162306a36Sopenharmony_ci		return -EINVAL;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	for (i = 0; i < 16; i++) {
11462306a36Sopenharmony_ci		int hi = hex_to_bin(uuid[si[i] + 0]);
11562306a36Sopenharmony_ci		int lo = hex_to_bin(uuid[si[i] + 1]);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		b[ei[i]] = (hi << 4) | lo;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return 0;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ciint guid_parse(const char *uuid, guid_t *u)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	return __uuid_parse(uuid, u->b, guid_index);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ciEXPORT_SYMBOL(guid_parse);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ciint uuid_parse(const char *uuid, uuid_t *u)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	return __uuid_parse(uuid, u->b, uuid_index);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ciEXPORT_SYMBOL(uuid_parse);
134