1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright 2012 Milan Jurik. All rights reserved.
  25  * Copyright 2013 Joyent, Inc. All rights reserved.
  26  * Copyright 2014 Andrew Stormont.
  27  */
  28 
  29 /*
  30  * The copyright in this file is taken from the original Leach & Salz
  31  * UUID specification, from which this implementation is derived.
  32  */
  33 
  34 /*
  35  * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
  36  * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
  37  * Digital Equipment Corporation, Maynard, Mass.  Copyright (c) 1998
  38  * Microsoft.  To anyone who acknowledges that this file is provided
  39  * "AS IS" without any express or implied warranty: permission to use,
  40  * copy, modify, and distribute this file for any purpose is hereby
  41  * granted without fee, provided that the above copyright notices and
  42  * this notice appears in all source code copies, and that none of the
  43  * names of Open Software Foundation, Inc., Hewlett-Packard Company,
  44  * or Digital Equipment Corporation be used in advertising or
  45  * publicity pertaining to distribution of the software without
  46  * specific, written prior permission.  Neither Open Software
  47  * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
  48  * Equipment Corporation makes any representations about the
  49  * suitability of this software for any purpose.
  50  */
  51 
  52 /*
  53  * This module is the workhorse for generating abstract
  54  * UUIDs.  It delegates system-specific tasks (such
  55  * as obtaining the node identifier or system time)
  56  * to the sysdep module.
  57  */
  58 
  59 #include <ctype.h>
  60 #include <sys/param.h>
  61 #include <sys/stat.h>
  62 #include <errno.h>
  63 #include <stdio.h>
  64 #include <stdlib.h>
  65 #include <strings.h>
  66 #include <fcntl.h>
  67 #include <unistd.h>
  68 #include <synch.h>
  69 #include <sys/mman.h>
  70 #include "uuid_misc.h"
  71 
  72 shared_buffer_t         *data;
  73 
  74 static  uuid_node_t     node_id_cache;
  75 static  int             node_init;
  76 static  int             file_type;
  77 static  int             fd;
  78 
  79 /*
  80  * The urandmtx mutex prevents multiple opens of /dev/urandom and protects the
  81  * cache.
  82  */
  83 #define RCACHE_SIZE     65535
  84 static  mutex_t         urandmtx;
  85 static  int             fd_urand = -1;
  86 static  char            rcache[RCACHE_SIZE];
  87 static  char            *rcachep = rcache;
  88 
  89 /*
  90  * misc routines
  91  */
  92 uint16_t                get_random(void);
  93 void                    get_current_time(uuid_time_t *);
  94 
  95 void                    struct_to_string(uuid_t, struct uuid *);
  96 void                    string_to_struct(struct uuid *, uuid_t);
  97 int                     get_ethernet_address(uuid_node_t *);
  98 
  99 /*
 100  * local functions
 101  */
 102 static  int             map_state();
 103 static  void            format_uuid(struct uuid *, uint16_t, uuid_time_t,
 104     uuid_node_t);
 105 static  void            fill_random_bytes(uchar_t *, int);
 106 static  int             uuid_create(struct uuid *);
 107 static  void            gen_ethernet_address(uuid_node_t *);
 108 static  void            revalidate_data(uuid_node_t *);
 109 
 110 /*
 111  * Generates a uuid based on version 1 format.
 112  * Returns 0 on success and -1 on failure.
 113  */
 114 static int
 115 uuid_create(struct uuid *uuid)
 116 {
 117         uuid_time_t     timestamp;
 118         uuid_node_t     system_node;
 119         int             ret, non_unique = 0;
 120 
 121         /*
 122          * Get the system MAC address and/or cache it
 123          */
 124         if (node_init) {
 125                 bcopy(&node_id_cache, &system_node, sizeof (uuid_node_t));
 126         } else {
 127                 gen_ethernet_address(&system_node);
 128                 bcopy(&system_node, &node_id_cache, sizeof (uuid_node_t));
 129                 node_init = 1;
 130         }
 131 
 132         /*
 133          * Access the state file, mmap it and initialize the shared lock.
 134          * file_type tells us whether we had access to the state file or
 135          * created a temporary one.
 136          */
 137         if (map_state() == -1)
 138                 return (-1);
 139 
 140         /*
 141          * Acquire the lock
 142          */
 143         for (;;) {
 144                 if ((ret = mutex_lock(&data->lock)) == 0)
 145                         break;
 146                 else
 147                         switch (ret) {
 148                                 case EOWNERDEAD:
 149                                         revalidate_data(&system_node);
 150                                         (void) mutex_consistent(&data->lock);
 151                                         (void) mutex_unlock(&data->lock);
 152                                         break;
 153                                 case ENOTRECOVERABLE:
 154                                         return (ret);
 155                         }
 156         }
 157 
 158         /* State file is either new or is temporary, get a random clock seq */
 159         if (data->state.clock == 0) {
 160                 data->state.clock = get_random();
 161                 non_unique++;
 162         }
 163 
 164         if (memcmp(&system_node, &data->state.node, sizeof (uuid_node_t)) != 0)
 165                 data->state.clock++;
 166 
 167         get_current_time(&timestamp);
 168 
 169         /*
 170          * If timestamp is not set or is not in the past, bump
 171          * data->state.clock
 172          */
 173         if ((data->state.ts == 0) || (data->state.ts >= timestamp)) {
 174                 data->state.clock++;
 175                 data->state.ts = timestamp;
 176         }
 177 
 178         if (non_unique)
 179                 system_node.nodeID[0] |= 0x80;
 180 
 181         /* Stuff fields into the UUID struct */
 182         format_uuid(uuid, data->state.clock, timestamp, system_node);
 183 
 184         (void) mutex_unlock(&data->lock);
 185 
 186         return (0);
 187 }
 188 
 189 /*
 190  * Fills system_node with Ethernet address if available,
 191  * else fills random numbers
 192  */
 193 static void
 194 gen_ethernet_address(uuid_node_t *system_node)
 195 {
 196         uchar_t         node[6];
 197 
 198         if (get_ethernet_address(system_node) != 0) {
 199                 fill_random_bytes(node, 6);
 200                 (void) memcpy(system_node->nodeID, node, 6);
 201                 /*
 202                  * use 8:0:20 with the multicast bit set
 203                  * to avoid namespace collisions.
 204                  */
 205                 system_node->nodeID[0] = 0x88;
 206                 system_node->nodeID[1] = 0x00;
 207                 system_node->nodeID[2] = 0x20;
 208         }
 209 }
 210 
 211 /*
 212  * Formats a UUID, given the clock_seq timestamp, and node address.
 213  * Fills in passed-in pointer with the resulting uuid.
 214  */
 215 static void
 216 format_uuid(struct uuid *uuid, uint16_t clock_seq,
 217     uuid_time_t timestamp, uuid_node_t node)
 218 {
 219 
 220         /*
 221          * First set up the first 60 bits from the timestamp
 222          */
 223         uuid->time_low = (uint32_t)(timestamp & 0xFFFFFFFF);
 224         uuid->time_mid = (uint16_t)((timestamp >> 32) & 0xFFFF);
 225         uuid->time_hi_and_version = (uint16_t)((timestamp >> 48) & 0x0FFF);
 226 
 227         /*
 228          * This is version 1, so say so in the UUID version field (4 bits)
 229          */
 230         uuid->time_hi_and_version |= (1 << 12);
 231 
 232         /*
 233          * Now do the clock sequence
 234          */
 235         uuid->clock_seq_low = clock_seq & 0xFF;
 236 
 237         /*
 238          * We must save the most-significant 2 bits for the reserved field
 239          */
 240         uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
 241 
 242         /*
 243          * The variant for this format is the 2 high bits set to 10,
 244          * so here it is
 245          */
 246         uuid->clock_seq_hi_and_reserved |= 0x80;
 247 
 248         /*
 249          * write result to passed-in pointer
 250          */
 251         (void) memcpy(&uuid->node_addr, &node, sizeof (uuid->node_addr));
 252 }
 253 
 254 /*
 255  * Opens/creates the state file, falling back to a tmp
 256  */
 257 static int
 258 map_state()
 259 {
 260         FILE    *tmp;
 261 
 262         /* If file's mapped, return */
 263         if (file_type != 0)
 264                 return (1);
 265 
 266         if ((fd = open(STATE_LOCATION, O_RDWR)) < 0) {
 267                 file_type = TEMP_FILE;
 268 
 269                 if ((tmp = tmpfile()) == NULL)
 270                         return (-1);
 271                 else
 272                         fd = fileno(tmp);
 273         } else {
 274                 file_type = STATE_FILE;
 275         }
 276 
 277         (void) ftruncate(fd, (off_t)sizeof (shared_buffer_t));
 278 
 279         /* LINTED - alignment */
 280         data = (shared_buffer_t *)mmap(NULL, sizeof (shared_buffer_t),
 281             PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
 282 
 283         if (data == MAP_FAILED)
 284                 return (-1);
 285 
 286         (void) mutex_init(&data->lock, USYNC_PROCESS|LOCK_ROBUST, 0);
 287 
 288         (void) close(fd);
 289 
 290         return (1);
 291 }
 292 
 293 static void
 294 revalidate_data(uuid_node_t *node)
 295 {
 296         int i;
 297 
 298         data->state.ts = 0;
 299 
 300         for (i = 0; i < sizeof (data->state.node.nodeID); i++)
 301                 data->state.node.nodeID[i] = 0;
 302 
 303         data->state.clock = 0;
 304 
 305         gen_ethernet_address(node);
 306         bcopy(node, &node_id_cache, sizeof (uuid_node_t));
 307         node_init = 1;
 308 }
 309 
 310 /*
 311  * Prints a nicely-formatted uuid to stdout.
 312  */
 313 void
 314 uuid_print(struct uuid u)
 315 {
 316         int i;
 317 
 318         (void) printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
 319             u.time_hi_and_version, u.clock_seq_hi_and_reserved,
 320             u.clock_seq_low);
 321         for (i = 0; i < 6; i++)
 322                 (void) printf("%2.2x", u.node_addr[i]);
 323         (void) printf("\n");
 324 }
 325 
 326 /*
 327  * Only called with urandmtx held.
 328  * Fills/refills the cache of randomness. We know that our allocations of
 329  * randomness are always much less than the total size of the cache.
 330  * Tries to use /dev/urandom random number generator - if that fails for some
 331  * reason, it retries MAX_RETRY times then sets rcachep to NULL so we no
 332  * longer use the cache.
 333  */
 334 static void
 335 load_cache()
 336 {
 337         int i, retries = 0;
 338         int nbytes = RCACHE_SIZE;
 339         char *buf = rcache;
 340 
 341         while (nbytes > 0) {
 342                 i = read(fd_urand, buf, nbytes);
 343                 if ((i < 0) && (errno == EINTR)) {
 344                         continue;
 345                 }
 346                 if (i <= 0) {
 347                         if (retries++ == MAX_RETRY)
 348                                 break;
 349                         continue;
 350                 }
 351                 nbytes -= i;
 352                 buf += i;
 353                 retries = 0;
 354         }
 355         if (nbytes == 0)
 356                 rcachep = rcache;
 357         else
 358                 rcachep = NULL;
 359 }
 360 
 361 /*
 362  * Fills buf with random numbers - nbytes is the number of bytes
 363  * to fill-in. Tries to use cached data from the /dev/urandom random number
 364  * generator - if that fails for some reason, it uses srand48(3C)
 365  */
 366 static void
 367 fill_random_bytes(uchar_t *buf, int nbytes)
 368 {
 369         int i;
 370 
 371         if (fd_urand == -1) {
 372                 (void) mutex_lock(&urandmtx);
 373                 /* check again now that we have the mutex */
 374                 if (fd_urand == -1) {
 375                         if ((fd_urand = open(URANDOM_PATH, O_RDONLY)) >= 0)
 376                                 load_cache();
 377                 }
 378                 (void) mutex_unlock(&urandmtx);
 379         }
 380         if (fd_urand >= 0 && rcachep != NULL) {
 381                 int cnt;
 382 
 383                 (void) mutex_lock(&urandmtx);
 384                 if (rcachep != NULL &&
 385                     (rcachep + nbytes) >= (rcache + RCACHE_SIZE))
 386                         load_cache();
 387 
 388                 if (rcachep != NULL) {
 389                         for (cnt = 0; cnt < nbytes; cnt++)
 390                                 *buf++ = *rcachep++;
 391                         (void) mutex_unlock(&urandmtx);
 392                         return;
 393                 }
 394                 (void) mutex_unlock(&urandmtx);
 395         }
 396         for (i = 0; i < nbytes; i++) {
 397                 *buf++ = get_random() & 0xFF;
 398         }
 399 }
 400 
 401 /*
 402  * Unpacks the structure members in "struct uuid" to a char string "uuid_t".
 403  */
 404 void
 405 struct_to_string(uuid_t ptr, struct uuid *uu)
 406 {
 407         uint_t          tmp;
 408         uchar_t         *out = ptr;
 409 
 410         tmp = uu->time_low;
 411         out[3] = (uchar_t)tmp;
 412         tmp >>= 8;
 413         out[2] = (uchar_t)tmp;
 414         tmp >>= 8;
 415         out[1] = (uchar_t)tmp;
 416         tmp >>= 8;
 417         out[0] = (uchar_t)tmp;
 418 
 419         tmp = uu->time_mid;
 420         out[5] = (uchar_t)tmp;
 421         tmp >>= 8;
 422         out[4] = (uchar_t)tmp;
 423 
 424         tmp = uu->time_hi_and_version;
 425         out[7] = (uchar_t)tmp;
 426         tmp >>= 8;
 427         out[6] = (uchar_t)tmp;
 428 
 429         tmp = uu->clock_seq_hi_and_reserved;
 430         out[8] = (uchar_t)tmp;
 431         tmp = uu->clock_seq_low;
 432         out[9] = (uchar_t)tmp;
 433 
 434         (void) memcpy(out+10, uu->node_addr, 6);
 435 
 436 }
 437 
 438 /*
 439  * Packs the values in the "uuid_t" string into "struct uuid".
 440  */
 441 void
 442 string_to_struct(struct uuid *uuid, uuid_t in)
 443 {
 444         uchar_t *ptr;
 445         uint_t  tmp;
 446 
 447         ptr = in;
 448 
 449         tmp = *ptr++;
 450         tmp = (tmp << 8) | *ptr++;
 451         tmp = (tmp << 8) | *ptr++;
 452         tmp = (tmp << 8) | *ptr++;
 453         uuid->time_low = tmp;
 454 
 455         tmp = *ptr++;
 456         tmp = (tmp << 8) | *ptr++;
 457         uuid->time_mid = tmp;
 458 
 459         tmp = *ptr++;
 460         tmp = (tmp << 8) | *ptr++;
 461         uuid->time_hi_and_version = tmp;
 462 
 463         tmp = *ptr++;
 464         uuid->clock_seq_hi_and_reserved = tmp;
 465 
 466         tmp = *ptr++;
 467         uuid->clock_seq_low = tmp;
 468 
 469         (void) memcpy(uuid->node_addr, ptr, 6);
 470 
 471 }
 472 
 473 /*
 474  * Generates UUID based on DCE Version 4
 475  */
 476 void
 477 uuid_generate_random(uuid_t uu)
 478 {
 479         struct uuid     uuid;
 480 
 481         if (uu == NULL)
 482                 return;
 483 
 484         (void) memset(uu, 0, sizeof (uuid_t));
 485         (void) memset(&uuid, 0, sizeof (struct uuid));
 486 
 487         fill_random_bytes(uu, sizeof (uuid_t));
 488         string_to_struct(&uuid, uu);
 489         /*
 490          * This is version 4, so say so in the UUID version field (4 bits)
 491          */
 492         uuid.time_hi_and_version |= (1 << 14);
 493         /*
 494          * we don't want the bit 1 to be set also which is for version 1
 495          */
 496         uuid.time_hi_and_version &= VER1_MASK;
 497 
 498         /*
 499          * The variant for this format is the 2 high bits set to 10,
 500          * so here it is
 501          */
 502         uuid.clock_seq_hi_and_reserved |= 0x80;
 503 
 504         /*
 505          * Set MSB of Ethernet address to 1 to indicate that it was generated
 506          * randomly
 507          */
 508         uuid.node_addr[0] |= 0x80;
 509         struct_to_string(uu, &uuid);
 510 }
 511 
 512 /*
 513  * Generates UUID based on DCE Version 1.
 514  */
 515 void
 516 uuid_generate_time(uuid_t uu)
 517 {
 518         struct  uuid uuid;
 519 
 520         if (uu == NULL)
 521                 return;
 522 
 523         if (uuid_create(&uuid) < 0) {
 524                 uuid_generate_random(uu);
 525                 return;
 526         }
 527 
 528         struct_to_string(uu, &uuid);
 529 }
 530 
 531 /*
 532  * Creates a new UUID. The uuid will be generated based on high-quality
 533  * randomness from /dev/urandom, if available by calling uuid_generate_random.
 534  * If it failed to generate UUID then uuid_generate will call
 535  * uuid_generate_time.
 536  */
 537 void
 538 uuid_generate(uuid_t uu)
 539 {
 540         if (uu == NULL) {
 541                 return;
 542         }
 543         if (fd_urand == -1) {
 544                 (void) mutex_lock(&urandmtx);
 545                 /* check again now that we have the mutex */
 546                 if (fd_urand == -1) {
 547                         if ((fd_urand = open(URANDOM_PATH, O_RDONLY)) >= 0)
 548                                 load_cache();
 549                 }
 550                 (void) mutex_unlock(&urandmtx);
 551         }
 552         if (fd_urand >= 0) {
 553                 uuid_generate_random(uu);
 554         } else {
 555                 (void) uuid_generate_time(uu);
 556         }
 557 }
 558 
 559 /*
 560  * Copies the UUID variable src to dst.
 561  */
 562 void
 563 uuid_copy(uuid_t dst, uuid_t src)
 564 {
 565         (void) memcpy(dst, src, UUID_LEN);
 566 }
 567 
 568 /*
 569  * Sets the value of the supplied uuid variable uu, to the NULL value.
 570  */
 571 void
 572 uuid_clear(uuid_t uu)
 573 {
 574         (void) memset(uu, 0, UUID_LEN);
 575 }
 576 
 577 /*
 578  * This function converts the supplied UUID uu from the internal
 579  * binary format into a 36-byte string (plus trailing null char)
 580  * and stores this value in the character string pointed to by out.
 581  */
 582 static void
 583 uuid_unparse_common(uuid_t uu, char *out, boolean_t upper)
 584 {
 585         struct uuid     uuid;
 586         uint16_t        clock_seq;
 587         char            etheraddr[13];
 588         int             index = 0, i;
 589 
 590         /* basic sanity checking */
 591         if (uu == NULL) {
 592                 return;
 593         }
 594 
 595         string_to_struct(&uuid, uu);
 596         clock_seq = uuid.clock_seq_hi_and_reserved;
 597         clock_seq = (clock_seq  << 8) | uuid.clock_seq_low;
 598         for (i = 0; i < 6; i++) {
 599                 (void) sprintf(&etheraddr[index++], upper ? "%.2X" : "%.2x",
 600                     uuid.node_addr[i]);
 601                 index++;
 602         }
 603         etheraddr[index] = '\0';
 604 
 605         (void) snprintf(out, 25,
 606             upper ? "%08X-%04X-%04X-%04X-" : "%08x-%04x-%04x-%04x-",
 607             uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, clock_seq);
 608         (void) strlcat(out, etheraddr, UUID_PRINTABLE_STRING_LENGTH);
 609 }
 610 
 611 void
 612 uuid_unparse_upper(uuid_t uu, char *out)
 613 {
 614         uuid_unparse_common(uu, out, B_TRUE);
 615 }
 616 
 617 void
 618 uuid_unparse_lower(uuid_t uu, char *out)
 619 {
 620         uuid_unparse_common(uu, out, B_FALSE);
 621 }
 622 
 623 void
 624 uuid_unparse(uuid_t uu, char *out)
 625 {
 626         /*
 627          * Historically uuid_unparse on Solaris returns lower case,
 628          * for compatibility we preserve this behaviour.
 629          */
 630         uuid_unparse_common(uu, out, B_FALSE);
 631 }
 632 
 633 /*
 634  * The uuid_is_null function compares the value of the supplied
 635  * UUID variable uu to the NULL value. If the value is equal
 636  * to the NULL UUID, 1 is returned, otherwise 0 is returned.
 637  */
 638 int
 639 uuid_is_null(uuid_t uu)
 640 {
 641         int             i;
 642         uuid_t          null_uu;
 643 
 644         (void) memset(null_uu, 0, sizeof (uuid_t));
 645         i = memcmp(uu, null_uu, sizeof (uuid_t));
 646         if (i == 0) {
 647                 /* uu is NULL uuid */
 648                 return (1);
 649         } else {
 650                 return (0);
 651         }
 652 }
 653 
 654 /*
 655  * uuid_parse converts the UUID string given by 'in' into the
 656  * internal uuid_t format. The input UUID is a string of the form
 657  * cefa7a9c-1dd2-11b2-8350-880020adbeef in printf(3C) format.
 658  * Upon successfully parsing the input string, UUID is stored
 659  * in the location pointed to by uu
 660  */
 661 int
 662 uuid_parse(char *in, uuid_t uu)
 663 {
 664 
 665         char            *ptr, buf[3];
 666         int             i;
 667         struct uuid     uuid;
 668         uint16_t        clock_seq;
 669 
 670         /* do some sanity checking */
 671         if ((strlen(in) != 36) || (uu == NULL) || (in[36] != '\0')) {
 672                 return (-1);
 673         }
 674 
 675         ptr = in;
 676         for (i = 0; i < 36; i++, ptr++) {
 677                 if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
 678                         if (*ptr != '-') {
 679                                 return (-1);
 680                         }
 681                 } else {
 682                         if (!isxdigit(*ptr)) {
 683                                 return (-1);
 684                         }
 685                 }
 686         }
 687 
 688         uuid.time_low = strtoul(in, NULL, 16);
 689         uuid.time_mid = strtoul(in+9, NULL, 16);
 690         uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
 691         clock_seq = strtoul(in+19, NULL, 16);
 692         uuid.clock_seq_hi_and_reserved = (clock_seq & 0xFF00) >> 8;
 693         uuid.clock_seq_low = (clock_seq & 0xFF);
 694 
 695         ptr = in+24;
 696         buf[2] = '\0';
 697         for (i = 0; i < 6; i++) {
 698                 buf[0] = *ptr++;
 699                 buf[1] = *ptr++;
 700                 uuid.node_addr[i] = strtoul(buf, NULL, 16);
 701         }
 702         struct_to_string(uu, &uuid);
 703         return (0);
 704 }
 705 
 706 /*
 707  * uuid_time extracts the time at which the supplied UUID uu
 708  * was created. This function can only extract the creation
 709  * time for UUIDs created with the uuid_generate_time function.
 710  * The time at which the UUID was created, in seconds and
 711  * microseconds since the epoch is stored in the location
 712  * pointed to by ret_tv.
 713  */
 714 time_t
 715 uuid_time(uuid_t uu, struct timeval *ret_tv)
 716 {
 717         struct uuid     uuid;
 718         uint_t          high;
 719         struct timeval  tv;
 720         u_longlong_t    clock_reg;
 721         uint_t          tmp;
 722         uint8_t         clk;
 723 
 724         string_to_struct(&uuid, uu);
 725         tmp = (uuid.time_hi_and_version & 0xF000) >> 12;
 726         clk = uuid.clock_seq_hi_and_reserved;
 727 
 728         /* check if uu is NULL, Version = 1 of DCE and Variant = 0b10x */
 729         if ((uu == NULL) || ((tmp & 0x01) != 0x01) || ((clk & 0x80) != 0x80)) {
 730                 return (-1);
 731         }
 732         high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
 733         clock_reg = uuid.time_low | ((u_longlong_t)high << 32);
 734 
 735         clock_reg -= (((u_longlong_t)0x01B21DD2) << 32) + 0x13814000;
 736         tv.tv_sec = clock_reg / 10000000;
 737         tv.tv_usec = (clock_reg % 10000000) / 10;
 738 
 739         if (ret_tv) {
 740                 *ret_tv = tv;
 741         }
 742 
 743         return (tv.tv_sec);
 744 }