2 * gen_uuid.c --- generate a DCE-compatible uuid
13 #include <sys/types.h>
17 #include <sys/ioctl.h>
18 #include <sys/socket.h>
19 #ifdef HAVE_SYS_SOCKIO_H
20 #include <sys/sockio.h>
25 #ifdef HAVE_NETINET_IN_H
26 #include <netinet/in.h>
32 #define srand(x) srandom(x)
33 #define rand() random()
37 * Generate a series of random bytes. Use /dev/urandom if possible,
38 * and if not, use srandom/random.
40 static void get_random_bytes(void *buf, int nbytes)
44 char *cp = (char *) buf;
47 fd = open("/dev/urandom", O_RDONLY);
48 srand((getpid() << 16) ^ getuid() ^ time(0));
51 i = read(fd, cp, nbytes);
59 for (i=0; i < nbytes; i++)
60 *cp++ = rand() & 0xFF;
64 * Get the ethernet hardware address, if we can find it...
66 static int get_node_id(unsigned char *node_id)
70 struct ifreq ifr, *ifrp;
77 * BSD 4.4 defines the size of an ifreq to be
78 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
79 * However, under earlier systems, sa_len isn't present, so the size is
80 * just sizeof(struct ifreq)
84 #define max(a,b) ((a) > (b) ? (a) : (b))
86 #define ifreq_size(i) max(sizeof(struct ifreq),\
87 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
89 #define ifreq_size(i) sizeof(struct ifreq)
90 #endif /* HAVE_SA_LEN*/
92 sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
96 memset(buf, 0, sizeof(buf));
97 ifc.ifc_len = sizeof(buf);
99 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
104 for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
105 ifrp = (struct ifreq *)((caddr_t) ifc.ifc_buf+i);
106 strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
108 if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
110 a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
113 if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
115 a = (unsigned char *) ifr.ifr_enaddr;
118 * XXX we don't have a way of getting the hardware
123 #endif /* SIOCGENADDR */
124 #endif /* SIOCGIFHWADDR */
125 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
128 memcpy(node_id, a, 6);
138 /* Assume that the gettimeofday() has microsecond granularity */
139 #define MAX_ADJUSTMENT 10
141 static int get_clock(__u32 *clock_high, __u32 *clock_low, __u16 *ret_clock_seq)
143 static int adjustment = 0;
144 static struct timeval last = {0, 0};
145 static __u16 clock_seq;
147 unsigned long long clock;
150 gettimeofday(&tv, 0);
151 if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
152 get_random_bytes(&clock_seq, sizeof(clock_seq));
157 if ((tv.tv_sec < last.tv_sec) ||
158 ((tv.tv_sec == last.tv_sec) &&
159 (tv.tv_usec < last.tv_usec))) {
160 clock_seq = (clock_seq+1) & 0x1FFF;
162 } else if ((tv.tv_sec == last.tv_sec) &&
163 (tv.tv_usec == last.tv_usec)) {
164 if (adjustment >= MAX_ADJUSTMENT)
170 clock = tv.tv_usec*10 + adjustment;
171 clock += ((unsigned long long) tv.tv_sec)*10000000;
172 clock += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
174 *clock_high = clock >> 32;
176 *ret_clock_seq = clock_seq;
180 void uuid_generate(uuid_t out)
182 static unsigned char node_id[6];
183 static int has_init = 0;
188 if (get_node_id(node_id) <= 0)
189 get_random_bytes(node_id, 6);
192 get_clock(&clock_mid, &uu.time_low, &uu.clock_seq);
193 uu.clock_seq |= 0x8000;
194 uu.time_mid = (__u16) clock_mid;
195 uu.time_hi_and_version = (clock_mid >> 16) | 0x1000;
196 memcpy(uu.node, node_id, 6);