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.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/endian.h>
32 #include <sys/kernel.h>
34 #include <sys/mutex.h>
36 #include <sys/socket.h>
37 #include <sys/sysproto.h>
38 #include <sys/systm.h>
40 #include <sys/vimage.h>
43 #include <net/if_dl.h>
44 #include <net/if_types.h>
48 * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
49 * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
51 * Note that the generator state is itself an UUID, but the time and clock
52 * sequence fields are written in the native byte order.
55 CTASSERT(sizeof(struct uuid
) == 16);
57 /* We use an alternative, more convenient representation in the generator. */
60 uint64_t ll
; /* internal. */
67 uint16_t seq
; /* Big-endian. */
68 uint16_t node
[UUID_NODE_LEN
>>1];
71 CTASSERT(sizeof(struct uuid_private
) == 16);
73 static struct uuid_private uuid_last
;
75 static struct mtx uuid_mutex
;
76 MTX_SYSINIT(uuid_lock
, &uuid_mutex
, "UUID generator mutex lock", MTX_DEF
);
79 * Return the first MAC address we encounter or, if none was found,
80 * construct a sufficiently random multicast address. We don't try
81 * to return the same MAC address as previously returned. We always
82 * generate a new multicast address if no MAC address exists in the
84 * It would be nice to know if 'ifnet' or any of its sub-structures
85 * has been changed in any way. If not, we could simply skip the
86 * scan and safely return the MAC address we returned before.
89 uuid_node(uint16_t *node
)
93 struct sockaddr_dl
*sdl
;
97 TAILQ_FOREACH(ifp
, &V_ifnet
, if_link
) {
98 /* Walk the address list */
99 TAILQ_FOREACH(ifa
, &ifp
->if_addrhead
, ifa_link
) {
100 sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
101 if (sdl
!= NULL
&& sdl
->sdl_family
== AF_LINK
&&
102 sdl
->sdl_type
== IFT_ETHER
) {
103 /* Got a MAC address. */
104 bcopy(LLADDR(sdl
), node
, UUID_NODE_LEN
);
112 for (i
= 0; i
< (UUID_NODE_LEN
>>1); i
++)
113 node
[i
] = (uint16_t)arc4random();
114 *((uint8_t*)node
) |= 0x01;
118 * Get the current time as a 60 bit count of 100-nanosecond intervals
119 * since 00:00:00.00, October 15,1582. We apply a magic offset to convert
120 * the Unix time since 00:00:00.00, January 1, 1970 to the date of the
121 * Gregorian reform to the Christian calendar.
127 uint64_t time
= 0x01B21DD213814000LL
;
130 time
+= (uint64_t)bt
.sec
* 10000000LL;
131 time
+= (10000000LL * (uint32_t)(bt
.frac
>> 32)) >> 32;
132 return (time
& ((1LL << 60) - 1LL));
136 kern_uuidgen(struct uuid
*store
, size_t count
)
138 struct uuid_private uuid
;
142 mtx_lock(&uuid_mutex
);
144 uuid_node(uuid
.node
);
147 if (uuid_last
.time
.ll
== 0LL || uuid_last
.node
[0] != uuid
.node
[0] ||
148 uuid_last
.node
[1] != uuid
.node
[1] ||
149 uuid_last
.node
[2] != uuid
.node
[2])
150 uuid
.seq
= (uint16_t)arc4random() & 0x3fff;
151 else if (uuid_last
.time
.ll
>= time
)
152 uuid
.seq
= (uuid_last
.seq
+ 1) & 0x3fff;
154 uuid
.seq
= uuid_last
.seq
;
157 uuid_last
.time
.ll
= (time
+ count
- 1) & ((1LL << 60) - 1LL);
159 mtx_unlock(&uuid_mutex
);
161 /* Set sequence and variant and deal with byte order. */
162 uuid
.seq
= htobe16(uuid
.seq
| 0x8000);
164 for (n
= 0; n
< count
; n
++) {
165 /* Set time and version (=1). */
166 uuid
.time
.x
.low
= (uint32_t)time
;
167 uuid
.time
.x
.mid
= (uint16_t)(time
>> 32);
168 uuid
.time
.x
.hi
= ((uint16_t)(time
>> 48) & 0xfff) | (1 << 12);
169 store
[n
] = *(struct uuid
*)&uuid
;
176 #ifndef _SYS_SYSPROTO_H_
177 struct uuidgen_args
{
183 uuidgen(struct thread
*td
, struct uuidgen_args
*uap
)
190 * Limit the number of UUIDs that can be created at the same time
191 * to some arbitrary number. This isn't really necessary, but I
192 * like to have some sort of upper-bound that's less than 2G :-)
193 * XXX probably needs to be tunable.
195 if (uap
->count
< 1 || uap
->count
> 2048)
199 store
= malloc(count
* sizeof(struct uuid
), M_TEMP
, M_WAITOK
);
200 kern_uuidgen(store
, count
);
201 error
= copyout(store
, uap
->store
, count
* sizeof(struct uuid
));
207 snprintf_uuid(char *buf
, size_t sz
, struct uuid
*uuid
)
209 struct uuid_private
*id
;
212 id
= (struct uuid_private
*)uuid
;
213 cnt
= snprintf(buf
, sz
, "%08x-%04x-%04x-%04x-%04x%04x%04x",
214 id
->time
.x
.low
, id
->time
.x
.mid
, id
->time
.x
.hi
, be16toh(id
->seq
),
215 be16toh(id
->node
[0]), be16toh(id
->node
[1]), be16toh(id
->node
[2]));
220 printf_uuid(struct uuid
*uuid
)
224 snprintf_uuid(buf
, sizeof(buf
), uuid
);
225 return (printf("%s", buf
));
229 sbuf_printf_uuid(struct sbuf
*sb
, struct uuid
*uuid
)
233 snprintf_uuid(buf
, sizeof(buf
), uuid
);
234 return (sbuf_printf(sb
, "%s", buf
));
238 * Encode/Decode UUID into byte-stream.
239 * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
242 * 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
243 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
245 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
246 * | time_mid | time_hi_and_version |
247 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
248 * |clk_seq_hi_res | clk_seq_low | node (0-1) |
249 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
251 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
255 le_uuid_enc(void *buf
, struct uuid
const *uuid
)
261 le32enc(p
, uuid
->time_low
);
262 le16enc(p
+ 4, uuid
->time_mid
);
263 le16enc(p
+ 6, uuid
->time_hi_and_version
);
264 p
[8] = uuid
->clock_seq_hi_and_reserved
;
265 p
[9] = uuid
->clock_seq_low
;
266 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
267 p
[10 + i
] = uuid
->node
[i
];
271 le_uuid_dec(void const *buf
, struct uuid
*uuid
)
277 uuid
->time_low
= le32dec(p
);
278 uuid
->time_mid
= le16dec(p
+ 4);
279 uuid
->time_hi_and_version
= le16dec(p
+ 6);
280 uuid
->clock_seq_hi_and_reserved
= p
[8];
281 uuid
->clock_seq_low
= p
[9];
282 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
283 uuid
->node
[i
] = p
[10 + i
];
287 be_uuid_enc(void *buf
, struct uuid
const *uuid
)
293 be32enc(p
, uuid
->time_low
);
294 be16enc(p
+ 4, uuid
->time_mid
);
295 be16enc(p
+ 6, uuid
->time_hi_and_version
);
296 p
[8] = uuid
->clock_seq_hi_and_reserved
;
297 p
[9] = uuid
->clock_seq_low
;
298 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
299 p
[10 + i
] = uuid
->node
[i
];
303 be_uuid_dec(void const *buf
, struct uuid
*uuid
)
309 uuid
->time_low
= be32dec(p
);
310 uuid
->time_mid
= le16dec(p
+ 4);
311 uuid
->time_hi_and_version
= be16dec(p
+ 6);
312 uuid
->clock_seq_hi_and_reserved
= p
[8];
313 uuid
->clock_seq_low
= p
[9];
314 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
315 uuid
->node
[i
] = p
[10 + i
];
319 parse_uuid(const char *str
, struct uuid
*uuid
)
324 /* An empty string represents a nil UUID. */
326 bzero(uuid
, sizeof(*uuid
));
330 /* The UUID string representation has a fixed length. */
331 if (strlen(str
) != 36)
335 * We only work with "new" UUIDs. New UUIDs have the form:
336 * 01234567-89ab-cdef-0123-456789abcdef
337 * The so called "old" UUIDs, which we don't support, have the form:
338 * 0123456789ab.cd.ef.01.23.45.67.89.ab
343 n
= sscanf(str
, "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x", c
+ 0, c
+ 1,
344 c
+ 2, c
+ 3, c
+ 4, c
+ 5, c
+ 6, c
+ 7, c
+ 8, c
+ 9, c
+ 10);
345 /* Make sure we have all conversions. */
349 /* Successful scan. Build the UUID. */
350 uuid
->time_low
= c
[0];
351 uuid
->time_mid
= c
[1];
352 uuid
->time_hi_and_version
= c
[2];
353 uuid
->clock_seq_hi_and_reserved
= c
[3];
354 uuid
->clock_seq_low
= c
[4];
355 for (n
= 0; n
< 6; n
++)
356 uuid
->node
[n
] = c
[n
+ 5];
358 /* Check semantics... */
359 return (((c
[3] & 0x80) != 0x00 && /* variant 0? */
360 (c
[3] & 0xc0) != 0x80 && /* variant 1? */
361 (c
[3] & 0xe0) != 0xc0) ? EINVAL
: 0); /* variant 2? */