source: rtems-libbsd/freebsd/sys/kern/kern_uuid.c @ d4bf70e

55-freebsd-126-freebsd-12
Last change on this file since d4bf70e was d4bf70e, checked in by Sebastian Huber <sebastian.huber@…>, on Nov 15, 2018 at 9:06:00 AM

Disable or make static kern_* functions

  • Property mode set to 100644
File size: 11.4 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5 *
6 * Copyright (c) 2002 Marcel Moolenaar
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <sys/param.h>
35#include <sys/endian.h>
36#include <sys/kernel.h>
37#include <sys/lock.h>
38#include <sys/mutex.h>
39#include <sys/sbuf.h>
40#include <sys/socket.h>
41#include <sys/sysproto.h>
42#include <sys/systm.h>
43#include <sys/jail.h>
44#include <sys/uuid.h>
45
46#include <net/if.h>
47#include <net/if_dl.h>
48#include <net/if_types.h>
49#include <net/vnet.h>
50
51/*
52 * See also:
53 *      http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
54 *      http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
55 *
56 * Note that the generator state is itself an UUID, but the time and clock
57 * sequence fields are written in the native byte order.
58 */
59
60CTASSERT(sizeof(struct uuid) == 16);
61
62/* We use an alternative, more convenient representation in the generator. */
63struct uuid_private {
64        union {
65                uint64_t        ll;     /* internal, for uuid_last only */
66                struct {
67                        uint32_t        low;
68                        uint16_t        mid;
69                        uint16_t        hi;
70                } x;
71        } time;
72        uint16_t        seq;                    /* Big-endian. */
73        uint16_t        node[UUID_NODE_LEN>>1];
74};
75
76CTASSERT(sizeof(struct uuid_private) == 16);
77
78struct uuid_macaddr {
79        uint16_t        state;
80#define UUID_ETHER_EMPTY        0
81#define UUID_ETHER_RANDOM       1
82#define UUID_ETHER_UNIQUE       2
83        uint16_t        node[UUID_NODE_LEN>>1];
84};
85
86static struct uuid_private uuid_last;
87
88#define UUID_NETHER     4
89static struct uuid_macaddr uuid_ether[UUID_NETHER];
90
91static struct mtx uuid_mutex;
92MTX_SYSINIT(uuid_lock, &uuid_mutex, "UUID generator mutex lock", MTX_DEF);
93
94/*
95 * Return the first MAC address added in the array. If it's empty, then
96 * construct a sufficiently random multicast MAC address first. Any
97 * addresses added later will bump the random MAC address up tp the next
98 * index.
99 */
100static void
101uuid_node(uint16_t *node)
102{
103        int i;
104
105        if (uuid_ether[0].state == UUID_ETHER_EMPTY) {
106                for (i = 0; i < (UUID_NODE_LEN>>1); i++)
107                        uuid_ether[0].node[i] = (uint16_t)arc4random();
108                *((uint8_t*)uuid_ether[0].node) |= 0x01;
109                uuid_ether[0].state = UUID_ETHER_RANDOM;
110        }
111        for (i = 0; i < (UUID_NODE_LEN>>1); i++)
112                node[i] = uuid_ether[0].node[i];
113}
114
115/*
116 * Get the current time as a 60 bit count of 100-nanosecond intervals
117 * since 00:00:00.00, October 15,1582. We apply a magic offset to convert
118 * the Unix time since 00:00:00.00, January 1, 1970 to the date of the
119 * Gregorian reform to the Christian calendar.
120 */
121static uint64_t
122uuid_time(void)
123{
124        struct bintime bt;
125        uint64_t time = 0x01B21DD213814000LL;
126
127        bintime(&bt);
128        time += (uint64_t)bt.sec * 10000000LL;
129        time += (10000000LL * (uint32_t)(bt.frac >> 32)) >> 32;
130        return (time & ((1LL << 60) - 1LL));
131}
132
133#ifndef __rtems__
134struct uuid *
135kern_uuidgen(struct uuid *store, size_t count)
136{
137        struct uuid_private uuid;
138        uint64_t time;
139        size_t n;
140
141        mtx_lock(&uuid_mutex);
142
143        uuid_node(uuid.node);
144        time = uuid_time();
145
146        if (uuid_last.time.ll == 0LL || uuid_last.node[0] != uuid.node[0] ||
147            uuid_last.node[1] != uuid.node[1] ||
148            uuid_last.node[2] != uuid.node[2])
149                uuid.seq = (uint16_t)arc4random() & 0x3fff;
150        else if (uuid_last.time.ll >= time)
151                uuid.seq = (uuid_last.seq + 1) & 0x3fff;
152        else
153                uuid.seq = uuid_last.seq;
154
155        uuid_last = uuid;
156        uuid_last.time.ll = (time + count - 1) & ((1LL << 60) - 1LL);
157
158        mtx_unlock(&uuid_mutex);
159
160        /* Set sequence and variant and deal with byte order. */
161        uuid.seq = htobe16(uuid.seq | 0x8000);
162
163        for (n = 0; n < count; n++) {
164                /* Set time and version (=1). */
165                uuid.time.x.low = (uint32_t)time;
166                uuid.time.x.mid = (uint16_t)(time >> 32);
167                uuid.time.x.hi = ((uint16_t)(time >> 48) & 0xfff) | (1 << 12);
168                store[n] = *(struct uuid *)&uuid;
169                time++;
170        }
171
172        return (store);
173}
174
175#ifndef _SYS_SYSPROTO_H_
176struct uuidgen_args {
177        struct uuid *store;
178        int     count;
179};
180#endif
181int
182sys_uuidgen(struct thread *td, struct uuidgen_args *uap)
183{
184        struct uuid *store;
185        size_t count;
186        int error;
187
188        /*
189         * Limit the number of UUIDs that can be created at the same time
190         * to some arbitrary number. This isn't really necessary, but I
191         * like to have some sort of upper-bound that's less than 2G :-)
192         * XXX probably needs to be tunable.
193         */
194        if (uap->count < 1 || uap->count > 2048)
195                return (EINVAL);
196
197        count = uap->count;
198        store = malloc(count * sizeof(struct uuid), M_TEMP, M_WAITOK);
199        kern_uuidgen(store, count);
200        error = copyout(store, uap->store, count * sizeof(struct uuid));
201        free(store, M_TEMP);
202        return (error);
203}
204#endif /* __rtems__ */
205
206int
207uuid_ether_add(const uint8_t *addr)
208{
209        int i, sum;
210
211        /*
212         * Validate input. No multicast (flag 0x1), no locally administered
213         * (flag 0x2) and no 'all-zeroes' addresses.
214         */
215        if (addr[0] & 0x03)
216                return (EINVAL);
217        sum = 0;
218        for (i = 0; i < UUID_NODE_LEN; i++)
219                sum += addr[i];
220        if (sum == 0)
221                return (EINVAL);
222
223        mtx_lock(&uuid_mutex);
224
225        /* Make sure the MAC isn't known already and that there's space. */
226        i = 0;
227        while (i < UUID_NETHER && uuid_ether[i].state == UUID_ETHER_UNIQUE) {
228                if (!bcmp(addr, uuid_ether[i].node, UUID_NODE_LEN)) {
229                        mtx_unlock(&uuid_mutex);
230                        return (EEXIST);
231                }
232                i++;
233        }
234        if (i == UUID_NETHER) {
235                mtx_unlock(&uuid_mutex);
236                return (ENOSPC);
237        }
238
239        /* Insert MAC at index, moving the non-empty entry if possible. */
240        if (uuid_ether[i].state == UUID_ETHER_RANDOM && i < UUID_NETHER - 1)
241                uuid_ether[i + 1] = uuid_ether[i];
242        uuid_ether[i].state = UUID_ETHER_UNIQUE;
243        bcopy(addr, uuid_ether[i].node, UUID_NODE_LEN);
244        mtx_unlock(&uuid_mutex);
245        return (0);
246}
247
248int
249uuid_ether_del(const uint8_t *addr)
250{
251        int i;
252
253        mtx_lock(&uuid_mutex);
254        i = 0;
255        while (i < UUID_NETHER && uuid_ether[i].state == UUID_ETHER_UNIQUE &&
256            bcmp(addr, uuid_ether[i].node, UUID_NODE_LEN))
257                i++;
258        if (i == UUID_NETHER || uuid_ether[i].state != UUID_ETHER_UNIQUE) {
259                mtx_unlock(&uuid_mutex);
260                return (ENOENT);
261        }
262
263        /* Remove it by shifting higher index entries down. */
264        while (i < UUID_NETHER - 1 && uuid_ether[i].state != UUID_ETHER_EMPTY) {
265                uuid_ether[i] = uuid_ether[i + 1];
266                i++;
267        }
268        if (uuid_ether[i].state != UUID_ETHER_EMPTY) {
269                uuid_ether[i].state = UUID_ETHER_EMPTY;
270                bzero(uuid_ether[i].node, UUID_NODE_LEN);
271        }
272        mtx_unlock(&uuid_mutex);
273        return (0);
274}
275
276int
277snprintf_uuid(char *buf, size_t sz, struct uuid *uuid)
278{
279        struct uuid_private *id;
280        int cnt;
281
282        id = (struct uuid_private *)uuid;
283        cnt = snprintf(buf, sz, "%08x-%04x-%04x-%04x-%04x%04x%04x",
284            id->time.x.low, id->time.x.mid, id->time.x.hi, be16toh(id->seq),
285            be16toh(id->node[0]), be16toh(id->node[1]), be16toh(id->node[2]));
286        return (cnt);
287}
288
289int
290printf_uuid(struct uuid *uuid)
291{
292        char buf[38];
293
294        snprintf_uuid(buf, sizeof(buf), uuid);
295        return (printf("%s", buf));
296}
297
298int
299sbuf_printf_uuid(struct sbuf *sb, struct uuid *uuid)
300{
301        char buf[38];
302
303        snprintf_uuid(buf, sizeof(buf), uuid);
304        return (sbuf_printf(sb, "%s", buf));
305}
306
307/*
308 * Encode/Decode UUID into byte-stream.
309 *   http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
310 *
311 * 0                   1                   2                   3
312 *   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
313 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
314 *  |                          time_low                             |
315 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
316 *  |       time_mid                |         time_hi_and_version   |
317 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
318 *  |clk_seq_hi_res |  clk_seq_low  |         node (0-1)            |
319 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
320 *  |                         node (2-5)                            |
321 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
322 */
323
324void
325le_uuid_enc(void *buf, struct uuid const *uuid)
326{
327        u_char *p;
328        int i;
329
330        p = buf;
331        le32enc(p, uuid->time_low);
332        le16enc(p + 4, uuid->time_mid);
333        le16enc(p + 6, uuid->time_hi_and_version);
334        p[8] = uuid->clock_seq_hi_and_reserved;
335        p[9] = uuid->clock_seq_low;
336        for (i = 0; i < _UUID_NODE_LEN; i++)
337                p[10 + i] = uuid->node[i];
338}
339
340void
341le_uuid_dec(void const *buf, struct uuid *uuid)
342{
343        u_char const *p;
344        int i;
345
346        p = buf;
347        uuid->time_low = le32dec(p);
348        uuid->time_mid = le16dec(p + 4);
349        uuid->time_hi_and_version = le16dec(p + 6);
350        uuid->clock_seq_hi_and_reserved = p[8];
351        uuid->clock_seq_low = p[9];
352        for (i = 0; i < _UUID_NODE_LEN; i++)
353                uuid->node[i] = p[10 + i];
354}
355
356void
357be_uuid_enc(void *buf, struct uuid const *uuid)
358{
359        u_char *p;
360        int i;
361
362        p = buf;
363        be32enc(p, uuid->time_low);
364        be16enc(p + 4, uuid->time_mid);
365        be16enc(p + 6, uuid->time_hi_and_version);
366        p[8] = uuid->clock_seq_hi_and_reserved;
367        p[9] = uuid->clock_seq_low;
368        for (i = 0; i < _UUID_NODE_LEN; i++)
369                p[10 + i] = uuid->node[i];
370}
371
372void
373be_uuid_dec(void const *buf, struct uuid *uuid)
374{
375        u_char const *p;
376        int i;
377
378        p = buf;
379        uuid->time_low = be32dec(p);
380        uuid->time_mid = be16dec(p + 4);
381        uuid->time_hi_and_version = be16dec(p + 6);
382        uuid->clock_seq_hi_and_reserved = p[8];
383        uuid->clock_seq_low = p[9];
384        for (i = 0; i < _UUID_NODE_LEN; i++)
385                uuid->node[i] = p[10 + i];
386}
387
388int
389parse_uuid(const char *str, struct uuid *uuid)
390{
391        u_int c[11];
392        int n;
393
394        /* An empty string represents a nil UUID. */
395        if (*str == '\0') {
396                bzero(uuid, sizeof(*uuid));
397                return (0);
398        }
399
400        /* The UUID string representation has a fixed length. */
401        if (strlen(str) != 36)
402                return (EINVAL);
403
404        /*
405         * We only work with "new" UUIDs. New UUIDs have the form:
406         *      01234567-89ab-cdef-0123-456789abcdef
407         * The so called "old" UUIDs, which we don't support, have the form:
408         *      0123456789ab.cd.ef.01.23.45.67.89.ab
409         */
410        if (str[8] != '-')
411                return (EINVAL);
412
413        n = sscanf(str, "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x", c + 0, c + 1,
414            c + 2, c + 3, c + 4, c + 5, c + 6, c + 7, c + 8, c + 9, c + 10);
415        /* Make sure we have all conversions. */
416        if (n != 11)
417                return (EINVAL);
418
419        /* Successful scan. Build the UUID. */
420        uuid->time_low = c[0];
421        uuid->time_mid = c[1];
422        uuid->time_hi_and_version = c[2];
423        uuid->clock_seq_hi_and_reserved = c[3];
424        uuid->clock_seq_low = c[4];
425        for (n = 0; n < 6; n++)
426                uuid->node[n] = c[n + 5];
427
428        /* Check semantics... */
429        return (((c[3] & 0x80) != 0x00 &&               /* variant 0? */
430            (c[3] & 0xc0) != 0x80 &&                    /* variant 1? */
431            (c[3] & 0xe0) != 0xc0) ? EINVAL : 0);       /* variant 2? */
432}
433
434int
435uuidcmp(const struct uuid *uuid1, const struct uuid *uuid2)
436{
437
438        return (memcmp(uuid1, uuid2, sizeof(struct uuid)));
439}
Note: See TracBrowser for help on using the repository browser.