kern_uuid.c revision 253617
1116742Ssam/*- 2116904Ssam * Copyright (c) 2002 Marcel Moolenaar 3186904Ssam * All rights reserved. 4116742Ssam * 5116742Ssam * Redistribution and use in source and binary forms, with or without 6116742Ssam * modification, are permitted provided that the following conditions 7116742Ssam * are met: 8116742Ssam * 9116742Ssam * 1. Redistributions of source code must retain the above copyright 10116742Ssam * notice, this list of conditions and the following disclaimer. 11116742Ssam * 2. Redistributions in binary form must reproduce the above copyright 12116742Ssam * notice, this list of conditions and the following disclaimer in the 13116742Ssam * documentation and/or other materials provided with the distribution. 14116742Ssam * 15116904Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16116904Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17116904Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18116904Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19116904Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20116904Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21116904Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22116904Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23116904Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24116904Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25116904Ssam */ 26116742Ssam 27116742Ssam#include <sys/cdefs.h> 28116742Ssam__FBSDID("$FreeBSD: head/sys/kern/kern_uuid.c 253617 2013-07-24 18:13:43Z marcel $"); 29116742Ssam 30116742Ssam#include <sys/param.h> 31138568Ssam#include <sys/endian.h> 32170530Ssam#include <sys/kernel.h> 33116742Ssam#include <sys/lock.h> 34138568Ssam#include <sys/mutex.h> 35178354Ssam#include <sys/sbuf.h> 36178354Ssam#include <sys/socket.h> 37178354Ssam#include <sys/sysproto.h> 38178354Ssam#include <sys/systm.h> 39178354Ssam#include <sys/jail.h> 40178354Ssam#include <sys/uuid.h> 41178354Ssam 42178354Ssam#include <net/if.h> 43178354Ssam#include <net/if_dl.h> 44178354Ssam#include <net/if_types.h> 45138568Ssam#include <net/vnet.h> 46138568Ssam 47138568Ssam/* 48138568Ssam * See also: 49138568Ssam * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt 50138568Ssam * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm 51138568Ssam * 52138568Ssam * Note that the generator state is itself an UUID, but the time and clock 53138568Ssam * sequence fields are written in the native byte order. 54170530Ssam */ 55138568Ssam 56172211SsamCTASSERT(sizeof(struct uuid) == 16); 57172211Ssam 58172211Ssam/* We use an alternative, more convenient representation in the generator. */ 59116742Ssamstruct uuid_private { 60116742Ssam union { 61116742Ssam uint64_t ll; /* internal. */ 62170530Ssam struct { 63138568Ssam uint32_t low; 64116742Ssam uint16_t mid; 65138568Ssam uint16_t hi; 66138568Ssam } x; 67178354Ssam } time; 68138568Ssam uint16_t seq; /* Big-endian. */ 69116742Ssam uint16_t node[UUID_NODE_LEN>>1]; 70178354Ssam}; 71178354Ssam 72190093SrpauloCTASSERT(sizeof(struct uuid_private) == 16); 73178354Ssam 74178354Ssamstruct uuid_macaddr { 75178354Ssam uint16_t state; 76178354Ssam#define UUID_ETHER_EMPTY 0 77178354Ssam#define UUID_ETHER_RANDOM 1 78178354Ssam#define UUID_ETHER_UNIQUE 2 79178354Ssam uint16_t node[UUID_NODE_LEN>>1]; 80178354Ssam}; 81178354Ssam 82178354Ssamstatic struct uuid_private uuid_last; 83186904Ssam 84178354Ssam#define UUID_NETHER 4 85178354Ssamstatic struct uuid_macaddr uuid_ether[UUID_NETHER]; 86178354Ssam 87178354Ssamstatic struct mtx uuid_mutex; 88178354SsamMTX_SYSINIT(uuid_lock, &uuid_mutex, "UUID generator mutex lock", MTX_DEF); 89178354Ssam 90116742Ssam/* 91116742Ssam * Return the first MAC address added in the array. If it's empty, then 92116742Ssam * construct a sufficiently random multicast MAC address first. Any 93116742Ssam * addresses added later will bump the random MAC address up tp the next 94116742Ssam * index. 95116742Ssam */ 96178354Ssamstatic void 97178354Ssamuuid_node(uint16_t *node) 98178354Ssam{ 99178354Ssam int i; 100178354Ssam 101178354Ssam if (uuid_ether[0].state == UUID_ETHER_EMPTY) { 102120483Ssam for (i = 0; i < (UUID_NODE_LEN>>1); i++) 103183252Ssam uuid_ether[0].node[i] = (uint16_t)arc4random(); 104183252Ssam *((uint8_t*)uuid_ether[0].node) |= 0x01; 105183252Ssam uuid_ether[0].state = UUID_ETHER_RANDOM; 106183252Ssam } 107183252Ssam for (i = 0; i < (UUID_NODE_LEN>>1); i++) 108183252Ssam node[i] = uuid_ether[0].node[i]; 109183252Ssam} 110183252Ssam 111183252Ssam/* 112183252Ssam * Get the current time as a 60 bit count of 100-nanosecond intervals 113183252Ssam * since 00:00:00.00, October 15,1582. We apply a magic offset to convert 114183252Ssam * the Unix time since 00:00:00.00, January 1, 1970 to the date of the 115183252Ssam * Gregorian reform to the Christian calendar. 116183255Ssam */ 117183255Ssamstatic uint64_t 118183256Ssamuuid_time(void) 119183257Ssam{ 120183257Ssam struct bintime bt; 121186099Ssam uint64_t time = 0x01B21DD213814000LL; 122183252Ssam 123183252Ssam bintime(&bt); 124183252Ssam time += (uint64_t)bt.sec * 10000000LL; 125170530Ssam time += (10000000LL * (uint32_t)(bt.frac >> 32)) >> 32; 126170530Ssam return (time & ((1LL << 60) - 1LL)); 127170530Ssam} 128170530Ssam 129170530Ssamstruct uuid * 130170530Ssamkern_uuidgen(struct uuid *store, size_t count) 131170530Ssam{ 132170530Ssam struct uuid_private uuid; 133183252Ssam uint64_t time; 134170530Ssam size_t n; 135183251Ssam 136173273Ssam mtx_lock(&uuid_mutex); 137170530Ssam 138178354Ssam uuid_node(uuid.node); 139172225Ssam time = uuid_time(); 140172225Ssam 141172225Ssam if (uuid_last.time.ll == 0LL || uuid_last.node[0] != uuid.node[0] || 142172225Ssam uuid_last.node[1] != uuid.node[1] || 143170530Ssam uuid_last.node[2] != uuid.node[2]) 144138568Ssam uuid.seq = (uint16_t)arc4random() & 0x3fff; 145138568Ssam else if (uuid_last.time.ll >= time) 146116742Ssam uuid.seq = (uuid_last.seq + 1) & 0x3fff; 147116742Ssam else 148170530Ssam uuid.seq = uuid_last.seq; 149178354Ssam 150170530Ssam uuid_last = uuid; 151116742Ssam uuid_last.time.ll = (time + count - 1) & ((1LL << 60) - 1LL); 152116742Ssam 153170530Ssam mtx_unlock(&uuid_mutex); 154170530Ssam 155116742Ssam /* Set sequence and variant and deal with byte order. */ 156116742Ssam uuid.seq = htobe16(uuid.seq | 0x8000); 157138568Ssam 158170530Ssam for (n = 0; n < count; n++) { 159178354Ssam /* Set time and version (=1). */ 160138568Ssam uuid.time.x.low = (uint32_t)time; 161170530Ssam uuid.time.x.mid = (uint16_t)(time >> 32); 162170530Ssam uuid.time.x.hi = ((uint16_t)(time >> 48) & 0xfff) | (1 << 12); 163170530Ssam store[n] = *(struct uuid *)&uuid; 164170530Ssam time++; 165116742Ssam } 166170530Ssam 167170530Ssam return (store); 168170530Ssam} 169178354Ssam 170170530Ssam#ifndef _SYS_SYSPROTO_H_ 171170530Ssamstruct uuidgen_args { 172170530Ssam struct uuid *store; 173116742Ssam int count; 174170530Ssam}; 175170530Ssam#endif 176170530Ssamint 177170530Ssamsys_uuidgen(struct thread *td, struct uuidgen_args *uap) 178170530Ssam{ 179170530Ssam struct uuid *store; 180170530Ssam size_t count; 181170530Ssam int error; 182170530Ssam 183170530Ssam /* 184170530Ssam * Limit the number of UUIDs that can be created at the same time 185170530Ssam * to some arbitrary number. This isn't really necessary, but I 186116742Ssam * like to have some sort of upper-bound that's less than 2G :-) 187138568Ssam * XXX probably needs to be tunable. 188138568Ssam */ 189178354Ssam if (uap->count < 1 || uap->count > 2048) 190184288Ssam return (EINVAL); 191138568Ssam 192178354Ssam count = uap->count; 193178354Ssam store = malloc(count * sizeof(struct uuid), M_TEMP, M_WAITOK); 194178354Ssam kern_uuidgen(store, count); 195178354Ssam error = copyout(store, uap->store, count * sizeof(struct uuid)); 196116742Ssam free(store, M_TEMP); 197138568Ssam return (error); 198178354Ssam} 199116742Ssam 200170530Ssamint 201173273Ssamuuid_ether_add(const uint8_t *addr) 202173273Ssam{ 203182828Ssam int i, sum; 204182828Ssam 205183255Ssam /* 206183257Ssam * Validate input. No multicast (flag 0x1), no locally administered 207183257Ssam * (flag 0x2) and no 'all-zeroes' addresses. 208170530Ssam */ 209187797Ssam if (addr[0] & 0x03) 210187797Ssam return (EINVAL); 211187797Ssam sum = 0; 212187797Ssam for (i = 0; i < UUID_NODE_LEN; i++) 213187797Ssam sum += addr[i]; 214138568Ssam if (sum == 0) 215138568Ssam return (EINVAL); 216138568Ssam 217138568Ssam mtx_lock(&uuid_mutex); 218138568Ssam 219138568Ssam /* Make sure the MAC isn't known already and that there's space. */ 220178354Ssam i = 0; 221178354Ssam while (i < UUID_NETHER && uuid_ether[i].state == UUID_ETHER_UNIQUE) { 222178354Ssam if (!bcmp(addr, uuid_ether[i].node, UUID_NODE_LEN)) { 223178354Ssam mtx_unlock(&uuid_mutex); 224178354Ssam return (EEXIST); 225178354Ssam } 226178354Ssam i++; 227178354Ssam } 228178354Ssam if (i == UUID_NETHER) { 229178354Ssam mtx_unlock(&uuid_mutex); 230178354Ssam return (ENOSPC); 231178354Ssam } 232178354Ssam 233178354Ssam /* Insert MAC at index, moving the non-empty entry if possible. */ 234178354Ssam if (uuid_ether[i].state == UUID_ETHER_RANDOM && i < UUID_NETHER - 1) 235178354Ssam uuid_ether[i + 1] = uuid_ether[i]; 236178354Ssam uuid_ether[i].state = UUID_ETHER_UNIQUE; 237178354Ssam bcopy(addr, uuid_ether[i].node, UUID_NODE_LEN); 238178354Ssam mtx_unlock(&uuid_mutex); 239178354Ssam return (0); 240178354Ssam} 241178354Ssam 242178354Ssamint 243178354Ssamuuid_ether_del(const uint8_t *addr) 244178354Ssam{ 245178354Ssam int i; 246178354Ssam 247178354Ssam mtx_lock(&uuid_mutex); 248178354Ssam i = 0; 249178354Ssam while (i < UUID_NETHER && uuid_ether[i].state == UUID_ETHER_UNIQUE && 250178354Ssam bcmp(addr, uuid_ether[i].node, UUID_NODE_LEN)) 251178354Ssam i++; 252116742Ssam if (i == UUID_NETHER || uuid_ether[i].state != UUID_ETHER_UNIQUE) { 253116742Ssam mtx_unlock(&uuid_mutex); 254116742Ssam return (ENOENT); 255138568Ssam } 256116742Ssam 257116742Ssam /* Remove it by shifting higher index entries down. */ 258116742Ssam while (i < UUID_NETHER - 1 && uuid_ether[i].state != UUID_ETHER_EMPTY) { 259116742Ssam uuid_ether[i] = uuid_ether[i + 1]; 260116742Ssam i++; 261116742Ssam } 262138568Ssam if (uuid_ether[i].state != UUID_ETHER_EMPTY) { 263116742Ssam uuid_ether[i].state = UUID_ETHER_EMPTY; 264116742Ssam bzero(uuid_ether[i].node, UUID_NODE_LEN); 265116742Ssam } 266116742Ssam mtx_unlock(&uuid_mutex); 267116742Ssam return (0); 268144618Ssam} 269144618Ssam 270144618Ssamint 271178354Ssamsnprintf_uuid(char *buf, size_t sz, struct uuid *uuid) 272178354Ssam{ 273178354Ssam struct uuid_private *id; 274127877Ssam int cnt; 275138568Ssam 276138568Ssam id = (struct uuid_private *)uuid; 277138568Ssam cnt = snprintf(buf, sz, "%08x-%04x-%04x-%04x-%04x%04x%04x", 278138568Ssam id->time.x.low, id->time.x.mid, id->time.x.hi, be16toh(id->seq), 279138568Ssam be16toh(id->node[0]), be16toh(id->node[1]), be16toh(id->node[2])); 280116742Ssam return (cnt); 281148302Ssam} 282148302Ssam 283138568Ssamint 284178354Ssamprintf_uuid(struct uuid *uuid) 285178354Ssam{ 286178354Ssam char buf[38]; 287178354Ssam 288178354Ssam snprintf_uuid(buf, sizeof(buf), uuid); 289191746Sthompsa return (printf("%s", buf)); 290191746Sthompsa} 291178354Ssam 292148306Ssamint 293170530Ssamsbuf_printf_uuid(struct sbuf *sb, struct uuid *uuid) 294184274Ssam{ 295170530Ssam char buf[38]; 296178354Ssam 297178354Ssam snprintf_uuid(buf, sizeof(buf), uuid); 298138568Ssam return (sbuf_printf(sb, "%s", buf)); 299178354Ssam} 300178354Ssam 301178354Ssam/* 302178354Ssam * Encode/Decode UUID into byte-stream. 303178354Ssam * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt 304178354Ssam * 305178354Ssam * 0 1 2 3 306138568Ssam * 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 307138568Ssam * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 308178354Ssam * | time_low | 309178354Ssam * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 310178354Ssam * | time_mid | time_hi_and_version | 311178354Ssam * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 312138568Ssam * |clk_seq_hi_res | clk_seq_low | node (0-1) | 313138568Ssam * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 314138568Ssam * | node (2-5) | 315138568Ssam * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 316138568Ssam */ 317138568Ssam 318170530Ssamvoid 319170530Ssamle_uuid_enc(void *buf, struct uuid const *uuid) 320178354Ssam{ 321138568Ssam u_char *p; 322178354Ssam int i; 323138568Ssam 324138568Ssam p = buf; 325138568Ssam le32enc(p, uuid->time_low); 326178354Ssam le16enc(p + 4, uuid->time_mid); 327178354Ssam le16enc(p + 6, uuid->time_hi_and_version); 328178354Ssam p[8] = uuid->clock_seq_hi_and_reserved; 329178354Ssam p[9] = uuid->clock_seq_low; 330178354Ssam for (i = 0; i < _UUID_NODE_LEN; i++) 331178354Ssam p[10 + i] = uuid->node[i]; 332178354Ssam} 333178354Ssam 334178354Ssamvoid 335178354Ssamle_uuid_dec(void const *buf, struct uuid *uuid) 336138568Ssam{ 337144618Ssam u_char const *p; 338138568Ssam int i; 339178354Ssam 340178354Ssam p = buf; 341178354Ssam uuid->time_low = le32dec(p); 342178354Ssam uuid->time_mid = le16dec(p + 4); 343170530Ssam uuid->time_hi_and_version = le16dec(p + 6); 344178354Ssam uuid->clock_seq_hi_and_reserved = p[8]; 345138568Ssam uuid->clock_seq_low = p[9]; 346178354Ssam for (i = 0; i < _UUID_NODE_LEN; i++) 347178354Ssam uuid->node[i] = p[10 + i]; 348178354Ssam} 349178354Ssam 350178354Ssamvoid 351178354Ssambe_uuid_enc(void *buf, struct uuid const *uuid) 352178354Ssam{ 353178354Ssam u_char *p; 354178354Ssam int i; 355178354Ssam 356170530Ssam p = buf; 357170530Ssam be32enc(p, uuid->time_low); 358138568Ssam be16enc(p + 4, uuid->time_mid); 359148863Ssam be16enc(p + 6, uuid->time_hi_and_version); 360148863Ssam p[8] = uuid->clock_seq_hi_and_reserved; 361170530Ssam p[9] = uuid->clock_seq_low; 362148863Ssam for (i = 0; i < _UUID_NODE_LEN; i++) 363178354Ssam p[10 + i] = uuid->node[i]; 364170530Ssam} 365170530Ssam 366138568Ssamvoid 367138568Ssambe_uuid_dec(void const *buf, struct uuid *uuid) 368178354Ssam{ 369178354Ssam u_char const *p; 370138568Ssam int i; 371138568Ssam 372178354Ssam p = buf; 373178354Ssam uuid->time_low = be32dec(p); 374178354Ssam uuid->time_mid = le16dec(p + 4); 375178354Ssam uuid->time_hi_and_version = be16dec(p + 6); 376178354Ssam uuid->clock_seq_hi_and_reserved = p[8]; 377178354Ssam uuid->clock_seq_low = p[9]; 378178354Ssam for (i = 0; i < _UUID_NODE_LEN; i++) 379178354Ssam uuid->node[i] = p[10 + i]; 380178354Ssam} 381178354Ssam 382138568Ssamint 383144618Ssamparse_uuid(const char *str, struct uuid *uuid) 384178354Ssam{ 385178354Ssam u_int c[11]; 386170530Ssam int n; 387178354Ssam 388178354Ssam /* An empty string represents a nil UUID. */ 389178354Ssam if (*str == '\0') { 390178354Ssam bzero(uuid, sizeof(*uuid)); 391178354Ssam return (0); 392178354Ssam } 393178354Ssam 394170530Ssam /* The UUID string representation has a fixed length. */ 395170530Ssam if (strlen(str) != 36) 396148863Ssam return (EINVAL); 397170530Ssam 398178354Ssam /* 399178354Ssam * We only work with "new" UUIDs. New UUIDs have the form: 400138568Ssam * 01234567-89ab-cdef-0123-456789abcdef 401148863Ssam * The so called "old" UUIDs, which we don't support, have the form: 402170530Ssam * 0123456789ab.cd.ef.01.23.45.67.89.ab 403138568Ssam */ 404116742Ssam if (str[8] != '-') 405144618Ssam return (EINVAL); 406116742Ssam 407116742Ssam n = sscanf(str, "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x", c + 0, c + 1, 408178354Ssam c + 2, c + 3, c + 4, c + 5, c + 6, c + 7, c + 8, c + 9, c + 10); 409144618Ssam /* Make sure we have all conversions. */ 410138568Ssam if (n != 11) 411144618Ssam return (EINVAL); 412138568Ssam 413178354Ssam /* Successful scan. Build the UUID. */ 414178354Ssam uuid->time_low = c[0]; 415170530Ssam uuid->time_mid = c[1]; 416153073Ssam uuid->time_hi_and_version = c[2]; 417153073Ssam uuid->clock_seq_hi_and_reserved = c[3]; 418153073Ssam uuid->clock_seq_low = c[4]; 419178354Ssam for (n = 0; n < 6; n++) 420148936Ssam uuid->node[n] = c[n + 5]; 421148936Ssam 422178354Ssam /* Check semantics... */ 423178354Ssam return (((c[3] & 0x80) != 0x00 && /* variant 0? */ 424178354Ssam (c[3] & 0xc0) != 0x80 && /* variant 1? */ 425178354Ssam (c[3] & 0xe0) != 0xc0) ? EINVAL : 0); /* variant 2? */ 426116742Ssam} 427