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