1*37ddeb55Smartinh /* $OpenBSD: uuid.c,v 1.4 2010/06/27 18:19:36 martinh Exp $ */ 25d465952Smartinh /* 35d465952Smartinh * Copyright (c) 2002, Stockholms Universitet 45d465952Smartinh * (Stockholm University, Stockholm Sweden) 55d465952Smartinh * All rights reserved. 65d465952Smartinh * 75d465952Smartinh * Redistribution and use in source and binary forms, with or without 85d465952Smartinh * modification, are permitted provided that the following conditions 95d465952Smartinh * are met: 105d465952Smartinh * 115d465952Smartinh * 1. Redistributions of source code must retain the above copyright 125d465952Smartinh * notice, this list of conditions and the following disclaimer. 135d465952Smartinh * 145d465952Smartinh * 2. Redistributions in binary form must reproduce the above copyright 155d465952Smartinh * notice, this list of conditions and the following disclaimer in the 165d465952Smartinh * documentation and/or other materials provided with the distribution. 175d465952Smartinh * 185d465952Smartinh * 3. Neither the name of the university nor the names of its contributors 195d465952Smartinh * may be used to endorse or promote products derived from this software 205d465952Smartinh * without specific prior written permission. 215d465952Smartinh * 225d465952Smartinh * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 235d465952Smartinh * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 245d465952Smartinh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 255d465952Smartinh * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 265d465952Smartinh * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 275d465952Smartinh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 285d465952Smartinh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 295d465952Smartinh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 305d465952Smartinh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 315d465952Smartinh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 325d465952Smartinh * POSSIBILITY OF SUCH DAMAGE. 335d465952Smartinh */ 345d465952Smartinh 355d465952Smartinh /* 365d465952Smartinh * NCS/DCE/AFS/GUID generator 375d465952Smartinh * 385d465952Smartinh * for more information about DCE UUID, see 395d465952Smartinh * <http://www.opengroup.org/onlinepubs/9629399/apdxa.htm> 405d465952Smartinh * 415d465952Smartinh * Note, the Microsoft GUID is a DCE UUID, but it seems like they 425d465952Smartinh * folded in the seq num with the node part. That would explain how 435d465952Smartinh * the reserved field have a bit pattern 110 when reserved is a 2 bit 445d465952Smartinh * field. 455d465952Smartinh * 465d465952Smartinh * XXX should hash the node address for privacy issues 475d465952Smartinh */ 485d465952Smartinh 495d465952Smartinh #include <sys/types.h> 505d465952Smartinh #include <sys/socket.h> 515d465952Smartinh #include <netinet/in.h> 525d465952Smartinh #include <net/if.h> 535d465952Smartinh #include <net/if_types.h> 545d465952Smartinh #include <net/if_dl.h> 555d465952Smartinh #include <sys/file.h> 565d465952Smartinh 575d465952Smartinh #include <fcntl.h> 585d465952Smartinh #include <ifaddrs.h> 595d465952Smartinh #include <stdio.h> 605d465952Smartinh #include <stdlib.h> 615d465952Smartinh #include <string.h> 625d465952Smartinh #include <unistd.h> 635d465952Smartinh 645d465952Smartinh #include "uuid.h" 655d465952Smartinh 665d465952Smartinh static uint32_t seq_num; 675d465952Smartinh static struct timeval last_time; 685d465952Smartinh static int32_t counter; 695d465952Smartinh static char nodeaddr[6]; 705d465952Smartinh 715d465952Smartinh enum { UUID_NODE_MULTICAST = 0x80 }; 725d465952Smartinh 735d465952Smartinh static int 745d465952Smartinh time_cmp(struct timeval *tv1, struct timeval *tv2) 755d465952Smartinh { 765d465952Smartinh if (tv1->tv_sec > tv2->tv_sec) 775d465952Smartinh return -1; 785d465952Smartinh if (tv1->tv_sec < tv2->tv_sec) 795d465952Smartinh return 1; 805d465952Smartinh if (tv1->tv_usec > tv2->tv_usec) 815d465952Smartinh return -1; 825d465952Smartinh if (tv1->tv_usec < tv2->tv_usec) 835d465952Smartinh return 1; 845d465952Smartinh return 0; 855d465952Smartinh } 865d465952Smartinh 875d465952Smartinh static void 885d465952Smartinh get_node_addr(char *addr) 895d465952Smartinh { 905d465952Smartinh struct ifaddrs *ifa, *ifa0; 915d465952Smartinh int found_mac = 0; 925d465952Smartinh 935d465952Smartinh if (getifaddrs(&ifa0) != 0) 945d465952Smartinh ifa0 = NULL; 955d465952Smartinh 965d465952Smartinh for (ifa = ifa0; ifa != NULL && !found_mac; ifa = ifa->ifa_next) { 975d465952Smartinh if (ifa->ifa_addr == NULL) 985d465952Smartinh continue; 995d465952Smartinh 1005d465952Smartinh #if IFF_LOOPBACK 1015d465952Smartinh if (ifa->ifa_flags & IFF_LOOPBACK) 1025d465952Smartinh continue; 1035d465952Smartinh #endif 1045d465952Smartinh 1055d465952Smartinh switch (ifa->ifa_addr->sa_family) { 1065d465952Smartinh #ifdef AF_LINK 1075d465952Smartinh case AF_LINK: { 1085d465952Smartinh struct sockaddr_dl *dl = (struct sockaddr_dl *)ifa->ifa_addr; 1095d465952Smartinh 1105d465952Smartinh switch (dl->sdl_type) { 1115d465952Smartinh case IFT_ETHER: 1125d465952Smartinh case IFT_FDDI: 1135d465952Smartinh if (dl->sdl_alen == 6) { 1145d465952Smartinh memcpy(addr, LLADDR(dl), 6); 1155d465952Smartinh found_mac = 1; 1165d465952Smartinh } 1175d465952Smartinh } 1185d465952Smartinh 1195d465952Smartinh } 1205d465952Smartinh #endif 1215d465952Smartinh default: 1225d465952Smartinh break; 1235d465952Smartinh } 1245d465952Smartinh } 1255d465952Smartinh 1265d465952Smartinh if (ifa0 != NULL) 1275d465952Smartinh freeifaddrs(ifa0); 1285d465952Smartinh 1295d465952Smartinh if (!found_mac) { 1305d465952Smartinh /* 1315d465952Smartinh * Set the multicast bit to make sure we won't collide with an 1325d465952Smartinh * allocated (mac) address. 1335d465952Smartinh */ 1345d465952Smartinh arc4random_buf(addr, 6); 1355d465952Smartinh addr[0] |= UUID_NODE_MULTICAST; 1365d465952Smartinh } 1375d465952Smartinh return; 1385d465952Smartinh } 1395d465952Smartinh 1405d465952Smartinh /* 1415d465952Smartinh * Creates a new UUID. 1425d465952Smartinh */ 1435d465952Smartinh 1441291887fSmartinh void 1455d465952Smartinh uuid_create(afsUUID *uuid) 1465d465952Smartinh { 1475d465952Smartinh static int uuid_inited = 0; 1485d465952Smartinh struct timeval tv; 1495d465952Smartinh int ret, got_time; 1505d465952Smartinh uint64_t dce_time; 1515d465952Smartinh 1525d465952Smartinh if (uuid_inited == 0) { 1535d465952Smartinh gettimeofday(&last_time, NULL); 1545d465952Smartinh seq_num = arc4random(); 1555d465952Smartinh get_node_addr(nodeaddr); 1565d465952Smartinh uuid_inited = 1; 1575d465952Smartinh } 1585d465952Smartinh 1595d465952Smartinh gettimeofday(&tv, NULL); 1605d465952Smartinh 1615d465952Smartinh got_time = 0; 1625d465952Smartinh 1635d465952Smartinh do { 1645d465952Smartinh ret = time_cmp(&tv, &last_time); 1655d465952Smartinh if (ret < 0) { 1665d465952Smartinh /* Time went backward, just inc seq_num and be done. 1675d465952Smartinh * seq_num is 6 + 8 bit field it the uuid, so let it wrap 1685d465952Smartinh * around. don't let it be zero. 1695d465952Smartinh */ 1705d465952Smartinh seq_num = (seq_num + 1) & 0x3fff ; 1715d465952Smartinh if (seq_num == 0) 1725d465952Smartinh seq_num++; 1735d465952Smartinh got_time = 1; 1745d465952Smartinh counter = 0; 1755d465952Smartinh last_time = tv; 1765d465952Smartinh } else if (ret > 0) { 1775d465952Smartinh /* time went forward, reset counter and be happy */ 1785d465952Smartinh last_time = tv; 1795d465952Smartinh counter = 0; 1805d465952Smartinh got_time = 1; 1815d465952Smartinh } else { 1825d465952Smartinh #define UUID_MAX_HZ (1) /* make this bigger fix you have larger tickrate */ 1835d465952Smartinh #define MULTIPLIER_100_NANO_SEC 10 1845d465952Smartinh if (++counter < UUID_MAX_HZ * MULTIPLIER_100_NANO_SEC) 1855d465952Smartinh got_time = 1; 1865d465952Smartinh } 1875d465952Smartinh } while(!got_time); 1885d465952Smartinh 1895d465952Smartinh /* 1905d465952Smartinh * now shift time to dce_time, epoch 00:00:00:00, 15 October 1582 1915d465952Smartinh * dce time ends year ~3400, so start to worry now 1925d465952Smartinh */ 1935d465952Smartinh 1945d465952Smartinh dce_time = tv.tv_usec * MULTIPLIER_100_NANO_SEC + counter; 1955d465952Smartinh dce_time += ((uint64_t)tv.tv_sec) * 10000000; 1965d465952Smartinh dce_time += (((uint64_t)0x01b21dd2) << 32) + 0x13814000; 1975d465952Smartinh 1985d465952Smartinh uuid->time_low = dce_time & 0xffffffff; 1995d465952Smartinh uuid->time_mid = 0xffff & (dce_time >> 32); 2005d465952Smartinh uuid->time_hi_and_version = 0x0fff & (dce_time >> 48); 2015d465952Smartinh 2025d465952Smartinh uuid->time_hi_and_version |= (1 << 12); 2035d465952Smartinh 2045d465952Smartinh uuid->clock_seq_low = seq_num & 0xff; 2055d465952Smartinh uuid->clock_seq_hi_and_reserved = (seq_num >> 8) & 0x3f; 2065d465952Smartinh uuid->clock_seq_hi_and_reserved |= 0x80; /* dce variant */ 2075d465952Smartinh 2085d465952Smartinh memcpy(uuid->node, nodeaddr, 6); 2095d465952Smartinh } 2105d465952Smartinh 2115d465952Smartinh /* 2125d465952Smartinh * Converts a UUID from binary representation to a string representation. 2135d465952Smartinh */ 2145d465952Smartinh 215*37ddeb55Smartinh void 2165d465952Smartinh uuid_to_string(const afsUUID *uuid, char *str, size_t strsz) 2175d465952Smartinh { 2185d465952Smartinh snprintf(str, strsz, 2195d465952Smartinh "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 2205d465952Smartinh uuid->time_low, 2215d465952Smartinh uuid->time_mid, 2225d465952Smartinh uuid->time_hi_and_version, 2235d465952Smartinh (unsigned char)uuid->clock_seq_hi_and_reserved, 2245d465952Smartinh (unsigned char)uuid->clock_seq_low, 2255d465952Smartinh (unsigned char)uuid->node[0], 2265d465952Smartinh (unsigned char)uuid->node[1], 2275d465952Smartinh (unsigned char)uuid->node[2], 2285d465952Smartinh (unsigned char)uuid->node[3], 2295d465952Smartinh (unsigned char)uuid->node[4], 2305d465952Smartinh (unsigned char)uuid->node[5]); 2315d465952Smartinh } 2325d465952Smartinh 2335d465952Smartinh 2345d465952Smartinh #ifdef TEST 2355d465952Smartinh int 2365d465952Smartinh main(int argc, char **argv) 2375d465952Smartinh { 2385d465952Smartinh char str[1000]; 2395d465952Smartinh afsUUID u1, u2; 2405d465952Smartinh 2415d465952Smartinh uuid_create(&u1); 2425d465952Smartinh 2435d465952Smartinh uuid_to_string(&u1, str, sizeof(str)); 2445d465952Smartinh 2455d465952Smartinh printf("u: %s\n", str); 2465d465952Smartinh 2475d465952Smartinh if (uuid_from_string(str, &u2)) { 2485d465952Smartinh printf("failed to parse\n"); 2495d465952Smartinh return 0; 2505d465952Smartinh } 2515d465952Smartinh 252*37ddeb55Smartinh if (bcmp(&u1, &u2, sizeof(u1)) != 0) 2535d465952Smartinh printf("u1 != u2\n"); 2545d465952Smartinh 2555d465952Smartinh return 0; 2565d465952Smartinh } 2575d465952Smartinh #endif 258