xref: /freebsd/sys/kern/kern_uuid.c (revision 52183d0145e4ff7e32191569a7325e7fe6ca9090)
152183d01SMarcel Moolenaar /*
252183d01SMarcel Moolenaar  * Copyright (c) 2002 Marcel Moolenaar
352183d01SMarcel Moolenaar  * All rights reserved.
452183d01SMarcel Moolenaar  *
552183d01SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
652183d01SMarcel Moolenaar  * modification, are permitted provided that the following conditions
752183d01SMarcel Moolenaar  * are met:
852183d01SMarcel Moolenaar  *
952183d01SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
1052183d01SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
1152183d01SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
1252183d01SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
1352183d01SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
1452183d01SMarcel Moolenaar  *
1552183d01SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1652183d01SMarcel Moolenaar  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1752183d01SMarcel Moolenaar  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1852183d01SMarcel Moolenaar  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1952183d01SMarcel Moolenaar  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2052183d01SMarcel Moolenaar  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2152183d01SMarcel Moolenaar  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2252183d01SMarcel Moolenaar  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2352183d01SMarcel Moolenaar  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2452183d01SMarcel Moolenaar  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2552183d01SMarcel Moolenaar  *
2652183d01SMarcel Moolenaar  * $FreeBSD$
2752183d01SMarcel Moolenaar  */
2852183d01SMarcel Moolenaar 
2952183d01SMarcel Moolenaar #include <sys/param.h>
3052183d01SMarcel Moolenaar #include <sys/endian.h>
3152183d01SMarcel Moolenaar #include <sys/kernel.h>
3252183d01SMarcel Moolenaar #include <sys/lock.h>
3352183d01SMarcel Moolenaar #include <sys/mutex.h>
3452183d01SMarcel Moolenaar #include <sys/sbuf.h>
3552183d01SMarcel Moolenaar #include <sys/socket.h>
3652183d01SMarcel Moolenaar #include <sys/sysproto.h>
3752183d01SMarcel Moolenaar #include <sys/uuid.h>
3852183d01SMarcel Moolenaar 
3952183d01SMarcel Moolenaar #include <net/if.h>
4052183d01SMarcel Moolenaar #include <net/if_dl.h>
4152183d01SMarcel Moolenaar #include <net/if_types.h>
4252183d01SMarcel Moolenaar 
4352183d01SMarcel Moolenaar /*
4452183d01SMarcel Moolenaar  * See also:
4552183d01SMarcel Moolenaar  *	http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
4652183d01SMarcel Moolenaar  *	http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
4752183d01SMarcel Moolenaar  *
4852183d01SMarcel Moolenaar  * Note that the generator state is itself an UUID, but the time and clock
4952183d01SMarcel Moolenaar  * sequence fields are written in the native byte order.
5052183d01SMarcel Moolenaar  */
5152183d01SMarcel Moolenaar 
5252183d01SMarcel Moolenaar CTASSERT(sizeof(struct uuid) == 16);
5352183d01SMarcel Moolenaar 
5452183d01SMarcel Moolenaar /* We use an alternative, more convenient representation in the generator. */
5552183d01SMarcel Moolenaar struct uuid_private {
5652183d01SMarcel Moolenaar 	union {
5752183d01SMarcel Moolenaar 		uint64_t	ll;		/* internal. */
5852183d01SMarcel Moolenaar 		struct {
5952183d01SMarcel Moolenaar 			uint32_t	low;
6052183d01SMarcel Moolenaar 			uint16_t	mid;
6152183d01SMarcel Moolenaar 			uint16_t	hi;
6252183d01SMarcel Moolenaar 		} x;
6352183d01SMarcel Moolenaar 	} time;
6452183d01SMarcel Moolenaar 	uint16_t	seq;			/* Big-endian. */
6552183d01SMarcel Moolenaar 	uint16_t	node[UUID_NODE_LEN>>1];
6652183d01SMarcel Moolenaar };
6752183d01SMarcel Moolenaar 
6852183d01SMarcel Moolenaar CTASSERT(sizeof(struct uuid_private) == 16);
6952183d01SMarcel Moolenaar 
7052183d01SMarcel Moolenaar static struct uuid_private uuid_last;
7152183d01SMarcel Moolenaar 
7252183d01SMarcel Moolenaar static struct mtx uuid_mutex;
7352183d01SMarcel Moolenaar MTX_SYSINIT(uuid_lock, &uuid_mutex, "UUID generator mutex lock", MTX_DEF);
7452183d01SMarcel Moolenaar 
7552183d01SMarcel Moolenaar /*
7652183d01SMarcel Moolenaar  * Return the first MAC address we encounter or, if none was found,
7752183d01SMarcel Moolenaar  * construct a sufficiently random multicast address. We don't try
7852183d01SMarcel Moolenaar  * to return the same MAC address as previously returned. We always
7952183d01SMarcel Moolenaar  * generate a new multicast address if no MAC address exists in the
8052183d01SMarcel Moolenaar  * system.
8152183d01SMarcel Moolenaar  * It would be nice to know if 'ifnet' or any of its sub-structures
8252183d01SMarcel Moolenaar  * has been changed in any way. If not, we could simply skip the
8352183d01SMarcel Moolenaar  * scan and safely return the MAC address we returned before.
8452183d01SMarcel Moolenaar  */
8552183d01SMarcel Moolenaar static void
8652183d01SMarcel Moolenaar uuid_node(uint16_t *node)
8752183d01SMarcel Moolenaar {
8852183d01SMarcel Moolenaar 	struct ifnet *ifp;
8952183d01SMarcel Moolenaar 	struct ifaddr *ifa;
9052183d01SMarcel Moolenaar 	struct sockaddr_dl *sdl;
9152183d01SMarcel Moolenaar 	int i;
9252183d01SMarcel Moolenaar 
9352183d01SMarcel Moolenaar 	/* XXX: lock ifnet. */
9452183d01SMarcel Moolenaar 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
9552183d01SMarcel Moolenaar 		/* Walk the address list */
9652183d01SMarcel Moolenaar 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
9752183d01SMarcel Moolenaar 			sdl = (struct sockaddr_dl*)ifa->ifa_addr;
9852183d01SMarcel Moolenaar 			if (sdl != NULL && sdl->sdl_family == AF_LINK &&
9952183d01SMarcel Moolenaar 			    sdl->sdl_type == IFT_ETHER) {
10052183d01SMarcel Moolenaar 				/* Got a MAC address. */
10152183d01SMarcel Moolenaar 				bcopy(LLADDR(sdl), node, UUID_NODE_LEN);
10252183d01SMarcel Moolenaar 				/* XXX: unlock ifnet. */
10352183d01SMarcel Moolenaar 				return;
10452183d01SMarcel Moolenaar 			}
10552183d01SMarcel Moolenaar 		}
10652183d01SMarcel Moolenaar 	}
10752183d01SMarcel Moolenaar 	/* XXX: unlock ifnet. */
10852183d01SMarcel Moolenaar 
10952183d01SMarcel Moolenaar 	for (i = 0; i < (UUID_NODE_LEN>>1); i++)
11052183d01SMarcel Moolenaar 		node[i] = (uint16_t)arc4random();
11152183d01SMarcel Moolenaar 	*((uint8_t*)node) |= 0x80;
11252183d01SMarcel Moolenaar }
11352183d01SMarcel Moolenaar 
11452183d01SMarcel Moolenaar /*
11552183d01SMarcel Moolenaar  * Get the current time as a 60 bit count of 100-nanosecond intervals
11652183d01SMarcel Moolenaar  * since 00:00:00.00, October 15,1582. We apply a magic offset to convert
11752183d01SMarcel Moolenaar  * the Unix time since 00:00:00.00, Januari 1, 1970 to the date of the
11852183d01SMarcel Moolenaar  * Gregorian reform to the Christian calendar.
11952183d01SMarcel Moolenaar  */
12052183d01SMarcel Moolenaar static uint64_t
12152183d01SMarcel Moolenaar uuid_time(void)
12252183d01SMarcel Moolenaar {
12352183d01SMarcel Moolenaar 	struct bintime bt;
12452183d01SMarcel Moolenaar 	uint64_t time = 0x01B21DD213814000LL;
12552183d01SMarcel Moolenaar 
12652183d01SMarcel Moolenaar 	bintime(&bt);
12752183d01SMarcel Moolenaar 	time += (uint64_t)bt.sec * 10000000LL;
12852183d01SMarcel Moolenaar 	time += (10000000LL * (uint32_t)(bt.frac >> 32)) >> 32;
12952183d01SMarcel Moolenaar 	return (time & ((1LL << 60) - 1LL));
13052183d01SMarcel Moolenaar }
13152183d01SMarcel Moolenaar 
13252183d01SMarcel Moolenaar #ifndef _SYS_SYSPROTO_H_
13352183d01SMarcel Moolenaar struct uuidgen_args {
13452183d01SMarcel Moolenaar 	struct uuid *store;
13552183d01SMarcel Moolenaar 	int	count;
13652183d01SMarcel Moolenaar };
13752183d01SMarcel Moolenaar #endif
13852183d01SMarcel Moolenaar 
13952183d01SMarcel Moolenaar int uuidgen(struct thread *td, struct uuidgen_args *uap)
14052183d01SMarcel Moolenaar {
14152183d01SMarcel Moolenaar 	struct uuid_private uuid;
14252183d01SMarcel Moolenaar 	uint64_t time;
14352183d01SMarcel Moolenaar 	int error;
14452183d01SMarcel Moolenaar 
14552183d01SMarcel Moolenaar 	/*
14652183d01SMarcel Moolenaar 	 * Limit the number of UUIDs that can be created at the same time
14752183d01SMarcel Moolenaar 	 * to some arbitrary number. This isn't really necessary, but I
14852183d01SMarcel Moolenaar 	 * like to have some sort of upper-bound that's less than 2G :-)
14952183d01SMarcel Moolenaar 	 * XXX needs to be tunable.
15052183d01SMarcel Moolenaar 	 */
15152183d01SMarcel Moolenaar 	if (uap->count < 1 || uap->count > 2048)
15252183d01SMarcel Moolenaar 		return (EINVAL);
15352183d01SMarcel Moolenaar 
15452183d01SMarcel Moolenaar 	/* XXX: pre-validate accessibility to the whole of the UUID store? */
15552183d01SMarcel Moolenaar 
15652183d01SMarcel Moolenaar 	mtx_lock(&uuid_mutex);
15752183d01SMarcel Moolenaar 
15852183d01SMarcel Moolenaar 	uuid_node(uuid.node);
15952183d01SMarcel Moolenaar 	time = uuid_time();
16052183d01SMarcel Moolenaar 
16152183d01SMarcel Moolenaar 	if (uuid_last.time.ll == 0LL || uuid_last.node[0] != uuid.node[0] ||
16252183d01SMarcel Moolenaar 	    uuid_last.node[1] != uuid.node[1] ||
16352183d01SMarcel Moolenaar 	    uuid_last.node[2] != uuid.node[2])
16452183d01SMarcel Moolenaar 		uuid.seq = (uint16_t)arc4random() & 0x3fff;
16552183d01SMarcel Moolenaar 	else if (uuid_last.time.ll >= time)
16652183d01SMarcel Moolenaar 		uuid.seq = (uuid_last.seq + 1) & 0x3fff;
16752183d01SMarcel Moolenaar 	else
16852183d01SMarcel Moolenaar 		uuid.seq = uuid_last.seq;
16952183d01SMarcel Moolenaar 
17052183d01SMarcel Moolenaar 	uuid_last = uuid;
17152183d01SMarcel Moolenaar 	uuid_last.time.ll = (time + uap->count - 1) & ((1LL << 60) - 1LL);
17252183d01SMarcel Moolenaar 
17352183d01SMarcel Moolenaar 	mtx_unlock(&uuid_mutex);
17452183d01SMarcel Moolenaar 
17552183d01SMarcel Moolenaar 	/* Set sequence and variant and deal with byte order. */
17652183d01SMarcel Moolenaar 	uuid.seq = htobe16(uuid.seq | 0x8000);
17752183d01SMarcel Moolenaar 
17852183d01SMarcel Moolenaar 	/* XXX: this should copyout larger chunks at a time. */
17952183d01SMarcel Moolenaar 	do {
18052183d01SMarcel Moolenaar 		/* Set time and version (=1) and deal with byte order. */
18152183d01SMarcel Moolenaar 		uuid.time.x.low = (uint32_t)time;
18252183d01SMarcel Moolenaar 		uuid.time.x.mid = (uint16_t)(time >> 32);
18352183d01SMarcel Moolenaar 		uuid.time.x.hi = ((uint16_t)(time >> 48) & 0xfff) | (1 << 12);
18452183d01SMarcel Moolenaar 		error = copyout(&uuid, uap->store, sizeof(uuid));
18552183d01SMarcel Moolenaar 		uap->store++;
18652183d01SMarcel Moolenaar 		uap->count--;
18752183d01SMarcel Moolenaar 		time++;
18852183d01SMarcel Moolenaar 	} while (uap->count > 0 && !error);
18952183d01SMarcel Moolenaar 
19052183d01SMarcel Moolenaar 	return (error);
19152183d01SMarcel Moolenaar }
19252183d01SMarcel Moolenaar 
19352183d01SMarcel Moolenaar int
19452183d01SMarcel Moolenaar snprintf_uuid(char *buf, size_t sz, struct uuid *uuid)
19552183d01SMarcel Moolenaar {
19652183d01SMarcel Moolenaar 	struct uuid_private *id;
19752183d01SMarcel Moolenaar 	int cnt;
19852183d01SMarcel Moolenaar 
19952183d01SMarcel Moolenaar 	id = (struct uuid_private *)uuid;
20052183d01SMarcel Moolenaar 	cnt = snprintf(buf, sz, "%08x-%04x-%04x-%04x-%04x%04x%04x",
20152183d01SMarcel Moolenaar 	    id->time.x.low, id->time.x.mid, id->time.x.hi, be16toh(id->seq),
20252183d01SMarcel Moolenaar 	    be16toh(id->node[0]), be16toh(id->node[1]), be16toh(id->node[2]));
20352183d01SMarcel Moolenaar 	return (cnt);
20452183d01SMarcel Moolenaar }
20552183d01SMarcel Moolenaar 
20652183d01SMarcel Moolenaar int
20752183d01SMarcel Moolenaar printf_uuid(struct uuid *uuid)
20852183d01SMarcel Moolenaar {
20952183d01SMarcel Moolenaar 	char buf[38];
21052183d01SMarcel Moolenaar 
21152183d01SMarcel Moolenaar 	snprintf_uuid(buf, sizeof(buf), uuid);
21252183d01SMarcel Moolenaar 	return (printf("%s", buf));
21352183d01SMarcel Moolenaar }
21452183d01SMarcel Moolenaar 
21552183d01SMarcel Moolenaar int
21652183d01SMarcel Moolenaar sbuf_printf_uuid(struct sbuf *sb, struct uuid *uuid)
21752183d01SMarcel Moolenaar {
21852183d01SMarcel Moolenaar 	char buf[38];
21952183d01SMarcel Moolenaar 
22052183d01SMarcel Moolenaar 	snprintf_uuid(buf, sizeof(buf), uuid);
22152183d01SMarcel Moolenaar 	return (sbuf_printf(sb, "%s", buf));
22252183d01SMarcel Moolenaar }
223