kern_uuid.c revision 116182
154359Sroberto/* 254359Sroberto * Copyright (c) 2002 Marcel Moolenaar 354359Sroberto * All rights reserved. 454359Sroberto * 554359Sroberto * Redistribution and use in source and binary forms, with or without 654359Sroberto * modification, are permitted provided that the following conditions 7182007Sroberto * are met: 854359Sroberto * 9182007Sroberto * 1. Redistributions of source code must retain the above copyright 1054359Sroberto * notice, this list of conditions and the following disclaimer. 1154359Sroberto * 2. Redistributions in binary form must reproduce the above copyright 1254359Sroberto * notice, this list of conditions and the following disclaimer in the 1354359Sroberto * documentation and/or other materials provided with the distribution. 1454359Sroberto * 1554359Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1654359Sroberto * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17182007Sroberto * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18182007Sroberto * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19182007Sroberto * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20182007Sroberto * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21182007Sroberto * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22182007Sroberto * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23182007Sroberto * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24182007Sroberto * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25182007Sroberto */ 26182007Sroberto 27182007Sroberto#include <sys/cdefs.h> 28182007Sroberto__FBSDID("$FreeBSD: head/sys/kern/kern_uuid.c 116182 2003-06-11 00:56:59Z obrien $"); 29182007Sroberto 30182007Sroberto#include <sys/param.h> 31182007Sroberto#include <sys/endian.h> 32182007Sroberto#include <sys/kernel.h> 33182007Sroberto#include <sys/lock.h> 34182007Sroberto#include <sys/mutex.h> 35182007Sroberto#include <sys/sbuf.h> 36182007Sroberto#include <sys/socket.h> 37182007Sroberto#include <sys/sysproto.h> 38182007Sroberto#include <sys/systm.h> 39182007Sroberto#include <sys/uuid.h> 40182007Sroberto 41182007Sroberto#include <net/if.h> 42182007Sroberto#include <net/if_dl.h> 43182007Sroberto#include <net/if_types.h> 4454359Sroberto 4554359Sroberto/* 4654359Sroberto * See also: 4754359Sroberto * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt 4854359Sroberto * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm 4954359Sroberto * 5054359Sroberto * Note that the generator state is itself an UUID, but the time and clock 5154359Sroberto * sequence fields are written in the native byte order. 5254359Sroberto */ 5354359Sroberto 5454359SrobertoCTASSERT(sizeof(struct uuid) == 16); 5554359Sroberto 5654359Sroberto/* We use an alternative, more convenient representation in the generator. */ 5754359Srobertostruct uuid_private { 5854359Sroberto union { 5954359Sroberto uint64_t ll; /* internal. */ 6054359Sroberto struct { 6154359Sroberto uint32_t low; 6254359Sroberto uint16_t mid; 6354359Sroberto uint16_t hi; 6454359Sroberto } x; 6554359Sroberto } time; 6654359Sroberto uint16_t seq; /* Big-endian. */ 6754359Sroberto uint16_t node[UUID_NODE_LEN>>1]; 6854359Sroberto}; 6954359Sroberto 7054359SrobertoCTASSERT(sizeof(struct uuid_private) == 16); 7154359Sroberto 7254359Srobertostatic struct uuid_private uuid_last; 7354359Sroberto 7454359Srobertostatic struct mtx uuid_mutex; 7554359SrobertoMTX_SYSINIT(uuid_lock, &uuid_mutex, "UUID generator mutex lock", MTX_DEF); 7654359Sroberto 7754359Sroberto/* 7854359Sroberto * Return the first MAC address we encounter or, if none was found, 7954359Sroberto * construct a sufficiently random multicast address. We don't try 8054359Sroberto * to return the same MAC address as previously returned. We always 8154359Sroberto * generate a new multicast address if no MAC address exists in the 8254359Sroberto * system. 8354359Sroberto * It would be nice to know if 'ifnet' or any of its sub-structures 8454359Sroberto * has been changed in any way. If not, we could simply skip the 8554359Sroberto * scan and safely return the MAC address we returned before. 8654359Sroberto */ 8754359Srobertostatic void 8854359Srobertouuid_node(uint16_t *node) 8954359Sroberto{ 9054359Sroberto struct ifnet *ifp; 9154359Sroberto struct ifaddr *ifa; 9254359Sroberto struct sockaddr_dl *sdl; 9354359Sroberto int i; 9454359Sroberto 9554359Sroberto IFNET_RLOCK(); 9654359Sroberto TAILQ_FOREACH(ifp, &ifnet, if_link) { 9754359Sroberto /* Walk the address list */ 9854359Sroberto TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 9954359Sroberto sdl = (struct sockaddr_dl*)ifa->ifa_addr; 10054359Sroberto if (sdl != NULL && sdl->sdl_family == AF_LINK && 10154359Sroberto sdl->sdl_type == IFT_ETHER) { 10254359Sroberto /* Got a MAC address. */ 10354359Sroberto bcopy(LLADDR(sdl), node, UUID_NODE_LEN); 10454359Sroberto IFNET_RUNLOCK(); 10554359Sroberto return; 10654359Sroberto } 10754359Sroberto } 10854359Sroberto } 10954359Sroberto IFNET_RUNLOCK(); 11054359Sroberto 11154359Sroberto for (i = 0; i < (UUID_NODE_LEN>>1); i++) 11254359Sroberto node[i] = (uint16_t)arc4random(); 11354359Sroberto *((uint8_t*)node) |= 0x80; 11454359Sroberto} 11554359Sroberto 11654359Sroberto/* 11754359Sroberto * Get the current time as a 60 bit count of 100-nanosecond intervals 11854359Sroberto * since 00:00:00.00, October 15,1582. We apply a magic offset to convert 11954359Sroberto * the Unix time since 00:00:00.00, Januari 1, 1970 to the date of the 12054359Sroberto * Gregorian reform to the Christian calendar. 12154359Sroberto */ 12254359Srobertostatic uint64_t 12354359Srobertouuid_time(void) 12454359Sroberto{ 12554359Sroberto struct bintime bt; 12654359Sroberto uint64_t time = 0x01B21DD213814000LL; 12754359Sroberto 12854359Sroberto bintime(&bt); 12954359Sroberto time += (uint64_t)bt.sec * 10000000LL; 13054359Sroberto time += (10000000LL * (uint32_t)(bt.frac >> 32)) >> 32; 13154359Sroberto return (time & ((1LL << 60) - 1LL)); 13254359Sroberto} 13354359Sroberto 13454359Sroberto#ifndef _SYS_SYSPROTO_H_ 13554359Srobertostruct uuidgen_args { 13654359Sroberto struct uuid *store; 13754359Sroberto int count; 13854359Sroberto}; 13954359Sroberto#endif 14054359Sroberto 14154359Srobertoint 14254359Srobertouuidgen(struct thread *td, struct uuidgen_args *uap) 14354359Sroberto{ 14454359Sroberto struct uuid_private uuid; 14554359Sroberto uint64_t time; 14654359Sroberto int error; 14754359Sroberto 14854359Sroberto /* 14954359Sroberto * Limit the number of UUIDs that can be created at the same time 15054359Sroberto * to some arbitrary number. This isn't really necessary, but I 15154359Sroberto * like to have some sort of upper-bound that's less than 2G :-) 15254359Sroberto * XXX needs to be tunable. 15354359Sroberto */ 15454359Sroberto if (uap->count < 1 || uap->count > 2048) 15554359Sroberto return (EINVAL); 15654359Sroberto 15754359Sroberto /* XXX: pre-validate accessibility to the whole of the UUID store? */ 15854359Sroberto 15954359Sroberto mtx_lock(&uuid_mutex); 16082498Sroberto 16154359Sroberto uuid_node(uuid.node); 16254359Sroberto time = uuid_time(); 16354359Sroberto 16454359Sroberto if (uuid_last.time.ll == 0LL || uuid_last.node[0] != uuid.node[0] || 16554359Sroberto uuid_last.node[1] != uuid.node[1] || 16654359Sroberto uuid_last.node[2] != uuid.node[2]) 16754359Sroberto uuid.seq = (uint16_t)arc4random() & 0x3fff; 16854359Sroberto else if (uuid_last.time.ll >= time) 16954359Sroberto uuid.seq = (uuid_last.seq + 1) & 0x3fff; 17054359Sroberto else 17154359Sroberto uuid.seq = uuid_last.seq; 17254359Sroberto 17354359Sroberto uuid_last = uuid; 17454359Sroberto uuid_last.time.ll = (time + uap->count - 1) & ((1LL << 60) - 1LL); 17554359Sroberto 17654359Sroberto mtx_unlock(&uuid_mutex); 17754359Sroberto 17854359Sroberto /* Set sequence and variant and deal with byte order. */ 17954359Sroberto uuid.seq = htobe16(uuid.seq | 0x8000); 18054359Sroberto 18154359Sroberto /* XXX: this should copyout larger chunks at a time. */ 18254359Sroberto do { 18354359Sroberto /* Set time and version (=1) and deal with byte order. */ 18454359Sroberto uuid.time.x.low = (uint32_t)time; 18554359Sroberto uuid.time.x.mid = (uint16_t)(time >> 32); 18654359Sroberto uuid.time.x.hi = ((uint16_t)(time >> 48) & 0xfff) | (1 << 12); 18754359Sroberto error = copyout(&uuid, uap->store, sizeof(uuid)); 18854359Sroberto uap->store++; 18954359Sroberto uap->count--; 190182007Sroberto time++; 191182007Sroberto } while (uap->count > 0 && !error); 192182007Sroberto 193182007Sroberto return (error); 194182007Sroberto} 195182007Sroberto 19656746Srobertoint 19756746Srobertosnprintf_uuid(char *buf, size_t sz, struct uuid *uuid) 19856746Sroberto{ 19954359Sroberto struct uuid_private *id; 20054359Sroberto int cnt; 20154359Sroberto 20254359Sroberto id = (struct uuid_private *)uuid; 20354359Sroberto cnt = snprintf(buf, sz, "%08x-%04x-%04x-%04x-%04x%04x%04x", 20454359Sroberto id->time.x.low, id->time.x.mid, id->time.x.hi, be16toh(id->seq), 20554359Sroberto be16toh(id->node[0]), be16toh(id->node[1]), be16toh(id->node[2])); 20654359Sroberto return (cnt); 20754359Sroberto} 20854359Sroberto 20954359Srobertoint 21054359Srobertoprintf_uuid(struct uuid *uuid) 21154359Sroberto{ 21254359Sroberto char buf[38]; 21354359Sroberto 21454359Sroberto snprintf_uuid(buf, sizeof(buf), uuid); 21554359Sroberto return (printf("%s", buf)); 21654359Sroberto} 21754359Sroberto 21854359Srobertoint 21954359Srobertosbuf_printf_uuid(struct sbuf *sb, struct uuid *uuid) 220{ 221 char buf[38]; 222 223 snprintf_uuid(buf, sizeof(buf), uuid); 224 return (sbuf_printf(sb, "%s", buf)); 225} 226 227/* 228 * Encode/Decode UUID into byte-stream. 229 * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt 230 * 231 * 0 1 2 3 232 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 233 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 234 * | time_low | 235 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 236 * | time_mid | time_hi_and_version | 237 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 238 * |clk_seq_hi_res | clk_seq_low | node (0-1) | 239 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 240 * | node (2-5) | 241 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 242 */ 243 244void 245le_uuid_enc(void *buf, struct uuid const *uuid) 246{ 247 u_char *p; 248 int i; 249 250 p = buf; 251 le32enc(p, uuid->time_low); 252 le16enc(p + 4, uuid->time_mid); 253 le16enc(p + 6, uuid->time_hi_and_version); 254 p[8] = uuid->clock_seq_hi_and_reserved; 255 p[9] = uuid->clock_seq_low; 256 for (i = 0; i < _UUID_NODE_LEN; i++) 257 p[10 + i] = uuid->node[i]; 258} 259 260void 261le_uuid_dec(void const *buf, struct uuid *uuid) 262{ 263 u_char const *p; 264 int i; 265 266 p = buf; 267 uuid->time_low = le32dec(p); 268 uuid->time_mid = le16dec(p + 4); 269 uuid->time_hi_and_version = le16dec(p + 6); 270 uuid->clock_seq_hi_and_reserved = p[8]; 271 uuid->clock_seq_low = p[9]; 272 for (i = 0; i < _UUID_NODE_LEN; i++) 273 uuid->node[i] = p[10 + i]; 274} 275void 276be_uuid_enc(void *buf, struct uuid const *uuid) 277{ 278 u_char *p; 279 int i; 280 281 p = buf; 282 be32enc(p, uuid->time_low); 283 be16enc(p + 4, uuid->time_mid); 284 be16enc(p + 6, uuid->time_hi_and_version); 285 p[8] = uuid->clock_seq_hi_and_reserved; 286 p[9] = uuid->clock_seq_low; 287 for (i = 0; i < _UUID_NODE_LEN; i++) 288 p[10 + i] = uuid->node[i]; 289} 290 291void 292be_uuid_dec(void const *buf, struct uuid *uuid) 293{ 294 u_char const *p; 295 int i; 296 297 p = buf; 298 uuid->time_low = be32dec(p); 299 uuid->time_mid = le16dec(p + 4); 300 uuid->time_hi_and_version = be16dec(p + 6); 301 uuid->clock_seq_hi_and_reserved = p[8]; 302 uuid->clock_seq_low = p[9]; 303 for (i = 0; i < _UUID_NODE_LEN; i++) 304 uuid->node[i] = p[10 + i]; 305} 306