1 /* $NetBSD: kern_uuid.c,v 1.15 2008/07/02 14:47:34 matt Exp $ */
4 * Copyright (c) 2002 Marcel Moolenaar
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * $FreeBSD: /repoman/r/ncvs/src/sys/kern/kern_uuid.c,v 1.7 2004/01/12 13:34:11 rse Exp $
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: kern_uuid.c,v 1.15 2008/07/02 14:47:34 matt Exp $");
34 #include <sys/param.h>
35 #include <sys/endian.h>
36 #include <sys/kernel.h>
37 #include <sys/mutex.h>
38 #include <sys/socket.h>
39 #include <sys/systm.h>
44 #include <sys/mount.h>
45 #include <sys/syscallargs.h>
49 #include <net/if_dl.h>
50 #include <net/if_types.h>
54 * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
55 * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
57 * Note that the generator state is itself an UUID, but the time and clock
58 * sequence fields are written in the native byte order.
61 CTASSERT(sizeof(struct uuid
) == 16);
63 /* We use an alternative, more convenient representation in the generator. */
66 uint64_t ll
; /* internal. */
73 uint16_t seq
; /* Big-endian. */
74 uint16_t node
[UUID_NODE_LEN
>>1];
77 CTASSERT(sizeof(struct uuid_private
) == 16);
79 static struct uuid_private uuid_last
;
81 /* "UUID generator mutex lock" */
82 static kmutex_t uuid_mutex
;
88 mutex_init(&uuid_mutex
, MUTEX_DEFAULT
, IPL_NONE
);
92 * Return the first MAC address we encounter or, if none was found,
93 * construct a sufficiently random multicast address. We don't try
94 * to return the same MAC address as previously returned. We always
95 * generate a new multicast address if no MAC address exists in the
97 * It would be nice to know if 'ifnet' or any of its sub-structures
98 * has been changed in any way. If not, we could simply skip the
99 * scan and safely return the MAC address we returned before.
102 uuid_node(uint16_t *node
)
106 struct sockaddr_dl
*sdl
;
110 KERNEL_LOCK(1, NULL
);
112 /* Walk the address list */
113 IFADDR_FOREACH(ifa
, ifp
) {
114 sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
115 if (sdl
!= NULL
&& sdl
->sdl_family
== AF_LINK
&&
116 sdl
->sdl_type
== IFT_ETHER
) {
117 /* Got a MAC address. */
118 memcpy(node
, CLLADDR(sdl
), UUID_NODE_LEN
);
119 KERNEL_UNLOCK_ONE(NULL
);
125 KERNEL_UNLOCK_ONE(NULL
);
128 for (i
= 0; i
< (UUID_NODE_LEN
>>1); i
++)
129 node
[i
] = (uint16_t)arc4random();
130 *((uint8_t*)node
) |= 0x01;
134 * Get the current time as a 60 bit count of 100-nanosecond intervals
135 * since 00:00:00.00, October 15,1582. We apply a magic offset to convert
136 * the Unix time since 00:00:00.00, January 1, 1970 to the date of the
137 * Gregorian reform to the Christian calendar.
140 * At present, NetBSD has no timespec source, only timeval sources. So,
147 uint64_t xtime
= 0x01B21DD213814000LL
;
150 xtime
+= (uint64_t)tv
.tv_sec
* 10000000LL;
151 xtime
+= (uint64_t)(10 * tv
.tv_usec
);
152 return (xtime
& ((1LL << 60) - 1LL));
156 * Internal routine to actually generate the UUID.
159 uuid_generate(struct uuid_private
*uuid
, uint64_t *timep
, int count
)
163 mutex_enter(&uuid_mutex
);
165 uuid_node(uuid
->node
);
169 if (uuid_last
.time
.ll
== 0LL || uuid_last
.node
[0] != uuid
->node
[0] ||
170 uuid_last
.node
[1] != uuid
->node
[1] ||
171 uuid_last
.node
[2] != uuid
->node
[2])
172 uuid
->seq
= (uint16_t)arc4random() & 0x3fff;
173 else if (uuid_last
.time
.ll
>= xtime
)
174 uuid
->seq
= (uuid_last
.seq
+ 1) & 0x3fff;
176 uuid
->seq
= uuid_last
.seq
;
179 uuid_last
.time
.ll
= (xtime
+ count
- 1) & ((1LL << 60) - 1LL);
181 mutex_exit(&uuid_mutex
);
185 kern_uuidgen(struct uuid
*store
, int count
, bool to_user
)
187 struct uuid_private uuid
;
193 /* Generate the base UUID. */
194 uuid_generate(&uuid
, &xtime
, count
);
196 /* Set sequence and variant and deal with byte order. */
197 uuid
.seq
= htobe16(uuid
.seq
| 0x8000);
199 for (i
= 0; i
< count
; xtime
++, i
++) {
200 /* Set time and version (=1) and deal with byte order. */
201 uuid
.time
.x
.low
= (uint32_t)xtime
;
202 uuid
.time
.x
.mid
= (uint16_t)(xtime
>> 32);
203 uuid
.time
.x
.hi
= ((uint16_t)(xtime
>> 48) & 0xfff) | (1 << 12);
205 error
= copyout(&uuid
, store
+ i
, sizeof(uuid
));
209 memcpy(store
+ i
, &uuid
, sizeof(uuid
));
217 sys_uuidgen(struct lwp
*l
, const struct sys_uuidgen_args
*uap
, register_t
*retval
)
220 * Limit the number of UUIDs that can be created at the same time
221 * to some arbitrary number. This isn't really necessary, but I
222 * like to have some sort of upper-bound that's less than 2G :-)
223 * XXX needs to be tunable.
225 if (SCARG(uap
,count
) < 1 || SCARG(uap
,count
) > 2048)
228 return kern_uuidgen(SCARG(uap
, store
), SCARG(uap
,count
), true);
232 uuidgen(struct uuid
*store
, int count
)
234 return kern_uuidgen(store
,count
, false);
238 uuid_snprintf(char *buf
, size_t sz
, const struct uuid
*uuid
)
240 const struct uuid_private
*id
;
243 id
= (const struct uuid_private
*)uuid
;
244 cnt
= snprintf(buf
, sz
, "%08x-%04x-%04x-%04x-%04x%04x%04x",
245 id
->time
.x
.low
, id
->time
.x
.mid
, id
->time
.x
.hi
, be16toh(id
->seq
),
246 be16toh(id
->node
[0]), be16toh(id
->node
[1]), be16toh(id
->node
[2]));
251 uuid_printf(const struct uuid
*uuid
)
253 char buf
[UUID_STR_LEN
];
255 (void) uuid_snprintf(buf
, sizeof(buf
), uuid
);
261 * Encode/Decode UUID into octet-stream.
262 * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
265 * 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
266 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
268 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
269 * | time_mid | time_hi_and_version |
270 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
271 * |clk_seq_hi_res | clk_seq_low | node (0-1) |
272 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
274 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
278 uuid_enc_le(void *buf
, const struct uuid
*uuid
)
283 le32enc(p
, uuid
->time_low
);
284 le16enc(p
+ 4, uuid
->time_mid
);
285 le16enc(p
+ 6, uuid
->time_hi_and_version
);
286 p
[8] = uuid
->clock_seq_hi_and_reserved
;
287 p
[9] = uuid
->clock_seq_low
;
288 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
289 p
[10 + i
] = uuid
->node
[i
];
293 uuid_dec_le(void const *buf
, struct uuid
*uuid
)
295 const uint8_t *p
= buf
;
298 uuid
->time_low
= le32dec(p
);
299 uuid
->time_mid
= le16dec(p
+ 4);
300 uuid
->time_hi_and_version
= le16dec(p
+ 6);
301 uuid
->clock_seq_hi_and_reserved
= p
[8];
302 uuid
->clock_seq_low
= p
[9];
303 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
304 uuid
->node
[i
] = p
[10 + i
];
308 uuid_enc_be(void *buf
, const struct uuid
*uuid
)
313 be32enc(p
, uuid
->time_low
);
314 be16enc(p
+ 4, uuid
->time_mid
);
315 be16enc(p
+ 6, uuid
->time_hi_and_version
);
316 p
[8] = uuid
->clock_seq_hi_and_reserved
;
317 p
[9] = uuid
->clock_seq_low
;
318 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
319 p
[10 + i
] = uuid
->node
[i
];
323 uuid_dec_be(void const *buf
, struct uuid
*uuid
)
325 const uint8_t *p
= buf
;
328 uuid
->time_low
= be32dec(p
);
329 uuid
->time_mid
= be16dec(p
+ 4);
330 uuid
->time_hi_and_version
= be16dec(p
+ 6);
331 uuid
->clock_seq_hi_and_reserved
= p
[8];
332 uuid
->clock_seq_low
= p
[9];
333 for (i
= 0; i
< _UUID_NODE_LEN
; i
++)
334 uuid
->node
[i
] = p
[10 + i
];