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