2 * Copyright (c) 2002 Marcel Moolenaar
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: src/sys/kern/kern_uuid.c,v 1.13 2007/04/23 12:53:00 pjd Exp $
27 * $DragonFly: src/sys/kern/kern_uuid.c,v 1.1 2007/06/16 18:55:27 dillon Exp $
30 #include <sys/param.h>
31 #include <sys/endian.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
36 #include <sys/socket.h>
37 #include <sys/sysproto.h>
42 * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
43 * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
45 * Note that the generator state is itself an UUID, but the time and clock
46 * sequence fields are written in the native byte order.
49 /* We use an alternative, more convenient representation in the generator. */
52 uint64_t ll
; /* internal. */
59 uint16_t seq
; /* Big-endian. */
60 uint16_t node
[UUID_NODE_LEN
>>1];
65 static struct uuid_private uuid_last
;
67 static struct mtx uuid_mutex
;
68 MTX_SYSINIT(uuid_lock
, &uuid_mutex
, "UUID generator mutex lock", MTX_DEF
);
71 * Return the first MAC address we encounter or, if none was found,
72 * construct a sufficiently random multicast address. We don't try
73 * to return the same MAC address as previously returned. We always
74 * generate a new multicast address if no MAC address exists in the
76 * It would be nice to know if 'ifnet' or any of its sub-structures
77 * has been changed in any way. If not, we could simply skip the
78 * scan and safely return the MAC address we returned before.
81 uuid_node(uint16_t *node
)
85 struct sockaddr_dl
*sdl
;
89 TAILQ_FOREACH(ifp
, &ifnet
, if_link
) {
90 /* Walk the address list */
91 TAILQ_FOREACH(ifa
, &ifp
->if_addrhead
, ifa_link
) {
92 sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
93 if (sdl
!= NULL
&& sdl
->sdl_family
== AF_LINK
&&
94 sdl
->sdl_type
== IFT_ETHER
) {
95 /* Got a MAC address. */
96 bcopy(LLADDR(sdl
), node
, UUID_NODE_LEN
);
104 for (i
= 0; i
< (UUID_NODE_LEN
>>1); i
++)
105 node
[i
] = (uint16_t)arc4random();
106 *((uint8_t*)node
) |= 0x01;
110 * Get the current time as a 60 bit count of 100-nanosecond intervals
111 * since 00:00:00.00, October 15,1582. We apply a magic offset to convert
112 * the Unix time since 00:00:00.00, January 1, 1970 to the date of the
113 * Gregorian reform to the Christian calendar.
119 uint64_t time
= 0x01B21DD213814000LL
;
122 time
+= (uint64_t)bt
.sec
* 10000000LL;
123 time
+= (10000000LL * (uint32_t)(bt
.frac
>> 32)) >> 32;
124 return (time
& ((1LL << 60) - 1LL));
128 kern_uuidgen(struct uuid
*store
, size_t count
)
130 struct uuid_private uuid
;
134 mtx_lock(&uuid_mutex
);
136 uuid_node(uuid
.node
);
139 if (uuid_last
.time
.ll
== 0LL || uuid_last
.node
[0] != uuid
.node
[0] ||
140 uuid_last
.node
[1] != uuid
.node
[1] ||
141 uuid_last
.node
[2] != uuid
.node
[2])
142 uuid
.seq
= (uint16_t)arc4random() & 0x3fff;
143 else if (uuid_last
.time
.ll
>= time
)
144 uuid
.seq
= (uuid_last
.seq
+ 1) & 0x3fff;
146 uuid
.seq
= uuid_last
.seq
;
149 uuid_last
.time
.ll
= (time
+ count
- 1) & ((1LL << 60) - 1LL);
151 mtx_unlock(&uuid_mutex
);
153 /* Set sequence and variant and deal with byte order. */
154 uuid
.seq
= htobe16(uuid
.seq
| 0x8000);
156 for (n
= 0; n
< count
; n
++) {
157 /* Set time and version (=1). */
158 uuid
.time
.x
.low
= (uint32_t)time
;
159 uuid
.time
.x
.mid
= (uint16_t)(time
>> 32);
160 uuid
.time
.x
.hi
= ((uint16_t)(time
>> 48) & 0xfff) | (1 << 12);
161 store
[n
] = *(struct uuid
*)&uuid
;
168 #ifndef _SYS_SYSPROTO_H_
169 struct uuidgen_args
{
175 uuidgen(struct thread
*td
, struct uuidgen_args
*uap
)
182 * Limit the number of UUIDs that can be created at the same time
183 * to some arbitrary number. This isn't really necessary, but I
184 * like to have some sort of upper-bound that's less than 2G :-)
185 * XXX probably needs to be tunable.
187 if (uap
->count
< 1 || uap
->count
> 2048)
191 store
= malloc(count
* sizeof(struct uuid
), M_TEMP
, M_WAITOK
);
192 kern_uuidgen(store
, count
);
193 error
= copyout(store
, uap
->store
, count
* sizeof(struct uuid
));
201 snprintf_uuid(char *buf
, size_t sz
, struct uuid
*uuid
)
203 struct uuid_private
*id
;
206 id
= (struct uuid_private
*)uuid
;
207 cnt
= ksnprintf(buf
, sz
, "%08x-%04x-%04x-%04x-%04x%04x%04x",
208 id
->time
.x
.low
, id
->time
.x
.mid
, id
->time
.x
.hi
, be16toh(id
->seq
),
209 be16toh(id
->node
[0]), be16toh(id
->node
[1]), be16toh(id
->node
[2]));
214 printf_uuid(struct uuid
*uuid
)
218 snprintf_uuid(buf
, sizeof(buf
), uuid
);
219 return (kprintf("%s", buf
));
223 sbuf_printf_uuid(struct sbuf
*sb
, struct uuid
*uuid
)
227 snprintf_uuid(buf
, sizeof(buf
), uuid
);
228 return (sbuf_printf(sb
, "%s", buf
));
232 * Encode/Decode UUID into byte-stream.
233 * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
236 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
237 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
239 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
240 * | time_mid | time_hi_and_version |
241 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
242 * |clk_seq_hi_res | clk_seq_low | node (0-1) |
243 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
245 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
249 le_uuid_enc(void *buf
, struct uuid
const *uuid
)
255 le32enc(p
, uuid
->time_low
);
256 le16enc(p
+ 4, uuid
->time_mid
);
257 le16enc(p
+ 6, uuid
->time_hi_and_version
);
258 p
[8] = uuid
->clock_seq_hi_and_reserved
;
259 p
[9] = uuid
->clock_seq_low
;
260 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
261 p
[10 + i
] = uuid
->node
[i
];
265 le_uuid_dec(void const *buf
, struct uuid
*uuid
)
271 uuid
->time_low
= le32dec(p
);
272 uuid
->time_mid
= le16dec(p
+ 4);
273 uuid
->time_hi_and_version
= le16dec(p
+ 6);
274 uuid
->clock_seq_hi_and_reserved
= p
[8];
275 uuid
->clock_seq_low
= p
[9];
276 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
277 uuid
->node
[i
] = p
[10 + i
];
281 be_uuid_enc(void *buf
, struct uuid
const *uuid
)
287 be32enc(p
, uuid
->time_low
);
288 be16enc(p
+ 4, uuid
->time_mid
);
289 be16enc(p
+ 6, uuid
->time_hi_and_version
);
290 p
[8] = uuid
->clock_seq_hi_and_reserved
;
291 p
[9] = uuid
->clock_seq_low
;
292 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
293 p
[10 + i
] = uuid
->node
[i
];
297 be_uuid_dec(void const *buf
, struct uuid
*uuid
)
303 uuid
->time_low
= be32dec(p
);
304 uuid
->time_mid
= le16dec(p
+ 4);
305 uuid
->time_hi_and_version
= be16dec(p
+ 6);
306 uuid
->clock_seq_hi_and_reserved
= p
[8];
307 uuid
->clock_seq_low
= p
[9];
308 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
309 uuid
->node
[i
] = p
[10 + i
];
313 parse_uuid(const char *str
, struct uuid
*uuid
)
318 /* An empty string represents a nil UUID. */
320 bzero(uuid
, sizeof(*uuid
));
324 /* The UUID string representation has a fixed length. */
325 if (strlen(str
) != 36)
329 * We only work with "new" UUIDs. New UUIDs have the form:
330 * 01234567-89ab-cdef-0123-456789abcdef
331 * The so called "old" UUIDs, which we don't support, have the form:
332 * 0123456789ab.cd.ef.01.23.45.67.89.ab
337 n
= ksscanf(str
, "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x", c
+ 0, c
+ 1,
338 c
+ 2, c
+ 3, c
+ 4, c
+ 5, c
+ 6, c
+ 7, c
+ 8, c
+ 9, c
+ 10);
339 /* Make sure we have all conversions. */
343 /* Successful scan. Build the UUID. */
344 uuid
->time_low
= c
[0];
345 uuid
->time_mid
= c
[1];
346 uuid
->time_hi_and_version
= c
[2];
347 uuid
->clock_seq_hi_and_reserved
= c
[3];
348 uuid
->clock_seq_low
= c
[4];
349 for (n
= 0; n
< 6; n
++)
350 uuid
->node
[n
] = c
[n
+ 5];
352 /* Check semantics... */
353 return (((c
[3] & 0x80) != 0x00 && /* variant 0? */
354 (c
[3] & 0xc0) != 0x80 && /* variant 1? */
355 (c
[3] & 0xe0) != 0xc0) ? EINVAL
: 0); /* variant 2? */