xref: /illumos-gate/usr/src/lib/libuuid/common/uuid.c (revision ed1ff83ac443ea5f7ed528f59d69a970592977a1)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d62bc4baSyz147064  * Common Development and Distribution License (the "License").
6d62bc4baSyz147064  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d62bc4baSyz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2433f5ff17SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
259d12795fSRobert Mustacchi  * Copyright 2015 Joyent, Inc. All rights reserved.
260b5ce10aSAndy Stormont  * Copyright 2014 Andrew Stormont.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * The copyright in this file is taken from the original Leach & Salz
317c478bd9Sstevel@tonic-gate  * UUID specification, from which this implementation is derived.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
367c478bd9Sstevel@tonic-gate  * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
377c478bd9Sstevel@tonic-gate  * Digital Equipment Corporation, Maynard, Mass.  Copyright (c) 1998
387c478bd9Sstevel@tonic-gate  * Microsoft.  To anyone who acknowledges that this file is provided
397c478bd9Sstevel@tonic-gate  * "AS IS" without any express or implied warranty: permission to use,
407c478bd9Sstevel@tonic-gate  * copy, modify, and distribute this file for any purpose is hereby
417c478bd9Sstevel@tonic-gate  * granted without fee, provided that the above copyright notices and
427c478bd9Sstevel@tonic-gate  * this notice appears in all source code copies, and that none of the
437c478bd9Sstevel@tonic-gate  * names of Open Software Foundation, Inc., Hewlett-Packard Company,
447c478bd9Sstevel@tonic-gate  * or Digital Equipment Corporation be used in advertising or
457c478bd9Sstevel@tonic-gate  * publicity pertaining to distribution of the software without
467c478bd9Sstevel@tonic-gate  * specific, written prior permission.  Neither Open Software
477c478bd9Sstevel@tonic-gate  * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
487c478bd9Sstevel@tonic-gate  * Equipment Corporation makes any representations about the
497c478bd9Sstevel@tonic-gate  * suitability of this software for any purpose.
507c478bd9Sstevel@tonic-gate  */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
53cc1a9a89SRafael Vanoni Polanczyk  * This module is the workhorse for generating abstract
547c478bd9Sstevel@tonic-gate  * UUIDs.  It delegates system-specific tasks (such
557c478bd9Sstevel@tonic-gate  * as obtaining the node identifier or system time)
567c478bd9Sstevel@tonic-gate  * to the sysdep module.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #include <ctype.h>
607c478bd9Sstevel@tonic-gate #include <sys/param.h>
617c478bd9Sstevel@tonic-gate #include <sys/stat.h>
627c478bd9Sstevel@tonic-gate #include <errno.h>
637c478bd9Sstevel@tonic-gate #include <stdio.h>
647c478bd9Sstevel@tonic-gate #include <stdlib.h>
657c478bd9Sstevel@tonic-gate #include <strings.h>
667c478bd9Sstevel@tonic-gate #include <fcntl.h>
677c478bd9Sstevel@tonic-gate #include <unistd.h>
687c478bd9Sstevel@tonic-gate #include <synch.h>
69cc1a9a89SRafael Vanoni Polanczyk #include <sys/mman.h>
707c478bd9Sstevel@tonic-gate #include "uuid_misc.h"
717c478bd9Sstevel@tonic-gate 
72cc1a9a89SRafael Vanoni Polanczyk shared_buffer_t		*data;
737c478bd9Sstevel@tonic-gate 
74cc1a9a89SRafael Vanoni Polanczyk static	uuid_node_t	node_id_cache;
75cc1a9a89SRafael Vanoni Polanczyk static	int		node_init;
76cc1a9a89SRafael Vanoni Polanczyk static	int		file_type;
77cc1a9a89SRafael Vanoni Polanczyk static	int		fd;
787c478bd9Sstevel@tonic-gate 
79cc1a9a89SRafael Vanoni Polanczyk /*
80cc1a9a89SRafael Vanoni Polanczyk  * misc routines
81cc1a9a89SRafael Vanoni Polanczyk  */
82cc1a9a89SRafael Vanoni Polanczyk uint16_t		get_random(void);
83cc1a9a89SRafael Vanoni Polanczyk void			get_current_time(uuid_time_t *);
84cc1a9a89SRafael Vanoni Polanczyk 
857c478bd9Sstevel@tonic-gate void			struct_to_string(uuid_t, struct uuid *);
867c478bd9Sstevel@tonic-gate void			string_to_struct(struct uuid *, uuid_t);
877c478bd9Sstevel@tonic-gate int			get_ethernet_address(uuid_node_t *);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate  * local functions
917c478bd9Sstevel@tonic-gate  */
92cc1a9a89SRafael Vanoni Polanczyk static	int		map_state();
93cc1a9a89SRafael Vanoni Polanczyk static	void		format_uuid(struct uuid *, uint16_t, uuid_time_t,
947c478bd9Sstevel@tonic-gate     uuid_node_t);
957c478bd9Sstevel@tonic-gate static	int		uuid_create(struct uuid *);
967c478bd9Sstevel@tonic-gate static	void		gen_ethernet_address(uuid_node_t *);
97cc1a9a89SRafael Vanoni Polanczyk static	void		revalidate_data(uuid_node_t *);
98cc1a9a89SRafael Vanoni Polanczyk 
997c478bd9Sstevel@tonic-gate /*
100cc1a9a89SRafael Vanoni Polanczyk  * Generates a uuid based on version 1 format.
101cc1a9a89SRafael Vanoni Polanczyk  * Returns 0 on success and -1 on failure.
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate static int
uuid_create(struct uuid * uuid)1047c478bd9Sstevel@tonic-gate uuid_create(struct uuid *uuid)
1057c478bd9Sstevel@tonic-gate {
106cc1a9a89SRafael Vanoni Polanczyk 	uuid_time_t	timestamp;
1077c478bd9Sstevel@tonic-gate 	uuid_node_t	system_node;
108cc1a9a89SRafael Vanoni Polanczyk 	int		ret, non_unique = 0;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	/*
111cc1a9a89SRafael Vanoni Polanczyk 	 * Get the system MAC address and/or cache it
1127c478bd9Sstevel@tonic-gate 	 */
113cc1a9a89SRafael Vanoni Polanczyk 	if (node_init) {
114cc1a9a89SRafael Vanoni Polanczyk 		bcopy(&node_id_cache, &system_node, sizeof (uuid_node_t));
1157c478bd9Sstevel@tonic-gate 	} else {
116cc1a9a89SRafael Vanoni Polanczyk 		gen_ethernet_address(&system_node);
117cc1a9a89SRafael Vanoni Polanczyk 		bcopy(&system_node, &node_id_cache, sizeof (uuid_node_t));
118cc1a9a89SRafael Vanoni Polanczyk 		node_init = 1;
1197c478bd9Sstevel@tonic-gate 	}
1207c478bd9Sstevel@tonic-gate 
121cc1a9a89SRafael Vanoni Polanczyk 	/*
122cc1a9a89SRafael Vanoni Polanczyk 	 * Access the state file, mmap it and initialize the shared lock.
123cc1a9a89SRafael Vanoni Polanczyk 	 * file_type tells us whether we had access to the state file or
124cc1a9a89SRafael Vanoni Polanczyk 	 * created a temporary one.
125cc1a9a89SRafael Vanoni Polanczyk 	 */
126ad2de435SRichard Lowe 	if (map_state() == -1)
127ad2de435SRichard Lowe 		return (-1);
128cc1a9a89SRafael Vanoni Polanczyk 
129cc1a9a89SRafael Vanoni Polanczyk 	/*
130cc1a9a89SRafael Vanoni Polanczyk 	 * Acquire the lock
131cc1a9a89SRafael Vanoni Polanczyk 	 */
132cc1a9a89SRafael Vanoni Polanczyk 	for (;;) {
133cc1a9a89SRafael Vanoni Polanczyk 		if ((ret = mutex_lock(&data->lock)) == 0)
134cc1a9a89SRafael Vanoni Polanczyk 			break;
135cc1a9a89SRafael Vanoni Polanczyk 		else
136cc1a9a89SRafael Vanoni Polanczyk 			switch (ret) {
137cc1a9a89SRafael Vanoni Polanczyk 				case EOWNERDEAD:
138cc1a9a89SRafael Vanoni Polanczyk 					revalidate_data(&system_node);
139cc1a9a89SRafael Vanoni Polanczyk 					(void) mutex_consistent(&data->lock);
140cc1a9a89SRafael Vanoni Polanczyk 					(void) mutex_unlock(&data->lock);
141cc1a9a89SRafael Vanoni Polanczyk 					break;
142cc1a9a89SRafael Vanoni Polanczyk 				case ENOTRECOVERABLE:
143cc1a9a89SRafael Vanoni Polanczyk 					return (ret);
144cc1a9a89SRafael Vanoni Polanczyk 			}
145cc1a9a89SRafael Vanoni Polanczyk 	}
146cc1a9a89SRafael Vanoni Polanczyk 
147cc1a9a89SRafael Vanoni Polanczyk 	/* State file is either new or is temporary, get a random clock seq */
148cc1a9a89SRafael Vanoni Polanczyk 	if (data->state.clock == 0) {
149cc1a9a89SRafael Vanoni Polanczyk 		data->state.clock = get_random();
1507c478bd9Sstevel@tonic-gate 		non_unique++;
1517c478bd9Sstevel@tonic-gate 	}
152cc1a9a89SRafael Vanoni Polanczyk 
153cc1a9a89SRafael Vanoni Polanczyk 	if (memcmp(&system_node, &data->state.node, sizeof (uuid_node_t)) != 0)
154cc1a9a89SRafael Vanoni Polanczyk 		data->state.clock++;
155cc1a9a89SRafael Vanoni Polanczyk 
156cc1a9a89SRafael Vanoni Polanczyk 	get_current_time(&timestamp);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	/*
159cc1a9a89SRafael Vanoni Polanczyk 	 * If timestamp is not set or is not in the past, bump
160cc1a9a89SRafael Vanoni Polanczyk 	 * data->state.clock
1617c478bd9Sstevel@tonic-gate 	 */
162cc1a9a89SRafael Vanoni Polanczyk 	if ((data->state.ts == 0) || (data->state.ts >= timestamp)) {
163cc1a9a89SRafael Vanoni Polanczyk 		data->state.clock++;
164cc1a9a89SRafael Vanoni Polanczyk 		data->state.ts = timestamp;
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	if (non_unique)
1687c478bd9Sstevel@tonic-gate 		system_node.nodeID[0] |= 0x80;
169cc1a9a89SRafael Vanoni Polanczyk 
170cc1a9a89SRafael Vanoni Polanczyk 	/* Stuff fields into the UUID struct */
171cc1a9a89SRafael Vanoni Polanczyk 	format_uuid(uuid, data->state.clock, timestamp, system_node);
172cc1a9a89SRafael Vanoni Polanczyk 
173cc1a9a89SRafael Vanoni Polanczyk 	(void) mutex_unlock(&data->lock);
174cc1a9a89SRafael Vanoni Polanczyk 
1757c478bd9Sstevel@tonic-gate 	return (0);
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate /*
179cc1a9a89SRafael Vanoni Polanczyk  * Fills system_node with Ethernet address if available,
1807c478bd9Sstevel@tonic-gate  * else fills random numbers
1817c478bd9Sstevel@tonic-gate  */
1827c478bd9Sstevel@tonic-gate static void
gen_ethernet_address(uuid_node_t * system_node)1837c478bd9Sstevel@tonic-gate gen_ethernet_address(uuid_node_t *system_node)
1847c478bd9Sstevel@tonic-gate {
1857c478bd9Sstevel@tonic-gate 	uchar_t		node[6];
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	if (get_ethernet_address(system_node) != 0) {
1889d12795fSRobert Mustacchi 		arc4random_buf(node, 6);
1897c478bd9Sstevel@tonic-gate 		(void) memcpy(system_node->nodeID, node, 6);
1907c478bd9Sstevel@tonic-gate 		/*
1917c478bd9Sstevel@tonic-gate 		 * use 8:0:20 with the multicast bit set
1927c478bd9Sstevel@tonic-gate 		 * to avoid namespace collisions.
1937c478bd9Sstevel@tonic-gate 		 */
1947c478bd9Sstevel@tonic-gate 		system_node->nodeID[0] = 0x88;
1957c478bd9Sstevel@tonic-gate 		system_node->nodeID[1] = 0x00;
1967c478bd9Sstevel@tonic-gate 		system_node->nodeID[2] = 0x20;
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /*
201cc1a9a89SRafael Vanoni Polanczyk  * Formats a UUID, given the clock_seq timestamp, and node address.
202cc1a9a89SRafael Vanoni Polanczyk  * Fills in passed-in pointer with the resulting uuid.
2037c478bd9Sstevel@tonic-gate  */
2047c478bd9Sstevel@tonic-gate static void
format_uuid(struct uuid * uuid,uint16_t clock_seq,uuid_time_t timestamp,uuid_node_t node)205cc1a9a89SRafael Vanoni Polanczyk format_uuid(struct uuid *uuid, uint16_t clock_seq,
2067c478bd9Sstevel@tonic-gate     uuid_time_t timestamp, uuid_node_t node)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	/*
2107c478bd9Sstevel@tonic-gate 	 * First set up the first 60 bits from the timestamp
2117c478bd9Sstevel@tonic-gate 	 */
2127c478bd9Sstevel@tonic-gate 	uuid->time_low = (uint32_t)(timestamp & 0xFFFFFFFF);
2137c478bd9Sstevel@tonic-gate 	uuid->time_mid = (uint16_t)((timestamp >> 32) & 0xFFFF);
214cc1a9a89SRafael Vanoni Polanczyk 	uuid->time_hi_and_version = (uint16_t)((timestamp >> 48) & 0x0FFF);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	/*
2177c478bd9Sstevel@tonic-gate 	 * This is version 1, so say so in the UUID version field (4 bits)
2187c478bd9Sstevel@tonic-gate 	 */
2197c478bd9Sstevel@tonic-gate 	uuid->time_hi_and_version |= (1 << 12);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/*
2227c478bd9Sstevel@tonic-gate 	 * Now do the clock sequence
2237c478bd9Sstevel@tonic-gate 	 */
2247c478bd9Sstevel@tonic-gate 	uuid->clock_seq_low = clock_seq & 0xFF;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	/*
2277c478bd9Sstevel@tonic-gate 	 * We must save the most-significant 2 bits for the reserved field
2287c478bd9Sstevel@tonic-gate 	 */
2297c478bd9Sstevel@tonic-gate 	uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	/*
2327c478bd9Sstevel@tonic-gate 	 * The variant for this format is the 2 high bits set to 10,
2337c478bd9Sstevel@tonic-gate 	 * so here it is
2347c478bd9Sstevel@tonic-gate 	 */
2357c478bd9Sstevel@tonic-gate 	uuid->clock_seq_hi_and_reserved |= 0x80;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	/*
2387c478bd9Sstevel@tonic-gate 	 * write result to passed-in pointer
2397c478bd9Sstevel@tonic-gate 	 */
2407c478bd9Sstevel@tonic-gate 	(void) memcpy(&uuid->node_addr, &node, sizeof (uuid->node_addr));
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate /*
244cc1a9a89SRafael Vanoni Polanczyk  * Opens/creates the state file, falling back to a tmp
2457c478bd9Sstevel@tonic-gate  */
2467c478bd9Sstevel@tonic-gate static int
map_state()247cc1a9a89SRafael Vanoni Polanczyk map_state()
2487c478bd9Sstevel@tonic-gate {
249cc1a9a89SRafael Vanoni Polanczyk 	FILE	*tmp;
2507c478bd9Sstevel@tonic-gate 
251cc1a9a89SRafael Vanoni Polanczyk 	/* If file's mapped, return */
252cc1a9a89SRafael Vanoni Polanczyk 	if (file_type != 0)
253cc1a9a89SRafael Vanoni Polanczyk 		return (1);
254cc1a9a89SRafael Vanoni Polanczyk 
255cc1a9a89SRafael Vanoni Polanczyk 	if ((fd = open(STATE_LOCATION, O_RDWR)) < 0) {
256cc1a9a89SRafael Vanoni Polanczyk 		file_type = TEMP_FILE;
257cc1a9a89SRafael Vanoni Polanczyk 
258cc1a9a89SRafael Vanoni Polanczyk 		if ((tmp = tmpfile()) == NULL)
2597c478bd9Sstevel@tonic-gate 			return (-1);
260cc1a9a89SRafael Vanoni Polanczyk 		else
261cc1a9a89SRafael Vanoni Polanczyk 			fd = fileno(tmp);
262cc1a9a89SRafael Vanoni Polanczyk 	} else {
263cc1a9a89SRafael Vanoni Polanczyk 		file_type = STATE_FILE;
2647c478bd9Sstevel@tonic-gate 	}
2657c478bd9Sstevel@tonic-gate 
266cc1a9a89SRafael Vanoni Polanczyk 	(void) ftruncate(fd, (off_t)sizeof (shared_buffer_t));
2677c478bd9Sstevel@tonic-gate 
268cc1a9a89SRafael Vanoni Polanczyk 	/* LINTED - alignment */
269cc1a9a89SRafael Vanoni Polanczyk 	data = (shared_buffer_t *)mmap(NULL, sizeof (shared_buffer_t),
270cc1a9a89SRafael Vanoni Polanczyk 	    PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
271cc1a9a89SRafael Vanoni Polanczyk 
272cc1a9a89SRafael Vanoni Polanczyk 	if (data == MAP_FAILED)
273cc1a9a89SRafael Vanoni Polanczyk 		return (-1);
274cc1a9a89SRafael Vanoni Polanczyk 
275cc1a9a89SRafael Vanoni Polanczyk 	(void) mutex_init(&data->lock, USYNC_PROCESS|LOCK_ROBUST, 0);
276cc1a9a89SRafael Vanoni Polanczyk 
277cc1a9a89SRafael Vanoni Polanczyk 	(void) close(fd);
278cc1a9a89SRafael Vanoni Polanczyk 
279cc1a9a89SRafael Vanoni Polanczyk 	return (1);
280cc1a9a89SRafael Vanoni Polanczyk }
281cc1a9a89SRafael Vanoni Polanczyk 
282cc1a9a89SRafael Vanoni Polanczyk static void
revalidate_data(uuid_node_t * node)283cc1a9a89SRafael Vanoni Polanczyk revalidate_data(uuid_node_t *node)
284cc1a9a89SRafael Vanoni Polanczyk {
285cc1a9a89SRafael Vanoni Polanczyk 	int i;
286cc1a9a89SRafael Vanoni Polanczyk 
287cc1a9a89SRafael Vanoni Polanczyk 	data->state.ts = 0;
288cc1a9a89SRafael Vanoni Polanczyk 
289cc1a9a89SRafael Vanoni Polanczyk 	for (i = 0; i < sizeof (data->state.node.nodeID); i++)
290cc1a9a89SRafael Vanoni Polanczyk 		data->state.node.nodeID[i] = 0;
291cc1a9a89SRafael Vanoni Polanczyk 
292cc1a9a89SRafael Vanoni Polanczyk 	data->state.clock = 0;
293cc1a9a89SRafael Vanoni Polanczyk 
294cc1a9a89SRafael Vanoni Polanczyk 	gen_ethernet_address(node);
295cc1a9a89SRafael Vanoni Polanczyk 	bcopy(node, &node_id_cache, sizeof (uuid_node_t));
296cc1a9a89SRafael Vanoni Polanczyk 	node_init = 1;
297cc1a9a89SRafael Vanoni Polanczyk }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate /*
300cc1a9a89SRafael Vanoni Polanczyk  * Prints a nicely-formatted uuid to stdout.
3017c478bd9Sstevel@tonic-gate  */
3027c478bd9Sstevel@tonic-gate void
uuid_print(struct uuid u)3037c478bd9Sstevel@tonic-gate uuid_print(struct uuid u)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate 	int i;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	(void) printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
3087c478bd9Sstevel@tonic-gate 	    u.time_hi_and_version, u.clock_seq_hi_and_reserved,
3097c478bd9Sstevel@tonic-gate 	    u.clock_seq_low);
3107c478bd9Sstevel@tonic-gate 	for (i = 0; i < 6; i++)
3117c478bd9Sstevel@tonic-gate 		(void) printf("%2.2x", u.node_addr[i]);
3127c478bd9Sstevel@tonic-gate 	(void) printf("\n");
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate /*
316cc1a9a89SRafael Vanoni Polanczyk  * Unpacks the structure members in "struct uuid" to a char string "uuid_t".
3177c478bd9Sstevel@tonic-gate  */
3187c478bd9Sstevel@tonic-gate void
struct_to_string(uuid_t ptr,struct uuid * uu)3197c478bd9Sstevel@tonic-gate struct_to_string(uuid_t ptr, struct uuid *uu)
3207c478bd9Sstevel@tonic-gate {
3217c478bd9Sstevel@tonic-gate 	uint_t		tmp;
3227c478bd9Sstevel@tonic-gate 	uchar_t		*out = ptr;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	tmp = uu->time_low;
3257c478bd9Sstevel@tonic-gate 	out[3] = (uchar_t)tmp;
3267c478bd9Sstevel@tonic-gate 	tmp >>= 8;
3277c478bd9Sstevel@tonic-gate 	out[2] = (uchar_t)tmp;
3287c478bd9Sstevel@tonic-gate 	tmp >>= 8;
3297c478bd9Sstevel@tonic-gate 	out[1] = (uchar_t)tmp;
3307c478bd9Sstevel@tonic-gate 	tmp >>= 8;
3317c478bd9Sstevel@tonic-gate 	out[0] = (uchar_t)tmp;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	tmp = uu->time_mid;
3347c478bd9Sstevel@tonic-gate 	out[5] = (uchar_t)tmp;
3357c478bd9Sstevel@tonic-gate 	tmp >>= 8;
3367c478bd9Sstevel@tonic-gate 	out[4] = (uchar_t)tmp;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	tmp = uu->time_hi_and_version;
3397c478bd9Sstevel@tonic-gate 	out[7] = (uchar_t)tmp;
3407c478bd9Sstevel@tonic-gate 	tmp >>= 8;
3417c478bd9Sstevel@tonic-gate 	out[6] = (uchar_t)tmp;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	tmp = uu->clock_seq_hi_and_reserved;
3447c478bd9Sstevel@tonic-gate 	out[8] = (uchar_t)tmp;
3457c478bd9Sstevel@tonic-gate 	tmp = uu->clock_seq_low;
3467c478bd9Sstevel@tonic-gate 	out[9] = (uchar_t)tmp;
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	(void) memcpy(out+10, uu->node_addr, 6);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate /*
353cc1a9a89SRafael Vanoni Polanczyk  * Packs the values in the "uuid_t" string into "struct uuid".
3547c478bd9Sstevel@tonic-gate  */
3557c478bd9Sstevel@tonic-gate void
string_to_struct(struct uuid * uuid,uuid_t in)3567c478bd9Sstevel@tonic-gate string_to_struct(struct uuid *uuid, uuid_t in)
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate 	uchar_t	*ptr;
3597c478bd9Sstevel@tonic-gate 	uint_t	tmp;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	ptr = in;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	tmp = *ptr++;
3647c478bd9Sstevel@tonic-gate 	tmp = (tmp << 8) | *ptr++;
3657c478bd9Sstevel@tonic-gate 	tmp = (tmp << 8) | *ptr++;
3667c478bd9Sstevel@tonic-gate 	tmp = (tmp << 8) | *ptr++;
3677c478bd9Sstevel@tonic-gate 	uuid->time_low = tmp;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	tmp = *ptr++;
3707c478bd9Sstevel@tonic-gate 	tmp = (tmp << 8) | *ptr++;
3717c478bd9Sstevel@tonic-gate 	uuid->time_mid = tmp;
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	tmp = *ptr++;
3747c478bd9Sstevel@tonic-gate 	tmp = (tmp << 8) | *ptr++;
3757c478bd9Sstevel@tonic-gate 	uuid->time_hi_and_version = tmp;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	tmp = *ptr++;
3787c478bd9Sstevel@tonic-gate 	uuid->clock_seq_hi_and_reserved = tmp;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	tmp = *ptr++;
3817c478bd9Sstevel@tonic-gate 	uuid->clock_seq_low = tmp;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	(void) memcpy(uuid->node_addr, ptr, 6);
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate /*
388cc1a9a89SRafael Vanoni Polanczyk  * Generates UUID based on DCE Version 4
3897c478bd9Sstevel@tonic-gate  */
3907c478bd9Sstevel@tonic-gate void
uuid_generate_random(uuid_t uu)3917c478bd9Sstevel@tonic-gate uuid_generate_random(uuid_t uu)
3927c478bd9Sstevel@tonic-gate {
3937c478bd9Sstevel@tonic-gate 	struct uuid	uuid;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	if (uu == NULL)
3967c478bd9Sstevel@tonic-gate 		return;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	(void) memset(uu, 0, sizeof (uuid_t));
3997c478bd9Sstevel@tonic-gate 	(void) memset(&uuid, 0, sizeof (struct uuid));
4007c478bd9Sstevel@tonic-gate 
4019d12795fSRobert Mustacchi 	arc4random_buf(uu, sizeof (uuid_t));
4027c478bd9Sstevel@tonic-gate 	string_to_struct(&uuid, uu);
403*ed1ff83aSRobert Mustacchi 
4047c478bd9Sstevel@tonic-gate 	/*
4057c478bd9Sstevel@tonic-gate 	 * This is version 4, so say so in the UUID version field (4 bits)
4067c478bd9Sstevel@tonic-gate 	 */
407*ed1ff83aSRobert Mustacchi 	uuid.time_hi_and_version &= 0xfff;
4087c478bd9Sstevel@tonic-gate 	uuid.time_hi_and_version |= (1 << 14);
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	/*
4117c478bd9Sstevel@tonic-gate 	 * The variant for this format is the 2 high bits set to 10,
4127c478bd9Sstevel@tonic-gate 	 * so here it is
4137c478bd9Sstevel@tonic-gate 	 */
414*ed1ff83aSRobert Mustacchi 	uuid.clock_seq_hi_and_reserved &= 0x3f;
4157c478bd9Sstevel@tonic-gate 	uuid.clock_seq_hi_and_reserved |= 0x80;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	struct_to_string(uu, &uuid);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /*
421cc1a9a89SRafael Vanoni Polanczyk  * Generates UUID based on DCE Version 1.
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate void
uuid_generate_time(uuid_t uu)4247c478bd9Sstevel@tonic-gate uuid_generate_time(uuid_t uu)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	struct	uuid uuid;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	if (uu == NULL)
4297c478bd9Sstevel@tonic-gate 		return;
4307c478bd9Sstevel@tonic-gate 
431cc1a9a89SRafael Vanoni Polanczyk 	if (uuid_create(&uuid) < 0) {
4327c478bd9Sstevel@tonic-gate 		uuid_generate_random(uu);
4337c478bd9Sstevel@tonic-gate 		return;
4347c478bd9Sstevel@tonic-gate 	}
435cc1a9a89SRafael Vanoni Polanczyk 
4367c478bd9Sstevel@tonic-gate 	struct_to_string(uu, &uuid);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate /*
440cc1a9a89SRafael Vanoni Polanczyk  * Creates a new UUID. The uuid will be generated based on high-quality
4419d12795fSRobert Mustacchi  * randomness from arc4random(3C).
4427c478bd9Sstevel@tonic-gate  */
4437c478bd9Sstevel@tonic-gate void
uuid_generate(uuid_t uu)4447c478bd9Sstevel@tonic-gate uuid_generate(uuid_t uu)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate 	uuid_generate_random(uu);
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate /*
450cc1a9a89SRafael Vanoni Polanczyk  * Copies the UUID variable src to dst.
4517c478bd9Sstevel@tonic-gate  */
4527c478bd9Sstevel@tonic-gate void
uuid_copy(uuid_t dst,uuid_t src)4537c478bd9Sstevel@tonic-gate uuid_copy(uuid_t dst, uuid_t src)
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate 	(void) memcpy(dst, src, UUID_LEN);
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate /*
459cc1a9a89SRafael Vanoni Polanczyk  * Sets the value of the supplied uuid variable uu, to the NULL value.
4607c478bd9Sstevel@tonic-gate  */
4617c478bd9Sstevel@tonic-gate void
uuid_clear(uuid_t uu)4627c478bd9Sstevel@tonic-gate uuid_clear(uuid_t uu)
4637c478bd9Sstevel@tonic-gate {
4647c478bd9Sstevel@tonic-gate 	(void) memset(uu, 0, UUID_LEN);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate /*
468cc1a9a89SRafael Vanoni Polanczyk  * This function converts the supplied UUID uu from the internal
4697c478bd9Sstevel@tonic-gate  * binary format into a 36-byte string (plus trailing null char)
470cc1a9a89SRafael Vanoni Polanczyk  * and stores this value in the character string pointed to by out.
4717c478bd9Sstevel@tonic-gate  */
4720b5ce10aSAndy Stormont static void
uuid_unparse_common(uuid_t uu,char * out,boolean_t upper)4730b5ce10aSAndy Stormont uuid_unparse_common(uuid_t uu, char *out, boolean_t upper)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate 	struct uuid	uuid;
4767c478bd9Sstevel@tonic-gate 	uint16_t	clock_seq;
4777c478bd9Sstevel@tonic-gate 	char		etheraddr[13];
4787c478bd9Sstevel@tonic-gate 	int		index = 0, i;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	/* basic sanity checking */
4817c478bd9Sstevel@tonic-gate 	if (uu == NULL) {
4827c478bd9Sstevel@tonic-gate 		return;
4837c478bd9Sstevel@tonic-gate 	}
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	string_to_struct(&uuid, uu);
4867c478bd9Sstevel@tonic-gate 	clock_seq = uuid.clock_seq_hi_and_reserved;
4877c478bd9Sstevel@tonic-gate 	clock_seq = (clock_seq  << 8) | uuid.clock_seq_low;
4887c478bd9Sstevel@tonic-gate 	for (i = 0; i < 6; i++) {
4890b5ce10aSAndy Stormont 		(void) sprintf(&etheraddr[index++], upper ? "%.2X" : "%.2x",
4900b5ce10aSAndy Stormont 		    uuid.node_addr[i]);
4917c478bd9Sstevel@tonic-gate 		index++;
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate 	etheraddr[index] = '\0';
4947c478bd9Sstevel@tonic-gate 
4950b5ce10aSAndy Stormont 	(void) snprintf(out, 25,
4960b5ce10aSAndy Stormont 	    upper ? "%08X-%04X-%04X-%04X-" : "%08x-%04x-%04x-%04x-",
497cc1a9a89SRafael Vanoni Polanczyk 	    uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, clock_seq);
4986be356c5Sgz161490 	(void) strlcat(out, etheraddr, UUID_PRINTABLE_STRING_LENGTH);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5010b5ce10aSAndy Stormont void
uuid_unparse_upper(uuid_t uu,char * out)5020b5ce10aSAndy Stormont uuid_unparse_upper(uuid_t uu, char *out)
5030b5ce10aSAndy Stormont {
5040b5ce10aSAndy Stormont 	uuid_unparse_common(uu, out, B_TRUE);
5050b5ce10aSAndy Stormont }
5060b5ce10aSAndy Stormont 
5070b5ce10aSAndy Stormont void
uuid_unparse_lower(uuid_t uu,char * out)5080b5ce10aSAndy Stormont uuid_unparse_lower(uuid_t uu, char *out)
5090b5ce10aSAndy Stormont {
5100b5ce10aSAndy Stormont 	uuid_unparse_common(uu, out, B_FALSE);
5110b5ce10aSAndy Stormont }
5120b5ce10aSAndy Stormont 
5130b5ce10aSAndy Stormont void
uuid_unparse(uuid_t uu,char * out)5140b5ce10aSAndy Stormont uuid_unparse(uuid_t uu, char *out)
5150b5ce10aSAndy Stormont {
5160b5ce10aSAndy Stormont 	/*
5170b5ce10aSAndy Stormont 	 * Historically uuid_unparse on Solaris returns lower case,
5180b5ce10aSAndy Stormont 	 * for compatibility we preserve this behaviour.
5190b5ce10aSAndy Stormont 	 */
5200b5ce10aSAndy Stormont 	uuid_unparse_common(uu, out, B_FALSE);
5210b5ce10aSAndy Stormont }
5220b5ce10aSAndy Stormont 
5237c478bd9Sstevel@tonic-gate /*
524cc1a9a89SRafael Vanoni Polanczyk  * The uuid_is_null function compares the value of the supplied
5257c478bd9Sstevel@tonic-gate  * UUID variable uu to the NULL value. If the value is equal
5267c478bd9Sstevel@tonic-gate  * to the NULL UUID, 1 is returned, otherwise 0 is returned.
5277c478bd9Sstevel@tonic-gate  */
5287c478bd9Sstevel@tonic-gate int
uuid_is_null(uuid_t uu)5297c478bd9Sstevel@tonic-gate uuid_is_null(uuid_t uu)
5307c478bd9Sstevel@tonic-gate {
5317c478bd9Sstevel@tonic-gate 	int		i;
5327c478bd9Sstevel@tonic-gate 	uuid_t		null_uu;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	(void) memset(null_uu, 0, sizeof (uuid_t));
5357c478bd9Sstevel@tonic-gate 	i = memcmp(uu, null_uu, sizeof (uuid_t));
5367c478bd9Sstevel@tonic-gate 	if (i == 0) {
5377c478bd9Sstevel@tonic-gate 		/* uu is NULL uuid */
5387c478bd9Sstevel@tonic-gate 		return (1);
5397c478bd9Sstevel@tonic-gate 	} else {
5407c478bd9Sstevel@tonic-gate 		return (0);
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /*
545cc1a9a89SRafael Vanoni Polanczyk  * uuid_parse converts the UUID string given by 'in' into the
5467c478bd9Sstevel@tonic-gate  * internal uuid_t format. The input UUID is a string of the form
5477c478bd9Sstevel@tonic-gate  * cefa7a9c-1dd2-11b2-8350-880020adbeef in printf(3C) format.
5487c478bd9Sstevel@tonic-gate  * Upon successfully parsing the input string, UUID is stored
5497c478bd9Sstevel@tonic-gate  * in the location pointed to by uu
5507c478bd9Sstevel@tonic-gate  */
5517c478bd9Sstevel@tonic-gate int
uuid_parse(char * in,uuid_t uu)5527c478bd9Sstevel@tonic-gate uuid_parse(char *in, uuid_t uu)
5537c478bd9Sstevel@tonic-gate {
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	char		*ptr, buf[3];
5567c478bd9Sstevel@tonic-gate 	int		i;
5577c478bd9Sstevel@tonic-gate 	struct uuid	uuid;
5587c478bd9Sstevel@tonic-gate 	uint16_t	clock_seq;
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	/* do some sanity checking */
5617c478bd9Sstevel@tonic-gate 	if ((strlen(in) != 36) || (uu == NULL) || (in[36] != '\0')) {
5627c478bd9Sstevel@tonic-gate 		return (-1);
5637c478bd9Sstevel@tonic-gate 	}
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	ptr = in;
5667c478bd9Sstevel@tonic-gate 	for (i = 0; i < 36; i++, ptr++) {
5677c478bd9Sstevel@tonic-gate 		if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
5687c478bd9Sstevel@tonic-gate 			if (*ptr != '-') {
5697c478bd9Sstevel@tonic-gate 				return (-1);
5707c478bd9Sstevel@tonic-gate 			}
5717c478bd9Sstevel@tonic-gate 		} else {
5727c478bd9Sstevel@tonic-gate 			if (!isxdigit(*ptr)) {
5737c478bd9Sstevel@tonic-gate 				return (-1);
5747c478bd9Sstevel@tonic-gate 			}
5757c478bd9Sstevel@tonic-gate 		}
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	uuid.time_low = strtoul(in, NULL, 16);
5797c478bd9Sstevel@tonic-gate 	uuid.time_mid = strtoul(in+9, NULL, 16);
5807c478bd9Sstevel@tonic-gate 	uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
5817c478bd9Sstevel@tonic-gate 	clock_seq = strtoul(in+19, NULL, 16);
5827c478bd9Sstevel@tonic-gate 	uuid.clock_seq_hi_and_reserved = (clock_seq & 0xFF00) >> 8;
5837c478bd9Sstevel@tonic-gate 	uuid.clock_seq_low = (clock_seq & 0xFF);
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	ptr = in+24;
5867c478bd9Sstevel@tonic-gate 	buf[2] = '\0';
5877c478bd9Sstevel@tonic-gate 	for (i = 0; i < 6; i++) {
5887c478bd9Sstevel@tonic-gate 		buf[0] = *ptr++;
5897c478bd9Sstevel@tonic-gate 		buf[1] = *ptr++;
5907c478bd9Sstevel@tonic-gate 		uuid.node_addr[i] = strtoul(buf, NULL, 16);
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate 	struct_to_string(uu, &uuid);
5937c478bd9Sstevel@tonic-gate 	return (0);
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate /*
597cc1a9a89SRafael Vanoni Polanczyk  * uuid_time extracts the time at which the supplied UUID uu
5987c478bd9Sstevel@tonic-gate  * was created. This function can only extract the creation
5997c478bd9Sstevel@tonic-gate  * time for UUIDs created with the uuid_generate_time function.
6007c478bd9Sstevel@tonic-gate  * The time at which the UUID was created, in seconds and
6017c478bd9Sstevel@tonic-gate  * microseconds since the epoch is stored in the location
6027c478bd9Sstevel@tonic-gate  * pointed to by ret_tv.
6037c478bd9Sstevel@tonic-gate  */
6047c478bd9Sstevel@tonic-gate time_t
uuid_time(uuid_t uu,struct timeval * ret_tv)6057c478bd9Sstevel@tonic-gate uuid_time(uuid_t uu, struct timeval *ret_tv)
6067c478bd9Sstevel@tonic-gate {
6077c478bd9Sstevel@tonic-gate 	struct uuid	uuid;
6087c478bd9Sstevel@tonic-gate 	uint_t		high;
6097c478bd9Sstevel@tonic-gate 	struct timeval	tv;
6107c478bd9Sstevel@tonic-gate 	u_longlong_t	clock_reg;
6117c478bd9Sstevel@tonic-gate 	uint_t		tmp;
6127c478bd9Sstevel@tonic-gate 	uint8_t		clk;
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	string_to_struct(&uuid, uu);
6157c478bd9Sstevel@tonic-gate 	tmp = (uuid.time_hi_and_version & 0xF000) >> 12;
6167c478bd9Sstevel@tonic-gate 	clk = uuid.clock_seq_hi_and_reserved;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	/* check if uu is NULL, Version = 1 of DCE and Variant = 0b10x */
6197c478bd9Sstevel@tonic-gate 	if ((uu == NULL) || ((tmp & 0x01) != 0x01) || ((clk & 0x80) != 0x80)) {
6207c478bd9Sstevel@tonic-gate 		return (-1);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 	high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
6237c478bd9Sstevel@tonic-gate 	clock_reg = uuid.time_low | ((u_longlong_t)high << 32);
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	clock_reg -= (((u_longlong_t)0x01B21DD2) << 32) + 0x13814000;
6267c478bd9Sstevel@tonic-gate 	tv.tv_sec = clock_reg / 10000000;
6277c478bd9Sstevel@tonic-gate 	tv.tv_usec = (clock_reg % 10000000) / 10;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	if (ret_tv) {
6307c478bd9Sstevel@tonic-gate 		*ret_tv = tv;
6317c478bd9Sstevel@tonic-gate 	}
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	return (tv.tv_sec);
6347c478bd9Sstevel@tonic-gate }
635