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.
25*9d12795fSRobert 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(×tamp);
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) {
188*9d12795fSRobert 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
401*9d12795fSRobert Mustacchi arc4random_buf(uu, sizeof (uuid_t));
4027c478bd9Sstevel@tonic-gate string_to_struct(&uuid, uu);
4037c478bd9Sstevel@tonic-gate /*
4047c478bd9Sstevel@tonic-gate * This is version 4, so say so in the UUID version field (4 bits)
4057c478bd9Sstevel@tonic-gate */
4067c478bd9Sstevel@tonic-gate uuid.time_hi_and_version |= (1 << 14);
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate * we don't want the bit 1 to be set also which is for version 1
4097c478bd9Sstevel@tonic-gate */
4107c478bd9Sstevel@tonic-gate uuid.time_hi_and_version &= VER1_MASK;
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate * The variant for this format is the 2 high bits set to 10,
4147c478bd9Sstevel@tonic-gate * so here it is
4157c478bd9Sstevel@tonic-gate */
4167c478bd9Sstevel@tonic-gate uuid.clock_seq_hi_and_reserved |= 0x80;
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate * Set MSB of Ethernet address to 1 to indicate that it was generated
4207c478bd9Sstevel@tonic-gate * randomly
4217c478bd9Sstevel@tonic-gate */
4227c478bd9Sstevel@tonic-gate uuid.node_addr[0] |= 0x80;
4237c478bd9Sstevel@tonic-gate struct_to_string(uu, &uuid);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate /*
427cc1a9a89SRafael Vanoni Polanczyk * Generates UUID based on DCE Version 1.
4287c478bd9Sstevel@tonic-gate */
4297c478bd9Sstevel@tonic-gate void
uuid_generate_time(uuid_t uu)4307c478bd9Sstevel@tonic-gate uuid_generate_time(uuid_t uu)
4317c478bd9Sstevel@tonic-gate {
4327c478bd9Sstevel@tonic-gate struct uuid uuid;
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate if (uu == NULL)
4357c478bd9Sstevel@tonic-gate return;
4367c478bd9Sstevel@tonic-gate
437cc1a9a89SRafael Vanoni Polanczyk if (uuid_create(&uuid) < 0) {
4387c478bd9Sstevel@tonic-gate uuid_generate_random(uu);
4397c478bd9Sstevel@tonic-gate return;
4407c478bd9Sstevel@tonic-gate }
441cc1a9a89SRafael Vanoni Polanczyk
4427c478bd9Sstevel@tonic-gate struct_to_string(uu, &uuid);
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate /*
446cc1a9a89SRafael Vanoni Polanczyk * Creates a new UUID. The uuid will be generated based on high-quality
447*9d12795fSRobert Mustacchi * randomness from arc4random(3C).
4487c478bd9Sstevel@tonic-gate */
4497c478bd9Sstevel@tonic-gate void
uuid_generate(uuid_t uu)4507c478bd9Sstevel@tonic-gate uuid_generate(uuid_t uu)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate uuid_generate_random(uu);
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate /*
456cc1a9a89SRafael Vanoni Polanczyk * Copies the UUID variable src to dst.
4577c478bd9Sstevel@tonic-gate */
4587c478bd9Sstevel@tonic-gate void
uuid_copy(uuid_t dst,uuid_t src)4597c478bd9Sstevel@tonic-gate uuid_copy(uuid_t dst, uuid_t src)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate (void) memcpy(dst, src, UUID_LEN);
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate
4647c478bd9Sstevel@tonic-gate /*
465cc1a9a89SRafael Vanoni Polanczyk * Sets the value of the supplied uuid variable uu, to the NULL value.
4667c478bd9Sstevel@tonic-gate */
4677c478bd9Sstevel@tonic-gate void
uuid_clear(uuid_t uu)4687c478bd9Sstevel@tonic-gate uuid_clear(uuid_t uu)
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate (void) memset(uu, 0, UUID_LEN);
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate /*
474cc1a9a89SRafael Vanoni Polanczyk * This function converts the supplied UUID uu from the internal
4757c478bd9Sstevel@tonic-gate * binary format into a 36-byte string (plus trailing null char)
476cc1a9a89SRafael Vanoni Polanczyk * and stores this value in the character string pointed to by out.
4777c478bd9Sstevel@tonic-gate */
4780b5ce10aSAndy Stormont static void
uuid_unparse_common(uuid_t uu,char * out,boolean_t upper)4790b5ce10aSAndy Stormont uuid_unparse_common(uuid_t uu, char *out, boolean_t upper)
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate struct uuid uuid;
4827c478bd9Sstevel@tonic-gate uint16_t clock_seq;
4837c478bd9Sstevel@tonic-gate char etheraddr[13];
4847c478bd9Sstevel@tonic-gate int index = 0, i;
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate /* basic sanity checking */
4877c478bd9Sstevel@tonic-gate if (uu == NULL) {
4887c478bd9Sstevel@tonic-gate return;
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate string_to_struct(&uuid, uu);
4927c478bd9Sstevel@tonic-gate clock_seq = uuid.clock_seq_hi_and_reserved;
4937c478bd9Sstevel@tonic-gate clock_seq = (clock_seq << 8) | uuid.clock_seq_low;
4947c478bd9Sstevel@tonic-gate for (i = 0; i < 6; i++) {
4950b5ce10aSAndy Stormont (void) sprintf(ðeraddr[index++], upper ? "%.2X" : "%.2x",
4960b5ce10aSAndy Stormont uuid.node_addr[i]);
4977c478bd9Sstevel@tonic-gate index++;
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate etheraddr[index] = '\0';
5007c478bd9Sstevel@tonic-gate
5010b5ce10aSAndy Stormont (void) snprintf(out, 25,
5020b5ce10aSAndy Stormont upper ? "%08X-%04X-%04X-%04X-" : "%08x-%04x-%04x-%04x-",
503cc1a9a89SRafael Vanoni Polanczyk uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, clock_seq);
5046be356c5Sgz161490 (void) strlcat(out, etheraddr, UUID_PRINTABLE_STRING_LENGTH);
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate
5070b5ce10aSAndy Stormont void
uuid_unparse_upper(uuid_t uu,char * out)5080b5ce10aSAndy Stormont uuid_unparse_upper(uuid_t uu, char *out)
5090b5ce10aSAndy Stormont {
5100b5ce10aSAndy Stormont uuid_unparse_common(uu, out, B_TRUE);
5110b5ce10aSAndy Stormont }
5120b5ce10aSAndy Stormont
5130b5ce10aSAndy Stormont void
uuid_unparse_lower(uuid_t uu,char * out)5140b5ce10aSAndy Stormont uuid_unparse_lower(uuid_t uu, char *out)
5150b5ce10aSAndy Stormont {
5160b5ce10aSAndy Stormont uuid_unparse_common(uu, out, B_FALSE);
5170b5ce10aSAndy Stormont }
5180b5ce10aSAndy Stormont
5190b5ce10aSAndy Stormont void
uuid_unparse(uuid_t uu,char * out)5200b5ce10aSAndy Stormont uuid_unparse(uuid_t uu, char *out)
5210b5ce10aSAndy Stormont {
5220b5ce10aSAndy Stormont /*
5230b5ce10aSAndy Stormont * Historically uuid_unparse on Solaris returns lower case,
5240b5ce10aSAndy Stormont * for compatibility we preserve this behaviour.
5250b5ce10aSAndy Stormont */
5260b5ce10aSAndy Stormont uuid_unparse_common(uu, out, B_FALSE);
5270b5ce10aSAndy Stormont }
5280b5ce10aSAndy Stormont
5297c478bd9Sstevel@tonic-gate /*
530cc1a9a89SRafael Vanoni Polanczyk * The uuid_is_null function compares the value of the supplied
5317c478bd9Sstevel@tonic-gate * UUID variable uu to the NULL value. If the value is equal
5327c478bd9Sstevel@tonic-gate * to the NULL UUID, 1 is returned, otherwise 0 is returned.
5337c478bd9Sstevel@tonic-gate */
5347c478bd9Sstevel@tonic-gate int
uuid_is_null(uuid_t uu)5357c478bd9Sstevel@tonic-gate uuid_is_null(uuid_t uu)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate int i;
5387c478bd9Sstevel@tonic-gate uuid_t null_uu;
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate (void) memset(null_uu, 0, sizeof (uuid_t));
5417c478bd9Sstevel@tonic-gate i = memcmp(uu, null_uu, sizeof (uuid_t));
5427c478bd9Sstevel@tonic-gate if (i == 0) {
5437c478bd9Sstevel@tonic-gate /* uu is NULL uuid */
5447c478bd9Sstevel@tonic-gate return (1);
5457c478bd9Sstevel@tonic-gate } else {
5467c478bd9Sstevel@tonic-gate return (0);
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate /*
551cc1a9a89SRafael Vanoni Polanczyk * uuid_parse converts the UUID string given by 'in' into the
5527c478bd9Sstevel@tonic-gate * internal uuid_t format. The input UUID is a string of the form
5537c478bd9Sstevel@tonic-gate * cefa7a9c-1dd2-11b2-8350-880020adbeef in printf(3C) format.
5547c478bd9Sstevel@tonic-gate * Upon successfully parsing the input string, UUID is stored
5557c478bd9Sstevel@tonic-gate * in the location pointed to by uu
5567c478bd9Sstevel@tonic-gate */
5577c478bd9Sstevel@tonic-gate int
uuid_parse(char * in,uuid_t uu)5587c478bd9Sstevel@tonic-gate uuid_parse(char *in, uuid_t uu)
5597c478bd9Sstevel@tonic-gate {
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate char *ptr, buf[3];
5627c478bd9Sstevel@tonic-gate int i;
5637c478bd9Sstevel@tonic-gate struct uuid uuid;
5647c478bd9Sstevel@tonic-gate uint16_t clock_seq;
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate /* do some sanity checking */
5677c478bd9Sstevel@tonic-gate if ((strlen(in) != 36) || (uu == NULL) || (in[36] != '\0')) {
5687c478bd9Sstevel@tonic-gate return (-1);
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate ptr = in;
5727c478bd9Sstevel@tonic-gate for (i = 0; i < 36; i++, ptr++) {
5737c478bd9Sstevel@tonic-gate if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
5747c478bd9Sstevel@tonic-gate if (*ptr != '-') {
5757c478bd9Sstevel@tonic-gate return (-1);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate } else {
5787c478bd9Sstevel@tonic-gate if (!isxdigit(*ptr)) {
5797c478bd9Sstevel@tonic-gate return (-1);
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate uuid.time_low = strtoul(in, NULL, 16);
5857c478bd9Sstevel@tonic-gate uuid.time_mid = strtoul(in+9, NULL, 16);
5867c478bd9Sstevel@tonic-gate uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
5877c478bd9Sstevel@tonic-gate clock_seq = strtoul(in+19, NULL, 16);
5887c478bd9Sstevel@tonic-gate uuid.clock_seq_hi_and_reserved = (clock_seq & 0xFF00) >> 8;
5897c478bd9Sstevel@tonic-gate uuid.clock_seq_low = (clock_seq & 0xFF);
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate ptr = in+24;
5927c478bd9Sstevel@tonic-gate buf[2] = '\0';
5937c478bd9Sstevel@tonic-gate for (i = 0; i < 6; i++) {
5947c478bd9Sstevel@tonic-gate buf[0] = *ptr++;
5957c478bd9Sstevel@tonic-gate buf[1] = *ptr++;
5967c478bd9Sstevel@tonic-gate uuid.node_addr[i] = strtoul(buf, NULL, 16);
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate struct_to_string(uu, &uuid);
5997c478bd9Sstevel@tonic-gate return (0);
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate /*
603cc1a9a89SRafael Vanoni Polanczyk * uuid_time extracts the time at which the supplied UUID uu
6047c478bd9Sstevel@tonic-gate * was created. This function can only extract the creation
6057c478bd9Sstevel@tonic-gate * time for UUIDs created with the uuid_generate_time function.
6067c478bd9Sstevel@tonic-gate * The time at which the UUID was created, in seconds and
6077c478bd9Sstevel@tonic-gate * microseconds since the epoch is stored in the location
6087c478bd9Sstevel@tonic-gate * pointed to by ret_tv.
6097c478bd9Sstevel@tonic-gate */
6107c478bd9Sstevel@tonic-gate time_t
uuid_time(uuid_t uu,struct timeval * ret_tv)6117c478bd9Sstevel@tonic-gate uuid_time(uuid_t uu, struct timeval *ret_tv)
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate struct uuid uuid;
6147c478bd9Sstevel@tonic-gate uint_t high;
6157c478bd9Sstevel@tonic-gate struct timeval tv;
6167c478bd9Sstevel@tonic-gate u_longlong_t clock_reg;
6177c478bd9Sstevel@tonic-gate uint_t tmp;
6187c478bd9Sstevel@tonic-gate uint8_t clk;
6197c478bd9Sstevel@tonic-gate
6207c478bd9Sstevel@tonic-gate string_to_struct(&uuid, uu);
6217c478bd9Sstevel@tonic-gate tmp = (uuid.time_hi_and_version & 0xF000) >> 12;
6227c478bd9Sstevel@tonic-gate clk = uuid.clock_seq_hi_and_reserved;
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate /* check if uu is NULL, Version = 1 of DCE and Variant = 0b10x */
6257c478bd9Sstevel@tonic-gate if ((uu == NULL) || ((tmp & 0x01) != 0x01) || ((clk & 0x80) != 0x80)) {
6267c478bd9Sstevel@tonic-gate return (-1);
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
6297c478bd9Sstevel@tonic-gate clock_reg = uuid.time_low | ((u_longlong_t)high << 32);
6307c478bd9Sstevel@tonic-gate
6317c478bd9Sstevel@tonic-gate clock_reg -= (((u_longlong_t)0x01B21DD2) << 32) + 0x13814000;
6327c478bd9Sstevel@tonic-gate tv.tv_sec = clock_reg / 10000000;
6337c478bd9Sstevel@tonic-gate tv.tv_usec = (clock_reg % 10000000) / 10;
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate if (ret_tv) {
6367c478bd9Sstevel@tonic-gate *ret_tv = tv;
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate
6397c478bd9Sstevel@tonic-gate return (tv.tv_sec);
6407c478bd9Sstevel@tonic-gate }
641