The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_uuid.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2002 Marcel Moolenaar
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  *
    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.
   14  *
   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.
   25  *
   26  * $FreeBSD: releng/5.1/sys/kern/kern_uuid.c 108172 2002-12-22 05:35:03Z hsu $
   27  */
   28 
   29 #include <sys/param.h>
   30 #include <sys/endian.h>
   31 #include <sys/kernel.h>
   32 #include <sys/lock.h>
   33 #include <sys/mutex.h>
   34 #include <sys/sbuf.h>
   35 #include <sys/socket.h>
   36 #include <sys/sysproto.h>
   37 #include <sys/systm.h>
   38 #include <sys/uuid.h>
   39 
   40 #include <net/if.h>
   41 #include <net/if_dl.h>
   42 #include <net/if_types.h>
   43 
   44 /*
   45  * See also:
   46  *      http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
   47  *      http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
   48  *
   49  * Note that the generator state is itself an UUID, but the time and clock
   50  * sequence fields are written in the native byte order.
   51  */
   52 
   53 CTASSERT(sizeof(struct uuid) == 16);
   54 
   55 /* We use an alternative, more convenient representation in the generator. */
   56 struct uuid_private {
   57         union {
   58                 uint64_t        ll;             /* internal. */
   59                 struct {
   60                         uint32_t        low;
   61                         uint16_t        mid;
   62                         uint16_t        hi;
   63                 } x;
   64         } time;
   65         uint16_t        seq;                    /* Big-endian. */
   66         uint16_t        node[UUID_NODE_LEN>>1];
   67 };
   68 
   69 CTASSERT(sizeof(struct uuid_private) == 16);
   70 
   71 static struct uuid_private uuid_last;
   72 
   73 static struct mtx uuid_mutex;
   74 MTX_SYSINIT(uuid_lock, &uuid_mutex, "UUID generator mutex lock", MTX_DEF);
   75 
   76 /*
   77  * Return the first MAC address we encounter or, if none was found,
   78  * construct a sufficiently random multicast address. We don't try
   79  * to return the same MAC address as previously returned. We always
   80  * generate a new multicast address if no MAC address exists in the
   81  * system.
   82  * It would be nice to know if 'ifnet' or any of its sub-structures
   83  * has been changed in any way. If not, we could simply skip the
   84  * scan and safely return the MAC address we returned before.
   85  */
   86 static void
   87 uuid_node(uint16_t *node)
   88 {
   89         struct ifnet *ifp;
   90         struct ifaddr *ifa;
   91         struct sockaddr_dl *sdl;
   92         int i;
   93 
   94         IFNET_RLOCK();
   95         TAILQ_FOREACH(ifp, &ifnet, if_link) {
   96                 /* Walk the address list */
   97                 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
   98                         sdl = (struct sockaddr_dl*)ifa->ifa_addr;
   99                         if (sdl != NULL && sdl->sdl_family == AF_LINK &&
  100                             sdl->sdl_type == IFT_ETHER) {
  101                                 /* Got a MAC address. */
  102                                 bcopy(LLADDR(sdl), node, UUID_NODE_LEN);
  103                                 IFNET_RUNLOCK();
  104                                 return;
  105                         }
  106                 }
  107         }
  108         IFNET_RUNLOCK();
  109 
  110         for (i = 0; i < (UUID_NODE_LEN>>1); i++)
  111                 node[i] = (uint16_t)arc4random();
  112         *((uint8_t*)node) |= 0x80;
  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, Januari 1, 1970 to the date of the
  119  * Gregorian reform to the Christian calendar.
  120  */
  121 static uint64_t
  122 uuid_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 _SYS_SYSPROTO_H_
  134 struct uuidgen_args {
  135         struct uuid *store;
  136         int     count;
  137 };
  138 #endif
  139 
  140 int
  141 uuidgen(struct thread *td, struct uuidgen_args *uap)
  142 {
  143         struct uuid_private uuid;
  144         uint64_t time;
  145         int error;
  146 
  147         /*
  148          * Limit the number of UUIDs that can be created at the same time
  149          * to some arbitrary number. This isn't really necessary, but I
  150          * like to have some sort of upper-bound that's less than 2G :-)
  151          * XXX needs to be tunable.
  152          */
  153         if (uap->count < 1 || uap->count > 2048)
  154                 return (EINVAL);
  155 
  156         /* XXX: pre-validate accessibility to the whole of the UUID store? */
  157 
  158         mtx_lock(&uuid_mutex);
  159 
  160         uuid_node(uuid.node);
  161         time = uuid_time();
  162 
  163         if (uuid_last.time.ll == 0LL || uuid_last.node[0] != uuid.node[0] ||
  164             uuid_last.node[1] != uuid.node[1] ||
  165             uuid_last.node[2] != uuid.node[2])
  166                 uuid.seq = (uint16_t)arc4random() & 0x3fff;
  167         else if (uuid_last.time.ll >= time)
  168                 uuid.seq = (uuid_last.seq + 1) & 0x3fff;
  169         else
  170                 uuid.seq = uuid_last.seq;
  171 
  172         uuid_last = uuid;
  173         uuid_last.time.ll = (time + uap->count - 1) & ((1LL << 60) - 1LL);
  174 
  175         mtx_unlock(&uuid_mutex);
  176 
  177         /* Set sequence and variant and deal with byte order. */
  178         uuid.seq = htobe16(uuid.seq | 0x8000);
  179 
  180         /* XXX: this should copyout larger chunks at a time. */
  181         do {
  182                 /* Set time and version (=1) and deal with byte order. */
  183                 uuid.time.x.low = (uint32_t)time;
  184                 uuid.time.x.mid = (uint16_t)(time >> 32);
  185                 uuid.time.x.hi = ((uint16_t)(time >> 48) & 0xfff) | (1 << 12);
  186                 error = copyout(&uuid, uap->store, sizeof(uuid));
  187                 uap->store++;
  188                 uap->count--;
  189                 time++;
  190         } while (uap->count > 0 && !error);
  191 
  192         return (error);
  193 }
  194 
  195 int
  196 snprintf_uuid(char *buf, size_t sz, struct uuid *uuid)
  197 {
  198         struct uuid_private *id;
  199         int cnt;
  200 
  201         id = (struct uuid_private *)uuid;
  202         cnt = snprintf(buf, sz, "%08x-%04x-%04x-%04x-%04x%04x%04x",
  203             id->time.x.low, id->time.x.mid, id->time.x.hi, be16toh(id->seq),
  204             be16toh(id->node[0]), be16toh(id->node[1]), be16toh(id->node[2]));
  205         return (cnt);
  206 }
  207 
  208 int
  209 printf_uuid(struct uuid *uuid)
  210 {
  211         char buf[38];
  212 
  213         snprintf_uuid(buf, sizeof(buf), uuid);
  214         return (printf("%s", buf));
  215 }
  216 
  217 int
  218 sbuf_printf_uuid(struct sbuf *sb, struct uuid *uuid)
  219 {
  220         char buf[38];
  221 
  222         snprintf_uuid(buf, sizeof(buf), uuid);
  223         return (sbuf_printf(sb, "%s", buf));
  224 }

Cache object: 20b12b5b22c6ce84d47c211ba86558eb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.