1 /*- 2 * Copyright (c) 2002 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD: src/sys/kern/kern_uuid.c,v 1.13 2007/04/23 12:53:00 pjd Exp $ 27 */ 28 29 #include <sys/param.h> 30 #include <sys/endian.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/lock.h> 34 #include <sys/kern_syscall.h> 35 #include <sys/malloc.h> 36 #include <sys/random.h> 37 #include <sys/sbuf.h> 38 #include <sys/socket.h> 39 #include <sys/sysmsg.h> 40 #include <sys/uuid.h> 41 #include <sys/gpt.h> 42 #include <net/if.h> 43 #include <net/if_var.h> 44 45 /* 46 * See also: 47 * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt 48 * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm 49 * 50 * Note that the generator state is itself an UUID, but the time and clock 51 * sequence fields are written in the native byte order. 52 */ 53 54 /* We use an alternative, more convenient representation in the generator. */ 55 struct uuid_private { 56 union { 57 uint64_t ll; /* internal. */ 58 struct { 59 uint32_t low; 60 uint16_t mid; 61 uint16_t hi; 62 } x; 63 } time; 64 uint16_t seq; /* Big-endian. */ 65 uint16_t node[UUID_NODE_LEN>>1]; 66 }; 67 68 static struct uuid_private uuid_last; 69 70 static struct lock uuid_lock; 71 72 static 73 void 74 uuid_lock_init(void *arg __unused) 75 { 76 lockinit(&uuid_lock, "uuid", 0, 0); 77 } 78 SYSINIT(uuid_lock, SI_BOOT1_POST, SI_ORDER_ANY, uuid_lock_init, NULL); 79 80 /* 81 * Ask the network subsystem for a real MAC address from any of the 82 * system interfaces. If we can't find one, generate a random multicast 83 * MAC address. 84 */ 85 static void 86 uuid_node(uint16_t *node) 87 { 88 if (if_getanyethermac(node, UUID_NODE_LEN) != 0) 89 read_random(node, UUID_NODE_LEN, 1); 90 *((uint8_t*)node) |= 0x01; 91 } 92 93 /* 94 * Get the current time as a 60 bit count of 100-nanosecond intervals 95 * since 00:00:00.00, October 15,1582. We apply a magic offset to convert 96 * the Unix time since 00:00:00.00, January 1, 1970 to the date of the 97 * Gregorian reform to the Christian calendar. 98 */ 99 static uint64_t 100 uuid_time(void) 101 { 102 struct timespec ts; 103 uint64_t time = 0x01B21DD213814000LL; 104 105 nanotime(&ts); 106 time += ts.tv_sec * 10000000LL; /* 100 ns increments */ 107 time += ts.tv_nsec / 100; /* 100 ns increments */ 108 return (time & ((1LL << 60) - 1LL)); /* limit to 60 bits */ 109 } 110 111 struct uuid * 112 kern_uuidgen(struct uuid *store, size_t count) 113 { 114 struct uuid_private uuid; 115 uint64_t time; 116 size_t n; 117 118 lockmgr(&uuid_lock, LK_EXCLUSIVE | LK_RETRY); 119 120 uuid_node(uuid.node); 121 time = uuid_time(); 122 123 if (uuid_last.time.ll == 0LL || uuid_last.node[0] != uuid.node[0] || 124 uuid_last.node[1] != uuid.node[1] || 125 uuid_last.node[2] != uuid.node[2]) { 126 read_random(&uuid.seq, sizeof(uuid.seq), 1); 127 uuid.seq &= 0x3fff; 128 } else if (uuid_last.time.ll >= time) { 129 uuid.seq = (uuid_last.seq + 1) & 0x3fff; 130 } else { 131 uuid.seq = uuid_last.seq; 132 } 133 134 uuid_last = uuid; 135 uuid_last.time.ll = (time + count - 1) & ((1LL << 60) - 1LL); 136 137 lockmgr(&uuid_lock, LK_RELEASE); 138 139 /* Set sequence and variant and deal with byte order. */ 140 uuid.seq = htobe16(uuid.seq | 0x8000); 141 142 for (n = 0; n < count; n++) { 143 /* Set time and version (=1). */ 144 uuid.time.x.low = (uint32_t)time; 145 uuid.time.x.mid = (uint16_t)(time >> 32); 146 uuid.time.x.hi = ((uint16_t)(time >> 48) & 0xfff) | (1 << 12); 147 store[n] = *(struct uuid *)&uuid; 148 time++; 149 } 150 151 return (store); 152 } 153 154 /* 155 * uuidgen(struct uuid *store, int count) 156 * 157 * Generate an array of new UUIDs 158 */ 159 int 160 sys_uuidgen(struct sysmsg *sysmsg, const struct uuidgen_args *uap) 161 { 162 struct uuid *store; 163 size_t count; 164 int error; 165 166 /* 167 * Limit the number of UUIDs that can be created at the same time 168 * to some arbitrary number. This isn't really necessary, but I 169 * like to have some sort of upper-bound that's less than 2G :-) 170 * XXX probably needs to be tunable. 171 */ 172 if (uap->count < 1 || uap->count > 2048) 173 return (EINVAL); 174 175 count = uap->count; 176 store = kmalloc(count * sizeof(struct uuid), M_TEMP, M_WAITOK|M_NULLOK); 177 if (store == NULL) 178 return (ENOSPC); 179 kern_uuidgen(store, count); 180 error = copyout(store, uap->store, count * sizeof(struct uuid)); 181 kfree(store, M_TEMP); 182 return (error); 183 } 184 185 int 186 snprintf_uuid(char *buf, size_t sz, struct uuid *uuid) 187 { 188 struct uuid_private *id; 189 int cnt; 190 191 id = (struct uuid_private *)uuid; 192 cnt = ksnprintf(buf, sz, "%08x-%04x-%04x-%04x-%04x%04x%04x", 193 id->time.x.low, id->time.x.mid, id->time.x.hi, be16toh(id->seq), 194 be16toh(id->node[0]), be16toh(id->node[1]), be16toh(id->node[2])); 195 return (cnt); 196 } 197 198 int 199 printf_uuid(struct uuid *uuid) 200 { 201 char buf[38]; 202 203 snprintf_uuid(buf, sizeof(buf), uuid); 204 return (kprintf("%s", buf)); 205 } 206 207 int 208 sbuf_printf_uuid(struct sbuf *sb, struct uuid *uuid) 209 { 210 char buf[38]; 211 212 snprintf_uuid(buf, sizeof(buf), uuid); 213 return (sbuf_printf(sb, "%s", buf)); 214 } 215 216 /* 217 * Test functions 218 */ 219 220 /* A macro used to improve the readability of uuid_compare(). */ 221 #define DIFF_RETURN(a, b, field) do { \ 222 if ((a)->field != (b)->field) \ 223 return (((a)->field < (b)->field) ? -1 : 1); \ 224 } while (0) 225 226 /* 227 * kuuid_compare() - compare two UUIDs. 228 * See also: 229 * http://www.opengroup.org/onlinepubs/009629399/uuid_compare.htm 230 * 231 * NOTE: Either UUID can be NULL, meaning a nil UUID. nil UUIDs are smaller 232 * than any non-nil UUID. 233 */ 234 int 235 kuuid_compare(const struct uuid *a, const struct uuid *b) 236 { 237 int res; 238 239 /* Deal with NULL or equal pointers. */ 240 if (a == b) 241 return (0); 242 if (a == NULL) 243 return ((kuuid_is_nil(b)) ? 0 : -1); 244 if (b == NULL) 245 return ((kuuid_is_nil(a)) ? 0 : 1); 246 247 /* We have to compare the hard way. */ 248 DIFF_RETURN(a, b, time_low); 249 DIFF_RETURN(a, b, time_mid); 250 DIFF_RETURN(a, b, time_hi_and_version); 251 DIFF_RETURN(a, b, clock_seq_hi_and_reserved); 252 DIFF_RETURN(a, b, clock_seq_low); 253 254 res = bcmp(a->node, b->node, sizeof(a->node)); 255 if (res) 256 return ((res < 0) ? -1 : 1); 257 return (0); 258 } 259 260 #undef DIFF_RETURN 261 262 int 263 kuuid_is_nil(const struct uuid *uuid) 264 { 265 int i; 266 267 for (i = 0; i < sizeof(*uuid); i += sizeof(int)) { 268 if (*(const int *)((const char *)uuid + i) != 0) 269 return(0); 270 } 271 return(1); 272 } 273 274 int 275 kuuid_is_ccd(const struct uuid *uuid) 276 { 277 static struct uuid ccd_uuid = GPT_ENT_TYPE_DRAGONFLY_CCD; 278 return(kuuid_compare(uuid, &ccd_uuid) == 0); 279 } 280 281 int 282 kuuid_is_vinum(const struct uuid *uuid) 283 { 284 static struct uuid vinum_uuid = GPT_ENT_TYPE_DRAGONFLY_VINUM; 285 return(kuuid_compare(uuid, &vinum_uuid) == 0); 286 } 287 288 /* 289 * Encode/Decode UUID into byte-stream. 290 * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt 291 * 292 * 0 1 2 3 293 * 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 294 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 295 * | time_low | 296 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 297 * | time_mid | time_hi_and_version | 298 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 299 * |clk_seq_hi_res | clk_seq_low | node (0-1) | 300 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 301 * | node (2-5) | 302 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 303 */ 304 305 void 306 le_uuid_enc(void *buf, struct uuid const *uuid) 307 { 308 u_char *p; 309 int i; 310 311 p = buf; 312 le32enc(p, uuid->time_low); 313 le16enc(p + 4, uuid->time_mid); 314 le16enc(p + 6, uuid->time_hi_and_version); 315 p[8] = uuid->clock_seq_hi_and_reserved; 316 p[9] = uuid->clock_seq_low; 317 for (i = 0; i < _UUID_NODE_LEN; i++) 318 p[10 + i] = uuid->node[i]; 319 } 320 321 void 322 le_uuid_dec(void const *buf, struct uuid *uuid) 323 { 324 u_char const *p; 325 int i; 326 327 p = buf; 328 uuid->time_low = le32dec(p); 329 uuid->time_mid = le16dec(p + 4); 330 uuid->time_hi_and_version = le16dec(p + 6); 331 uuid->clock_seq_hi_and_reserved = p[8]; 332 uuid->clock_seq_low = p[9]; 333 for (i = 0; i < _UUID_NODE_LEN; i++) 334 uuid->node[i] = p[10 + i]; 335 } 336 337 void 338 be_uuid_enc(void *buf, struct uuid const *uuid) 339 { 340 u_char *p; 341 int i; 342 343 p = buf; 344 be32enc(p, uuid->time_low); 345 be16enc(p + 4, uuid->time_mid); 346 be16enc(p + 6, uuid->time_hi_and_version); 347 p[8] = uuid->clock_seq_hi_and_reserved; 348 p[9] = uuid->clock_seq_low; 349 for (i = 0; i < _UUID_NODE_LEN; i++) 350 p[10 + i] = uuid->node[i]; 351 } 352 353 void 354 be_uuid_dec(void const *buf, struct uuid *uuid) 355 { 356 u_char const *p; 357 int i; 358 359 p = buf; 360 uuid->time_low = be32dec(p); 361 uuid->time_mid = le16dec(p + 4); 362 uuid->time_hi_and_version = be16dec(p + 6); 363 uuid->clock_seq_hi_and_reserved = p[8]; 364 uuid->clock_seq_low = p[9]; 365 for (i = 0; i < _UUID_NODE_LEN; i++) 366 uuid->node[i] = p[10 + i]; 367 } 368 369 int 370 parse_uuid(const char *str, struct uuid *uuid) 371 { 372 u_int c[11]; 373 int n; 374 375 /* An empty string represents a nil UUID. */ 376 if (*str == '\0') { 377 bzero(uuid, sizeof(*uuid)); 378 return (0); 379 } 380 381 /* The UUID string representation has a fixed length. */ 382 if (strlen(str) != 36) 383 return (EINVAL); 384 385 /* 386 * We only work with "new" UUIDs. New UUIDs have the form: 387 * 01234567-89ab-cdef-0123-456789abcdef 388 * The so called "old" UUIDs, which we don't support, have the form: 389 * 0123456789ab.cd.ef.01.23.45.67.89.ab 390 */ 391 if (str[8] != '-') 392 return (EINVAL); 393 394 n = ksscanf(str, "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x", c + 0, c + 1, 395 c + 2, c + 3, c + 4, c + 5, c + 6, c + 7, c + 8, c + 9, c + 10); 396 /* Make sure we have all conversions. */ 397 if (n != 11) 398 return (EINVAL); 399 400 /* Successful scan. Build the UUID. */ 401 uuid->time_low = c[0]; 402 uuid->time_mid = c[1]; 403 uuid->time_hi_and_version = c[2]; 404 uuid->clock_seq_hi_and_reserved = c[3]; 405 uuid->clock_seq_low = c[4]; 406 for (n = 0; n < 6; n++) 407 uuid->node[n] = c[n + 5]; 408 409 /* Check semantics... */ 410 return (((c[3] & 0x80) != 0x00 && /* variant 0? */ 411 (c[3] & 0xc0) != 0x80 && /* variant 1? */ 412 (c[3] & 0xe0) != 0xc0) ? EINVAL : 0); /* variant 2? */ 413 } 414