summaryrefslogtreecommitdiff
path: root/usr/src/lib/libuuid/common
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libuuid/common
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libuuid/common')
-rw-r--r--usr/src/lib/libuuid/common/etheraddr.c885
-rw-r--r--usr/src/lib/libuuid/common/etheraddr.h90
-rw-r--r--usr/src/lib/libuuid/common/llib-luuid47
-rw-r--r--usr/src/lib/libuuid/common/uuid.c810
-rw-r--r--usr/src/lib/libuuid/common/uuid_misc.c186
-rw-r--r--usr/src/lib/libuuid/common/uuid_misc.h78
6 files changed, 2096 insertions, 0 deletions
diff --git a/usr/src/lib/libuuid/common/etheraddr.c b/usr/src/lib/libuuid/common/etheraddr.c
new file mode 100644
index 0000000000..901888e646
--- /dev/null
+++ b/usr/src/lib/libuuid/common/etheraddr.c
@@ -0,0 +1,885 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2000,2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "etheraddr.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <strings.h>
+#include <libdevinfo.h>
+#include <stropts.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+#include <sys/sockio.h>
+#include <sys/utsname.h>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sys/dlpi.h>
+/*
+ * debugging flag
+ */
+static int debug = 0;
+
+
+/* Timeout for DLPI acks */
+static int dlpi_timeout = DLPI_TIMEOUT;
+
+/*
+ * Global functions
+ */
+int dlpi_get_address(char *, struct ether_addr *);
+int get_net_if_names(char ***);
+void free_net_if_names(char **);
+
+
+/*
+ * local functions
+ */
+static int dlpi_info_req(int, dl_info_ack_t *);
+static int timed_getmsg(int, struct strbuf *, int *, int, char *, char *);
+static int ifrm_num(char *, unsigned int *);
+static int open_dev(dev_att_t *, int, int *, int);
+static void pf_dev_att(dev_att_t *);
+static void parse_ifname(dev_att_t *);
+static int ifname_open(char *, dev_att_t *);
+static int dlpi_open_attach(char *);
+static int dlpi_attach(int, int, int);
+static int dlpi_get_phys(int, uchar_t *);
+static int dlpi_info_req(int, dl_info_ack_t *);
+static int timed_getmsg(int, struct strbuf *, int *, int, char *, char *);
+
+/*
+ * get an individual arp entry
+ */
+int
+arp_get(uuid_node_t *node)
+{
+ struct utsname name;
+ struct arpreq ar;
+ struct hostent *hp;
+ struct sockaddr_in *sin;
+ int s;
+
+ if (uname(&name) == -1) {
+ return (-1);
+ }
+ (void) memset(&ar, 0, sizeof (ar));
+ ar.arp_pa.sa_family = AF_INET;
+ /* LINTED pointer */
+ sin = (struct sockaddr_in *)&ar.arp_pa;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = inet_addr(name.nodename);
+ if (sin->sin_addr.s_addr == (in_addr_t)-1) {
+ hp = gethostbyname(name.nodename);
+ if (hp == NULL) {
+ return (-1);
+ }
+ (void) memcpy(&sin->sin_addr, hp->h_addr,
+ sizeof (sin->sin_addr));
+ }
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ return (-1);
+ }
+ if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) {
+ (void) close(s);
+ return (-1);
+ }
+ (void) close(s);
+ if (ar.arp_flags & ATF_COM) {
+ bcopy(&ar.arp_ha.sa_data, node, 6);
+ } else
+ return (-1);
+ return (0);
+}
+
+
+/* Get all interface names. This will include IPv6 names. */
+int
+get_net_if_names(char ***names)
+{
+ char *buf; /* buffer for socket info */
+ int sd; /* socket descriptor */
+ int ifn; /* interface count structure */
+ struct ifconf ifc; /* interface config buffer */
+ struct ifreq *ifrp;
+ int numifs;
+ char **tmpnames;
+ int n;
+ char *tmpname;
+ sd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sd < 0)
+ return (-1);
+
+ if (ioctl(sd, SIOCGIFNUM, &ifn) < 0) {
+ (void) close(sd);
+ return (-1);
+ }
+
+ if (!(buf = malloc(ifn * sizeof (struct ifreq)))) {
+ (void) close(sd);
+ return (-1);
+ }
+
+ ifc.ifc_len = ifn * sizeof (struct ifreq);
+ ifc.ifc_buf = (caddr_t)buf;
+ if (ioctl(sd, SIOCGIFCONF, (char *)&ifc) < 0) {
+ free(buf);
+ (void) close(sd);
+ return (-1);
+ }
+ (void) close(sd);
+
+ ifrp = ifc.ifc_req;
+ numifs = ifc.ifc_len / sizeof (struct ifreq);
+ tmpnames = (char **)calloc((numifs+1), sizeof (char *));
+
+ if (tmpnames == NULL) {
+ free(buf);
+ return (-1);
+ }
+ for (n = 0; n < numifs; n++, ifrp++) {
+ if ((tmpnames[n] = strdup(ifrp->ifr_name)) == NULL)
+ break;
+ }
+ free(buf);
+ *names = tmpnames;
+ return (0);
+}
+
+/*
+ * frees previously-allocated array from get_net_if_names
+ */
+void
+free_net_if_names(char **ifnames)
+{
+ int i;
+
+ i = 0;
+ while (ifnames[i] != NULL) {
+ free(ifnames[i]);
+ i++;
+ }
+ free(ifnames);
+}
+
+
+/*
+ * attempt to remove ppa from end of file name
+ * return -1 if none found
+ * return ppa if found and remove the ppa from the filename
+ */
+static int
+ifrm_num(char *fname, unsigned int *ppa)
+{
+ int i;
+ uint_t p = 0;
+ unsigned int m = 1;
+
+ i = strlen(fname) - 1;
+ while (i >= 0 && '0' <= fname[i] && fname[i] <= '9') {
+ p += (fname[i] - '0')*m;
+ m *= 10;
+ i--;
+ }
+ if (m == 1) {
+ return (-1);
+ }
+ fname[i + 1] = '\0';
+ *ppa = p;
+ return (0);
+}
+
+/*
+ * Open the device defined in dev_att with the given mode starting with
+ * the module indicated by mod_cnt (1 indexed). If mod_cnt > 0, fd must
+ * contain the file descriptor that modules are to be pushed on.
+ * Returns -1 if device could not be opened, the index of
+ * the module that could not be pushed or 0 on success.
+ */
+static int
+open_dev(dev_att_t *dev_att, int mode, int *fd, int mod_cnt)
+{
+ int cnt;
+ int local_fd;
+
+ if (debug)
+ (void) printf("open_dev: ifname: %s : dev %s fd %d "
+ " mod_cnt %d\n",
+ dev_att->ifname, dev_att->devname, *fd, mod_cnt);
+ /*
+ * if no module count is given, try and open the device
+ */
+ if (mod_cnt == 0) {
+ if (debug)
+ (void) printf("open_dev: opening %s\n",
+ dev_att->devname);
+ if ((local_fd = open(dev_att->devname, mode)) < 0) {
+ if (debug) {
+ perror("open_dev: device");
+ (void) printf("\n");
+ }
+ *fd = local_fd;
+ return (-1);
+ }
+ *fd = local_fd;
+ cnt = 1;
+ } else {
+ local_fd = *fd;
+ cnt = mod_cnt;
+ }
+
+ /*
+ * Try and push modules (if any) onto the device stream
+ */
+ for (; cnt <= dev_att->mod_cnt; cnt++) {
+ if (debug)
+ (void) printf(" pushing: mod %s",
+ dev_att->modlist[cnt - 1]);
+ if (ioctl(local_fd, I_PUSH, dev_att->modlist[cnt - 1]) == -1) {
+ if (debug) {
+ perror("open_dev: push");
+ (void) printf("\n");
+ }
+ return (cnt);
+ }
+ }
+ if (debug)
+ (void) printf("\n");
+ return (0);
+}
+
+/*
+ * Debug routine to print out dev_att_t structure
+ */
+static void
+pf_dev_att(dev_att_t *dev_att)
+{
+ int cnt;
+
+ (void) printf("\tifname: %s\n", dev_att->ifname);
+ (void) printf("\t style: %d\n", dev_att->style);
+ (void) printf("\t ppa: %d\n", dev_att->ppa);
+ (void) printf("\t mod_cnt: %d\n", dev_att->mod_cnt);
+ (void) printf("\t devname: %s\n", dev_att->devname);
+ for (cnt = 0; cnt < dev_att->mod_cnt; cnt++) {
+ (void) printf("\t module: %s\n", dev_att->modlist[cnt]);
+ }
+}
+
+/*
+ * This function parses a '.' delimited interface name of the form
+ * dev[.module[.module...]][:lun]
+ * and places the device and module name into dev_att
+ */
+static void
+parse_ifname(dev_att_t *dev_att)
+{
+ char *lunstr;
+ char *modlist = NULL; /* list of modules to push */
+ int cnt = 0; /* number of modules to push */
+ char modbuf[LIFNAMSIZ];
+ char *nxtmod;
+
+ /*
+ * check for specified lun at end of interface and
+ * strip it off.
+ */
+ lunstr = strchr(dev_att->ifname, ':');
+
+ if (lunstr) {
+ char *endptr;
+
+ *lunstr = '\0';
+ lunstr++;
+ endptr = lunstr;
+ dev_att->lun = strtoul(lunstr, &endptr, 10);
+
+ if (endptr == lunstr || *endptr != '\0') {
+ (void) printf("Invalid logical unit number:%s", lunstr);
+ exit(-1);
+ }
+ } else {
+ dev_att->lun = 0;
+ }
+
+ (void) strlcpy(modbuf, dev_att->ifname, LIFNAMSIZ);
+
+ /* parse '.' delmited module list */
+ modlist = strchr(modbuf, '.');
+ if (modlist) {
+ /* null-terminate interface name (device) */
+ *modlist = '\0';
+ modlist++;
+ if (strlen(modlist) == 0)
+ modlist = NULL;
+ while (modlist && cnt < MAX_MODS) {
+ nxtmod = strchr(modlist, '.');
+ if (nxtmod) {
+ *nxtmod = '\0';
+ nxtmod++;
+ }
+ (void) strncpy(dev_att->modlist[cnt], modlist,
+ LIFNAMSIZ);
+ cnt++;
+ modlist = nxtmod;
+ }
+ }
+ (void) snprintf(dev_att->devname, LIFNAMSIZ, "%s/%s", DEVDIR, modbuf);
+ dev_att->mod_cnt = cnt;
+}
+
+/*
+ * given a interface name (with possible modules to push)
+ * interface name must have the format of
+ * dev[ppa][.module[.module...][ppa]][:lun]
+ * where only one ppa may be specified e.g. ip0.foo.tun or ip.foo.tun0
+ */
+static int
+ifname_open(char *dev_name, dev_att_t *dev_att)
+{
+ int fd;
+ uint_t ppa;
+ int res;
+ int style;
+ dl_info_ack_t dl_info;
+ int mod_id;
+
+ if (debug)
+ (void) printf("ifname_open: %s\n", dev_name);
+
+ if (strlen(dev_name) > LIFNAMSIZ - 1) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* save copy of original device name */
+ (void) strncpy(dev_att->ifname, dev_name, LIFNAMSIZ);
+
+ /* parse modules */
+ parse_ifname(dev_att);
+
+ /* try DLPI style 1 device first */
+
+ if (debug) {
+ pf_dev_att(dev_att);
+ }
+ mod_id = open_dev(dev_att, O_RDWR, &fd, 0);
+ if (mod_id != 0) {
+ if (debug) {
+ (void) printf("Error on open_dev style 1 mod_id: %d"
+ " attemping style 2\n", mod_id);
+ pf_dev_att(dev_att);
+ }
+ if (mod_id == -1) {
+ res = ifrm_num(dev_att->devname, &ppa);
+ mod_id = 0;
+ if (res < 0) {
+ if (debug)
+ (void) fprintf(stderr,
+ "%s: No such file or directory\n",
+ dev_att->devname);
+ (void) close(fd);
+ return (-1);
+ }
+ /*
+ * ensure that it's the last module
+ * in the list to extract
+ * ppa
+ */
+ } else if ((mod_id != dev_att->mod_cnt) ||
+ (res = ifrm_num(dev_att->modlist[dev_att->mod_cnt - 1],
+ &ppa)) < 0) {
+ if (debug) {
+ (void) fprintf(stderr,
+ "Error on open_dev style 2 mod_id: %d \n",
+ mod_id);
+ }
+ if (mod_id == dev_att->mod_cnt)
+ (void) fprintf(stderr, "libuuid: could not "
+ "locate ppa in %s\n",
+ dev_att->ifname);
+ (void) close(fd);
+ return (-1);
+ }
+ goto style2;
+ }
+ dev_att->style = 1;
+ dev_att->ppa = 0;
+ style = DL_STYLE1;
+ goto dl_info_chk;
+style2:
+ dev_att->ppa = ppa;
+ mod_id = open_dev(dev_att, O_RDWR, &fd, mod_id);
+ if (mod_id != 0) {
+ if (debug) {
+ (void) fprintf(stderr,
+ "Error on open_dev style 2 mod_id: %d \n",
+ mod_id);
+ if (mod_id > 0) {
+ (void) fprintf(stderr, "%s: No such module\n",
+ dev_att->modlist[mod_id - 2]);
+ }
+ pf_dev_att(dev_att);
+ }
+ (void) close(fd);
+ return (-1);
+ }
+ dev_att->style = 2;
+ style = DL_STYLE2;
+dl_info_chk:
+ if (dlpi_info_req(fd, &dl_info) < 0) {
+ (void) close(fd);
+ pf_dev_att(dev_att);
+ return (-1);
+ }
+ if (dl_info.dl_provider_style != style) {
+ if (debug) {
+ (void) fprintf(stderr, "DLPI provider style mismatch: "
+ "expected style %s got style %s (0x%lx)\n",
+ style == DL_STYLE1 ? "1" : "2",
+ dl_info.dl_provider_style == DL_STYLE1 ? "1" : "2",
+ dl_info.dl_provider_style);
+ }
+ (void) close(fd);
+ return (-1);
+ }
+ if (debug) {
+ (void) printf("pars_dev_att() success\n");
+ pf_dev_att(dev_att);
+ }
+ return (fd);
+}
+
+static int
+dlpi_open_attach(char *ifname)
+{
+ int fd;
+ dev_att_t dev_att;
+
+ if (debug)
+ (void) printf("dlpi_open_attach %s\n", ifname);
+
+ /* if lun is specified fail (backwards compat) */
+ if (strchr(ifname, ':') != NULL) {
+ return (-1);
+ }
+ if ((fd = ifname_open(ifname, &dev_att)) < 0) {
+ /* Not found */
+ errno = ENXIO;
+ return (-1);
+ }
+ if (dlpi_attach(fd, dev_att.ppa, dev_att.style) < 0) {
+ (void) close(fd);
+ return (-1);
+ }
+ return (fd);
+}
+
+static int
+dlpi_attach(int fd, int ppa, int style)
+{
+ union DL_primitives *dlp;
+ char *buf;
+ struct strbuf ctl;
+ int flags;
+
+ if (style != 2)
+ return (0);
+
+ /* Allocate required buffers */
+ if ((buf = malloc(BUFSIZ)) == NULL) {
+ (void) fprintf(stderr, "libuuid: malloc() failed\n");
+ return (-1);
+ }
+
+ /* Issue DL_ATTACH_REQ */
+ /* LINTED: malloc returns a pointer aligned for any use */
+ dlp = (union DL_primitives *)buf;
+ dlp->attach_req.dl_primitive = DL_ATTACH_REQ;
+ dlp->attach_req.dl_ppa = ppa;
+ ctl.buf = (char *)dlp;
+ ctl.len = DL_ATTACH_REQ_SIZE;
+ if (putmsg(fd, &ctl, NULL, 0) < 0) {
+ perror("libuuid: putmsg");
+ free(buf);
+ return (-1);
+ }
+
+ /* read reply */
+ ctl.buf = (char *)dlp;
+ ctl.len = 0;
+ ctl.maxlen = BUFSIZ;
+ flags = 0;
+
+ /* start timeout for DL_OK_ACK reply */
+ if (timed_getmsg(fd, &ctl, &flags, dlpi_timeout,
+ "DL_OK_ACK", "DL_ATTACH_REQ") == 0) {
+ free(buf);
+ return (-1);
+ }
+
+ if (debug) {
+ (void) printf("ok_ack: ctl.len[%d] flags[%d]\n", ctl.len,
+ flags);
+ }
+
+ /* Validate DL_OK_ACK reply. */
+ if (ctl.len < sizeof (t_uscalar_t)) {
+ (void) fprintf(stderr,
+ "libuuid: attach failed: short reply to attach request\n");
+ free(buf);
+ return (-1);
+ }
+
+ if (dlp->dl_primitive == DL_ERROR_ACK) {
+ if (debug)
+ (void) fprintf(stderr,
+ "attach failed: dl_errno %lu errno %lu\n",
+ dlp->error_ack.dl_errno,
+ dlp->error_ack.dl_unix_errno);
+ free(buf);
+ errno = ENXIO;
+ return (-1);
+ }
+ if (dlp->dl_primitive != DL_OK_ACK) {
+ (void) fprintf(stderr,
+ "libuuid: attach failed: "
+ "unrecognizable dl_primitive %lu received",
+ dlp->dl_primitive);
+ free(buf);
+ return (-1);
+ }
+ if (ctl.len < DL_OK_ACK_SIZE) {
+ (void) fprintf(stderr,
+ "libuuid: attach failed: "
+ "short attach acknowledgement received\n");
+ free(buf);
+ return (-1);
+ }
+ if (dlp->ok_ack.dl_correct_primitive != DL_ATTACH_REQ) {
+ (void) fprintf(stderr,
+ "libuuid: attach failed: "
+ "returned prim %lu != requested prim %lu\n",
+ dlp->ok_ack.dl_correct_primitive,
+ (t_uscalar_t)DL_ATTACH_REQ);
+ free(buf);
+ return (-1);
+ }
+ if (debug)
+ (void) printf("attach done\n");
+
+ free(buf);
+ return (0);
+}
+
+static int
+dlpi_get_phys(int fd, uchar_t *eaddr)
+{
+ union DL_primitives *dlp;
+ char *buf;
+ struct strbuf ctl;
+ int flags;
+
+ /* Allocate required buffers */
+ if ((buf = malloc(BUFSIZ)) == NULL) {
+ (void) fprintf(stderr, "libuuid: malloc() failed\n");
+ return (-1);
+ }
+ /* Issue DL_PHYS_ADDR_REQ */
+ /* LINTED: malloc returns a pointer aligned for any use */
+ dlp = (union DL_primitives *)buf;
+ dlp->physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
+ dlp->physaddr_req.dl_addr_type = DL_CURR_PHYS_ADDR;
+ ctl.buf = (char *)dlp;
+ ctl.len = DL_PHYS_ADDR_REQ_SIZE;
+ if (putmsg(fd, &ctl, NULL, 0) < 0) {
+ perror("libuuid: putmsg");
+ free(buf);
+ return (-1);
+ }
+
+ /* read reply */
+ ctl.buf = (char *)dlp;
+ ctl.len = 0;
+ ctl.maxlen = BUFSIZ;
+ flags = 0;
+
+ if (timed_getmsg(fd, &ctl, &flags, dlpi_timeout,
+ "DL_PHYS_ADDR_ACK", "DL_PHYS_ADDR_REQ (DL_CURR_PHYS_ADDR)") == 0) {
+ free(buf);
+ return (-1);
+ }
+
+ if (debug) {
+ (void) printf("phys_addr_ack: ctl.len[%d] flags[%d]\n", ctl.len,
+ flags);
+ }
+
+ /* Validate DL_PHYS_ADDR_ACK reply. */
+ if (ctl.len < sizeof (t_uscalar_t)) {
+ (void) fprintf(stderr, "libuuid: phys_addr failed: "
+ "short reply to phys_addr request\n");
+ free(buf);
+ return (-1);
+ }
+
+ if (dlp->dl_primitive == DL_ERROR_ACK) {
+ /*
+ * Do not print errors for DL_UNSUPPORTED and DL_NOTSUPPORTED
+ */
+ if (dlp->error_ack.dl_errno != DL_UNSUPPORTED &&
+ dlp->error_ack.dl_errno != DL_NOTSUPPORTED) {
+ (void) fprintf(stderr, "libuuid: phys_addr failed: "
+ "dl_errno %lu errno %lu\n",
+ dlp->error_ack.dl_errno,
+ dlp->error_ack.dl_unix_errno);
+ }
+ free(buf);
+ return (-1);
+ }
+ if (dlp->dl_primitive != DL_PHYS_ADDR_ACK) {
+ (void) fprintf(stderr, "libuuid: phys_addr failed: "
+ "unrecognizable dl_primitive %lu received\n",
+ dlp->dl_primitive);
+ free(buf);
+ return (-1);
+ }
+ if (ctl.len < DL_PHYS_ADDR_ACK_SIZE) {
+ (void) fprintf(stderr, "libuuid: phys_addr failed: "
+ "short phys_addr acknowledgement received\n");
+ free(buf);
+ return (-1);
+ }
+ /* Check length of address. */
+ if (dlp->physaddr_ack.dl_addr_length != ETHERADDRL) {
+ free(buf);
+ return (-1);
+ }
+
+ /* copy Ethernet address */
+ (void) memcpy(eaddr, &buf[dlp->physaddr_ack.dl_addr_offset],
+ ETHERADDRL);
+
+ free(buf);
+ return (0);
+}
+
+
+
+static int
+dlpi_info_req(int fd, dl_info_ack_t *info_ack)
+{
+ dl_info_req_t info_req;
+ int buf[BUFSIZ/sizeof (int)];
+ union DL_primitives *dlp = (union DL_primitives *)buf;
+ struct strbuf ctl;
+ int flags;
+
+ info_req.dl_primitive = DL_INFO_REQ;
+
+ ctl.len = DL_INFO_REQ_SIZE;
+ ctl.buf = (char *)&info_req;
+
+ flags = RS_HIPRI;
+
+ if (putmsg(fd, &ctl, (struct strbuf *)NULL, flags) < 0) {
+ perror("libuuid: putmsg");
+ return (-1);
+ }
+
+ /* read reply */
+ ctl.buf = (char *)dlp;
+ ctl.len = 0;
+ ctl.maxlen = BUFSIZ;
+ flags = 0;
+ /* start timeout for DL_BIND_ACK reply */
+ if (timed_getmsg(fd, &ctl, &flags, dlpi_timeout, "DL_INFO_ACK",
+ "DL_INFO_ACK") == 0) {
+ return (-1);
+ }
+
+ if (debug) {
+ (void) printf("info_ack: ctl.len[%d] flags[%d]\n", ctl.len,
+ flags);
+ }
+
+ /* Validate DL_BIND_ACK reply. */
+ if (ctl.len < sizeof (t_uscalar_t)) {
+ (void) fprintf(stderr,
+ "libuuid: info req failed: short reply to info request\n");
+ return (-1);
+ }
+
+ if (dlp->dl_primitive == DL_ERROR_ACK) {
+ (void) fprintf(stderr,
+ "libuuid: info req failed: dl_errno %lu errno %lu\n",
+ dlp->error_ack.dl_errno, dlp->error_ack.dl_unix_errno);
+ return (-1);
+ }
+ if (dlp->dl_primitive != DL_INFO_ACK) {
+ (void) fprintf(stderr,
+ "libuuid: info req failed: "
+ "unrecognizable dl_primitive %lu received\n",
+ dlp->dl_primitive);
+ return (-1);
+ }
+ if (ctl.len < DL_INFO_ACK_SIZE) {
+ (void) fprintf(stderr,
+ "libuuid: info req failed: "
+ "short info acknowledgement received\n");
+ return (-1);
+ }
+ *info_ack = *(dl_info_ack_t *)dlp;
+ return (0);
+}
+
+
+/*
+ * interface called from libuuid to get the ethernet address - jhf
+ */
+int
+dlpi_get_address(char *ifname, struct ether_addr *ea)
+{
+ int fd;
+
+ if (debug)
+ (void) printf("dlpi_get_address: dlpi_open_attach\t");
+ fd = dlpi_open_attach(ifname);
+ if (fd < 0) {
+ /* Do not report an error */
+ return (-1);
+ }
+
+ if (debug)
+ (void) printf("dlpi_get_address: dlpi_get_phys %s\n", ifname);
+ if (dlpi_get_phys(fd, (uchar_t *)ea) < 0) {
+ (void) close(fd);
+ return (-1);
+ }
+ (void) close(fd);
+ return (0);
+}
+
+static int
+timed_getmsg(int fd, struct strbuf *ctlp, int *flagsp, int timeout, char *kind,
+ char *request)
+{
+ char perrorbuf[BUFSIZ];
+ struct pollfd pfd;
+ int ret;
+
+ pfd.fd = fd;
+
+ pfd.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
+ if ((ret = poll(&pfd, 1, timeout * 1000)) == 0) {
+ (void) fprintf(stderr, "libuuid: %s timed out\n", kind);
+ return (0);
+ } else if (ret == -1) {
+ (void) snprintf(perrorbuf, sizeof (perrorbuf),
+ "libuuid: poll for %s from %s", kind, request);
+ perror(perrorbuf);
+ return (0);
+ }
+
+ /* poll returned > 0 for this fd so getmsg should not block */
+ if ((ret = getmsg(fd, ctlp, NULL, flagsp)) < 0) {
+ (void) snprintf(perrorbuf, sizeof (perrorbuf),
+ "libuuid: getmsg expecting %s for %s", kind, request);
+ perror(perrorbuf);
+ return (0);
+ }
+
+ return (1);
+}
+
+/*
+ * Name: get_ethernet_address
+ *
+ * Description: Obtains the system ethernet address.
+ *
+ * Returns: 0 on success, non-zero otherwise. The system ethernet
+ * address is copied into the passed-in variable.
+ */
+int
+get_ethernet_address(uuid_node_t *node)
+{
+ char **ifnames;
+ char *ifname;
+ int i;
+ struct ether_addr addr;
+ int found;
+
+ if (arp_get(node) == 0)
+ return (0);
+
+ /*
+ * go get all interface names
+ */
+ if (get_net_if_names(&ifnames) == 0) {
+ return (0);
+ }
+
+ /*
+ * Assume failure
+ */
+ found = -1;
+
+ /*
+ * for each interface, query it through dlpi to get its physical
+ * (ethernet) address
+ */
+ if (ifnames != NULL) {
+ i = 0;
+ while ((ifnames[i] != NULL) && found) {
+ ifname = ifnames[i];
+ /* Gross hack to avoid getting errors from /dev/lo0 */
+ if (strcmp(ifname, LOOPBACK_IF) != 0) {
+ if (dlpi_get_address(ifname, &addr) == 0) {
+ bcopy(&addr, node, 6);
+ /*
+ * found one, set result to successful
+ */
+ found = 0;
+ continue;
+ }
+ }
+ i++;
+ }
+ free_net_if_names(ifnames);
+ }
+
+ /*
+ * Couldn't get ethernet address from any interfaces...
+ */
+ return (found);
+}
diff --git a/usr/src/lib/libuuid/common/etheraddr.h b/usr/src/lib/libuuid/common/etheraddr.h
new file mode 100644
index 0000000000..b2fdeaacf3
--- /dev/null
+++ b/usr/src/lib/libuuid/common/etheraddr.h
@@ -0,0 +1,90 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2000,2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _ETHERADDR_H
+#define _ETHERADDR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Module: etheraddr
+ * Description: This is the solaris-specific interface for retrieving
+ * the MAC (IEEE 802.3) node identifier, a.k.a. the ethernet
+ * address of the system. Note that this can only get the
+ * ethernet address if the process running the code can open
+ * /dev/[whatever] read/write, e.g. you must be root.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#include <sys/uuid.h>
+
+/* max modules that can be pushed on intr */
+#define MAX_MODS 9
+
+/* used to avoid getting errors from lo0 */
+#define LOOPBACK_IF "lo0"
+
+/*
+ * Local structure encapsulating an interface
+ * device and its associated modules
+ */
+typedef struct dev_att {
+ char ifname[LIFNAMSIZ]; /* interface name, such as "le0" */
+ int style; /* DLPI message style */
+ int ppa; /* Physical point of attachment */
+ int lun; /* logical unit number */
+ int mod_cnt; /* # modules to push onto stream */
+ char devname[LIFNAMSIZ]; /* device name, such as "/dev/le0" */
+ char modlist[MAX_MODS][LIFNAMSIZ]; /* modules to push onto stream */
+} dev_att_t;
+
+
+/* where devices are located */
+#define DEVDIR "/dev"
+
+/* how long to wait for dlpi requests to succeed */
+#define DLPI_TIMEOUT 60
+
+/*
+ * Global functions
+ */
+int arp_get(uuid_node_t *);
+int dlpi_get_address(char *, struct ether_addr *);
+int get_net_if_names(char ***);
+void free_net_if_names(char **);
+int get_ethernet_address(uuid_node_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ETHERADDR_H */
diff --git a/usr/src/lib/libuuid/common/llib-luuid b/usr/src/lib/libuuid/common/llib-luuid
new file mode 100644
index 0000000000..04ee51367d
--- /dev/null
+++ b/usr/src/lib/libuuid/common/llib-luuid
@@ -0,0 +1,47 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/uuid.h>
+#include <pkginfo.h>
+
+/*
+ * usr/src/lib/libuuid
+ */
+/* main.c */
+void uuid_clear(uuid_t);
+int uuid_compare(uuid_t, uuid_t);
+void uuid_copy(uuid_t, uuid_t);
+void uuid_generate(uuid_t);
+void uuid_generate_random(uuid_t);
+void uuid_generate_time(uuid_t);
+int uuid_is_null(uuid_t);
+int uuid_parse(char *, uuid_t);
+time_t uuid_time(uuid_t, struct timeval *);
+void uuid_unparse(uuid_t, char *);
diff --git a/usr/src/lib/libuuid/common/uuid.c b/usr/src/lib/libuuid/common/uuid.c
new file mode 100644
index 0000000000..1be9fba0d1
--- /dev/null
+++ b/usr/src/lib/libuuid/common/uuid.c
@@ -0,0 +1,810 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The copyright in this file is taken from the original Leach & Salz
+ * UUID specification, from which this implementation is derived.
+ */
+
+/*
+ * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+ * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
+ * Digital Equipment Corporation, Maynard, Mass. Copyright (c) 1998
+ * Microsoft. To anyone who acknowledges that this file is provided
+ * "AS IS" without any express or implied warranty: permission to use,
+ * copy, modify, and distribute this file for any purpose is hereby
+ * granted without fee, provided that the above copyright notices and
+ * this notice appears in all source code copies, and that none of the
+ * names of Open Software Foundation, Inc., Hewlett-Packard Company,
+ * or Digital Equipment Corporation be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission. Neither Open Software
+ * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
+ * Equipment Corporation makes any representations about the
+ * suitability of this software for any purpose.
+ */
+
+/*
+ * Module: uuid.c
+ *
+ * Description: This module is the workhorse for generating abstract
+ * UUIDs. It delegates system-specific tasks (such
+ * as obtaining the node identifier or system time)
+ * to the sysdep module.
+ */
+
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+#include <thread.h>
+#include <synch.h>
+#include "uuid_misc.h"
+
+#define STATE_LOCATION "/var/sadm/system/uuid_state"
+#define URANDOM_PATH "/dev/urandom"
+#define MAX_RETRY 8
+#define UUID_PRINTF_SIZE 37
+#define VER1_MASK 0xefff
+
+static mutex_t ulock = DEFAULTMUTEX;
+
+uint16_t _get_random(void);
+void _get_current_time(uuid_time_t *);
+void struct_to_string(uuid_t, struct uuid *);
+void string_to_struct(struct uuid *, uuid_t);
+int get_ethernet_address(uuid_node_t *);
+
+/*
+ * local functions
+ */
+static int _lock_state(char *);
+static void _unlock_state(int);
+static void _read_state(int, uint16_t *, uuid_time_t *,
+ uuid_node_t *);
+static int _write_state(int, uint16_t, uuid_time_t, uuid_node_t);
+static void _format_uuid(struct uuid *, uint16_t, uuid_time_t,
+ uuid_node_t);
+static void fill_random_bytes(uchar_t *, int);
+static int uuid_create(struct uuid *);
+
+static void gen_ethernet_address(uuid_node_t *);
+/*
+ * Name: uuid_create.
+ *
+ * Description: Generates a uuid based on Version 1 format
+ *
+ * Returns: 0 on success, -1 on Error
+ */
+static int
+uuid_create(struct uuid *uuid)
+{
+ uuid_time_t timestamp, last_time;
+ uint16_t clockseq = 0;
+ uuid_node_t last_node;
+ uuid_node_t system_node;
+ int locked_state_fd;
+ int non_unique = 0;
+
+ if (mutex_lock(&ulock) != 0) {
+ return (-1);
+ }
+
+ gen_ethernet_address(&system_node);
+ /*
+ * acquire system wide lock so we're alone
+ */
+ locked_state_fd = _lock_state(STATE_LOCATION);
+ if (locked_state_fd < 0) {
+ /* couldn't create and/or lock state; don't have access */
+ non_unique++;
+ } else {
+ /* read saved state from disk */
+ _read_state(locked_state_fd, &clockseq, &last_time,
+ &last_node);
+ }
+
+ if (clockseq == 0) {
+ /* couldn't read clock sequence; generate a random one */
+ clockseq = _get_random();
+ non_unique++;
+ }
+ if (memcmp(&system_node, &last_node, sizeof (uuid_node_t)) != 0) {
+ clockseq++;
+ }
+
+ /*
+ * get current time
+ */
+ _get_current_time(&timestamp);
+
+ /*
+ * If timestamp is not set or is not in the past,
+ * increment clock sequence.
+ */
+ if ((last_time == 0) || (last_time >= timestamp)) {
+ clockseq++;
+ last_time = timestamp;
+ }
+
+ if (non_unique)
+ system_node.nodeID[0] |= 0x80;
+ /*
+ * stuff fields into the UUID
+ */
+ _format_uuid(uuid, clockseq, timestamp, system_node);
+ if ((locked_state_fd >= 0) &&
+ (_write_state(locked_state_fd, clockseq, timestamp,
+ system_node) == -1)) {
+ _unlock_state(locked_state_fd);
+ (void) mutex_unlock(&ulock);
+ return (-1);
+ }
+ /*
+ * Unlock system-wide lock
+ */
+ _unlock_state(locked_state_fd);
+ (void) mutex_unlock(&ulock);
+ return (0);
+}
+
+/*
+ * Name: gen_ethernet_address
+ *
+ * Description: Fills system_node with Ethernet address if available,
+ * else fills random numbers
+ *
+ * Returns: Nothing
+ */
+static void
+gen_ethernet_address(uuid_node_t *system_node)
+{
+ uchar_t node[6];
+
+ if (get_ethernet_address(system_node) != 0) {
+ fill_random_bytes(node, 6);
+ (void) memcpy(system_node->nodeID, node, 6);
+ /*
+ * use 8:0:20 with the multicast bit set
+ * to avoid namespace collisions.
+ */
+ system_node->nodeID[0] = 0x88;
+ system_node->nodeID[1] = 0x00;
+ system_node->nodeID[2] = 0x20;
+ }
+}
+
+/*
+ * Name: _format_uuid
+ *
+ * Description: Formats a UUID, given the clock_seq timestamp,
+ * and node address. Fills in passed-in pointer with
+ * the resulting uuid.
+ *
+ * Returns: None.
+ */
+static void
+_format_uuid(struct uuid *uuid, uint16_t clock_seq,
+ uuid_time_t timestamp, uuid_node_t node)
+{
+
+ /*
+ * First set up the first 60 bits from the timestamp
+ */
+ uuid->time_low = (uint32_t)(timestamp & 0xFFFFFFFF);
+ uuid->time_mid = (uint16_t)((timestamp >> 32) & 0xFFFF);
+ uuid->time_hi_and_version = (uint16_t)((timestamp >> 48) &
+ 0x0FFF);
+
+ /*
+ * This is version 1, so say so in the UUID version field (4 bits)
+ */
+ uuid->time_hi_and_version |= (1 << 12);
+
+ /*
+ * Now do the clock sequence
+ */
+ uuid->clock_seq_low = clock_seq & 0xFF;
+
+ /*
+ * We must save the most-significant 2 bits for the reserved field
+ */
+ uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
+
+ /*
+ * The variant for this format is the 2 high bits set to 10,
+ * so here it is
+ */
+ uuid->clock_seq_hi_and_reserved |= 0x80;
+
+ /*
+ * write result to passed-in pointer
+ */
+ (void) memcpy(&uuid->node_addr, &node, sizeof (uuid->node_addr));
+}
+
+/*
+ * Name: _read_state
+ *
+ * Description: Reads non-volatile state from a (possibly) saved statefile.
+ * For each non-null pointer passed-in, the corresponding
+ * information from the statefile is filled in.
+ * the resulting uuid.
+ *
+ * Returns: Nothing.
+ */
+static void
+_read_state(int fd, uint16_t *clockseq,
+ uuid_time_t *timestamp, uuid_node_t *node)
+{
+ uuid_state_t vol_state;
+
+ bzero(node, sizeof (uuid_node_t));
+ *timestamp = 0;
+ *clockseq = 0;
+
+ if (read(fd, &vol_state, sizeof (uuid_state_t)) <
+ sizeof (uuid_state_t)) {
+ /* This file is being accessed the first time */
+ }
+
+ *node = vol_state.node;
+ *timestamp = vol_state.ts;
+ *clockseq = vol_state.cs;
+}
+
+
+/*
+ * Name: _write_state
+ *
+ * Description: Writes non-volatile state from the passed-in information.
+ *
+ * Returns: -1 on error, 0 otherwise.
+ */
+static int
+_write_state(int fd, uint16_t clockseq,
+ uuid_time_t timestamp, uuid_node_t node)
+{
+ uuid_state_t vol_state;
+
+ vol_state.cs = clockseq;
+ vol_state.ts = timestamp;
+ vol_state.node = node;
+ /*
+ * seek to beginning of file and write data
+ */
+ if (lseek(fd, 0, SEEK_SET) != -1) {
+ if (write(fd, &vol_state, sizeof (uuid_state_t)) != -1) {
+ return (0);
+ }
+ }
+ return (-1);
+}
+
+
+
+/*
+ * Name: _uuid_print
+ *
+ * Description: Prints a nicely-formatted uuid to stdout.
+ *
+ * Returns: None.
+ *
+ */
+void
+uuid_print(struct uuid u)
+{
+ int i;
+
+ (void) printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
+ u.time_hi_and_version, u.clock_seq_hi_and_reserved,
+ u.clock_seq_low);
+ for (i = 0; i < 6; i++)
+ (void) printf("%2.2x", u.node_addr[i]);
+ (void) printf("\n");
+}
+
+/*
+ * Name: _lock_state
+ *
+ * Description: Locks down the statefile, by first creating the file
+ * if it doesn't exist.
+ *
+ * Returns: A non-negative file descriptor referring to the locked
+ * state file, if it was able to be created and/or locked,
+ * or -1 otherwise.
+ */
+static int
+_lock_state(char *loc)
+{
+ int fd;
+ struct flock lock;
+
+ fd = open(loc, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
+
+ if (fd < 0) {
+ return (-1);
+ }
+
+ lock.l_type = F_WRLCK;
+ lock.l_start = 0;
+ lock.l_whence = SEEK_SET;
+ lock.l_len = 0;
+
+ if (fcntl(fd, F_SETLKW, &lock) == -1) {
+ /*
+ * File could not be locked, bail
+ */
+ (void) close(fd);
+ return (-1);
+ }
+ return (fd);
+}
+
+/*
+ * Name: _unlock_state
+ *
+ * Description: Unlocks a locked statefile, and close()'s the file.
+ *
+ * Returns: Nothing.
+ */
+void
+_unlock_state(int fd)
+{
+ struct flock lock;
+
+ lock.l_type = F_UNLCK;
+ lock.l_start = 0;
+ lock.l_whence = SEEK_SET;
+ lock.l_len = 0;
+
+ (void) fcntl(fd, F_SETLK, &lock);
+ (void) close(fd);
+}
+
+/*
+ * Name: fill_random_bytes
+ *
+ * Description: fills buf with random numbers - nbytes is the number of bytes
+ * to fill-in. Tries to use /dev/urandom random number generator-
+ * if that fails for some reason, it retries MAX_RETRY times. If
+ * it still fails then it uses srand48(3C)
+ *
+ * Returns: Nothing.
+ */
+static void
+fill_random_bytes(uchar_t *buf, int nbytes)
+{
+ int i, fd, retries = 0;
+
+ fd = open(URANDOM_PATH, O_RDONLY);
+ if (fd >= 0) {
+ while (nbytes > 0) {
+ i = read(fd, buf, nbytes);
+ if ((i < 0) && (errno == EINTR)) {
+ continue;
+ }
+ if (i <= 0) {
+ if (retries++ == MAX_RETRY)
+ break;
+ continue;
+ }
+ nbytes -= i;
+ buf += i;
+ retries = 0;
+ }
+ if (nbytes == 0) {
+ (void) close(fd);
+ return;
+ }
+ }
+ for (i = 0; i < nbytes; i++) {
+ *buf++ = _get_random() & 0xFF;
+ }
+ if (fd >= 0) {
+ (void) close(fd);
+ }
+}
+
+/*
+ * Name: struct_to_string
+ *
+ * Description: Unpacks the structure members in "struct uuid" to a char
+ * string "uuid_t".
+ *
+ * Returns: Nothing.
+ */
+void
+struct_to_string(uuid_t ptr, struct uuid *uu)
+{
+ uint_t tmp;
+ uchar_t *out = ptr;
+
+ tmp = uu->time_low;
+ out[3] = (uchar_t)tmp;
+ tmp >>= 8;
+ out[2] = (uchar_t)tmp;
+ tmp >>= 8;
+ out[1] = (uchar_t)tmp;
+ tmp >>= 8;
+ out[0] = (uchar_t)tmp;
+
+ tmp = uu->time_mid;
+ out[5] = (uchar_t)tmp;
+ tmp >>= 8;
+ out[4] = (uchar_t)tmp;
+
+ tmp = uu->time_hi_and_version;
+ out[7] = (uchar_t)tmp;
+ tmp >>= 8;
+ out[6] = (uchar_t)tmp;
+
+ tmp = uu->clock_seq_hi_and_reserved;
+ out[8] = (uchar_t)tmp;
+ tmp = uu->clock_seq_low;
+ out[9] = (uchar_t)tmp;
+
+ (void) memcpy(out+10, uu->node_addr, 6);
+
+}
+
+/*
+ * Name: string_to_struct
+ *
+ * Description: Packs the values in the "uuid_t" string into "struct uuid".
+ *
+ * Returns: Nothing
+ */
+void
+string_to_struct(struct uuid *uuid, uuid_t in)
+{
+
+ uchar_t *ptr;
+ uint_t tmp;
+
+ ptr = in;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uuid->time_low = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uuid->time_mid = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uuid->time_hi_and_version = tmp;
+
+ tmp = *ptr++;
+ uuid->clock_seq_hi_and_reserved = tmp;
+
+ tmp = *ptr++;
+ uuid->clock_seq_low = tmp;
+
+ (void) memcpy(uuid->node_addr, ptr, 6);
+
+}
+
+/*
+ * Name: uuid_generate_random
+ *
+ * Description: Generates UUID based on DCE Version 4
+ *
+ * Returns: Nothing. uu contains the newly generated UUID
+ */
+void
+uuid_generate_random(uuid_t uu)
+{
+
+ struct uuid uuid;
+
+ if (uu == NULL)
+ return;
+
+ (void) memset(uu, 0, sizeof (uuid_t));
+ (void) memset(&uuid, 0, sizeof (struct uuid));
+
+ fill_random_bytes(uu, sizeof (uuid_t));
+ string_to_struct(&uuid, uu);
+ /*
+ * This is version 4, so say so in the UUID version field (4 bits)
+ */
+ uuid.time_hi_and_version |= (1 << 14);
+ /*
+ * we don't want the bit 1 to be set also which is for version 1
+ */
+ uuid.time_hi_and_version &= VER1_MASK;
+
+ /*
+ * The variant for this format is the 2 high bits set to 10,
+ * so here it is
+ */
+ uuid.clock_seq_hi_and_reserved |= 0x80;
+
+ /*
+ * Set MSB of Ethernet address to 1 to indicate that it was generated
+ * randomly
+ */
+ uuid.node_addr[0] |= 0x80;
+ struct_to_string(uu, &uuid);
+}
+
+/*
+ * Name: uuid_generate_time
+ *
+ * Description: Generates UUID based on DCE Version 1.
+ *
+ * Returns: Nothing. uu contains the newly generated UUID.
+ */
+void
+uuid_generate_time(uuid_t uu)
+{
+ struct uuid uuid;
+
+ if (uu == NULL)
+ return;
+
+ if (uuid_create(&uuid) == -1) {
+ uuid_generate_random(uu);
+ return;
+ }
+ struct_to_string(uu, &uuid);
+}
+
+/*
+ * Name: uuid_generate
+ *
+ * Description: Creates a new UUID. The uuid will be generated based on
+ * high-quality randomness from /dev/urandom, if available by
+ * calling uuid_generate_random. If it failed to generate UUID
+ * then uuid_generate will call uuid_generate_time.
+ *
+ * Returns: Nothing. uu contains the newly generated UUID.
+ */
+void
+uuid_generate(uuid_t uu)
+{
+ int fd;
+
+ if (uu == NULL) {
+ return;
+ }
+ fd = open(URANDOM_PATH, O_RDONLY);
+ if (fd >= 0) {
+ (void) close(fd);
+ uuid_generate_random(uu);
+ } else {
+ (void) uuid_generate_time(uu);
+ }
+}
+
+/*
+ * Name: uuid_copy
+ *
+ * Description: The uuid_copy function copies the UUID variable src to dst
+ *
+ * Returns: Nothing
+ */
+void
+uuid_copy(uuid_t dst, uuid_t src)
+{
+
+ (void) memcpy(dst, src, UUID_LEN);
+}
+
+/*
+ * Name: uuid_clear
+ *
+ * Description: The uuid_clear function sets the value of the supplied uuid
+ * variable uu, to the NULL value.
+ *
+ * Returns: Nothing
+ */
+void
+uuid_clear(uuid_t uu)
+{
+ (void) memset(uu, 0, UUID_LEN);
+}
+
+/*
+ * Name: uuid_unparse
+ *
+ * Description: This function converts the supplied UUID uu from the internal
+ * binary format into a 36-byte string (plus trailing null char)
+ * and stores this value in the character string pointed to by out
+ *
+ * Returns: Nothing.
+ */
+void
+uuid_unparse(uuid_t uu, char *out)
+{
+ struct uuid uuid;
+ uint16_t clock_seq;
+ char etheraddr[13];
+ int index = 0, i;
+
+ /* basic sanity checking */
+ if (uu == NULL) {
+ return;
+ }
+
+ /* XXX user should have allocated enough memory */
+ /*
+ * if (strlen(out) < UUID_PRINTF_SIZE) {
+ * return;
+ * }
+ */
+ string_to_struct(&uuid, uu);
+ clock_seq = uuid.clock_seq_hi_and_reserved;
+ clock_seq = (clock_seq << 8) | uuid.clock_seq_low;
+ for (i = 0; i < 6; i++) {
+ (void) sprintf(&etheraddr[index++], "%.2x", uuid.node_addr[i]);
+ index++;
+ }
+ etheraddr[index] = '\0';
+
+ (void) snprintf(out, 25, "%08x-%04x-%04x-%04x-",
+ uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
+ clock_seq);
+ (void) strlcat(out, etheraddr, UUID_PRINTF_SIZE);
+}
+
+/*
+ * Name: uuid_is_null
+ *
+ * Description: The uuid_is_null function compares the value of the supplied
+ * UUID variable uu to the NULL value. If the value is equal
+ * to the NULL UUID, 1 is returned, otherwise 0 is returned.
+ *
+ * Returns: 0 if uu is NOT null, 1 if uu is NULL.
+ */
+int
+uuid_is_null(uuid_t uu)
+{
+ int i;
+ uuid_t null_uu;
+
+ (void) memset(null_uu, 0, sizeof (uuid_t));
+ i = memcmp(uu, null_uu, sizeof (uuid_t));
+ if (i == 0) {
+ /* uu is NULL uuid */
+ return (1);
+ } else {
+ return (0);
+ }
+}
+
+/*
+ * Name: uuid_parse
+ *
+ * Description: uuid_parse converts the UUID string given by 'in' into the
+ * internal uuid_t format. The input UUID is a string of the form
+ * cefa7a9c-1dd2-11b2-8350-880020adbeef in printf(3C) format.
+ * Upon successfully parsing the input string, UUID is stored
+ * in the location pointed to by uu
+ *
+ * Returns: 0 if the UUID is successfully stored, -1 otherwise.
+ */
+int
+uuid_parse(char *in, uuid_t uu)
+{
+
+ char *ptr, buf[3];
+ int i;
+ struct uuid uuid;
+ uint16_t clock_seq;
+
+ /* do some sanity checking */
+ if ((strlen(in) != 36) || (uu == NULL) || (in[36] != '\0')) {
+ return (-1);
+ }
+
+ ptr = in;
+ for (i = 0; i < 36; i++, ptr++) {
+ if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
+ if (*ptr != '-') {
+ return (-1);
+ }
+ } else {
+ if (!isxdigit(*ptr)) {
+ return (-1);
+ }
+ }
+ }
+
+ uuid.time_low = strtoul(in, NULL, 16);
+ uuid.time_mid = strtoul(in+9, NULL, 16);
+ uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
+ clock_seq = strtoul(in+19, NULL, 16);
+ uuid.clock_seq_hi_and_reserved = (clock_seq & 0xFF00) >> 8;
+ uuid.clock_seq_low = (clock_seq & 0xFF);
+
+ ptr = in+24;
+ buf[2] = '\0';
+ for (i = 0; i < 6; i++) {
+ buf[0] = *ptr++;
+ buf[1] = *ptr++;
+ uuid.node_addr[i] = strtoul(buf, NULL, 16);
+ }
+ struct_to_string(uu, &uuid);
+ return (0);
+}
+
+/*
+ * Name: uuid_time
+ *
+ * Description: uuid_time extracts the time at which the supplied UUID uu
+ * was created. This function can only extract the creation
+ * time for UUIDs created with the uuid_generate_time function.
+ * The time at which the UUID was created, in seconds and
+ * microseconds since the epoch is stored in the location
+ * pointed to by ret_tv.
+ *
+ * Returns: The time at which the UUID was created, in seconds since
+ * January 1, 1970 GMT (the epoch). -1 otherwise.
+ */
+time_t
+uuid_time(uuid_t uu, struct timeval *ret_tv)
+{
+ struct uuid uuid;
+ uint_t high;
+ struct timeval tv;
+ u_longlong_t clock_reg;
+ uint_t tmp;
+ uint8_t clk;
+
+ string_to_struct(&uuid, uu);
+ tmp = (uuid.time_hi_and_version & 0xF000) >> 12;
+ clk = uuid.clock_seq_hi_and_reserved;
+
+ /* check if uu is NULL, Version = 1 of DCE and Variant = 0b10x */
+ if ((uu == NULL) || ((tmp & 0x01) != 0x01) || ((clk & 0x80) != 0x80)) {
+ return (-1);
+ }
+ high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
+ clock_reg = uuid.time_low | ((u_longlong_t)high << 32);
+
+ clock_reg -= (((u_longlong_t)0x01B21DD2) << 32) + 0x13814000;
+ tv.tv_sec = clock_reg / 10000000;
+ tv.tv_usec = (clock_reg % 10000000) / 10;
+
+ if (ret_tv) {
+ *ret_tv = tv;
+ }
+
+ return (tv.tv_sec);
+}
diff --git a/usr/src/lib/libuuid/common/uuid_misc.c b/usr/src/lib/libuuid/common/uuid_misc.c
new file mode 100644
index 0000000000..7aec84fee1
--- /dev/null
+++ b/usr/src/lib/libuuid/common/uuid_misc.c
@@ -0,0 +1,186 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2000,2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * The copyright in this file is taken from the original Leach
+ * & Salz UUID specification, from which this implementation
+ * is derived.
+ */
+
+/*
+ * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+ * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
+ * Digital Equipment Corporation, Maynard, Mass. Copyright (c) 1998
+ * Microsoft. To anyone who acknowledges that this file is provided
+ * "AS IS" without any express or implied warranty: permission to use,
+ * copy, modify, and distribute this file for any purpose is hereby
+ * granted without fee, provided that the above copyright notices and
+ * this notice appears in all source code copies, and that none of the
+ * names of Open Software Foundation, Inc., Hewlett-Packard Company,
+ * or Digital Equipment Corporation be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission. Neither Open Software
+ * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
+ * Equipment Corporation makes any representations about the
+ * suitability of this software for any purpose.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <uuid/uuid.h>
+#include <stdlib.h>
+#include <strings.h>
+#include "uuid_misc.h"
+
+#define UUCMP(u1, u2) if (u1 != u2) return ((u1 < u2) ? -1 : 1)
+#define UUIDS_PER_TOD_CALL 10 /* tv_usec is multiplied by 10 */
+
+void struct_to_string(uuid_t, struct uuid *);
+void string_to_struct(struct uuid *, uuid_t);
+void get_system_time(uuid_time_t *);
+
+/*
+ * Name: _get_current_time
+ *
+ * Description: get-current_time -- get time as 60 bit 100ns ticks
+ * since the beginning of unix time.
+ * Compensate for the fact that real clock resolution is
+ * less than 100ns.
+ *
+ * Returns: None.
+ *
+ */
+void
+_get_current_time(uuid_time_t *timestamp)
+{
+ uuid_time_t time_now;
+ static uuid_time_t time_last = 0;
+ static uint16_t uuids_this_tick = 0;
+ int done;
+
+ done = 0;
+ while (!done) {
+ get_system_time(&time_now);
+
+ /*
+ * if clock reading changed since last UUID generated...
+ */
+ if (time_last != time_now) {
+ /*
+ * reset count of uuids generated with
+ * this clock reading
+ */
+ uuids_this_tick = 0;
+ done = 1;
+ } else {
+ uuids_this_tick++;
+ if (uuids_this_tick < UUIDS_PER_TOD_CALL)
+ done = 1;
+ }
+ /*
+ * too many UUIDs for this gettimeofday call; spin
+ */
+ }
+ time_last = time_now;
+ /*
+ * add the count of uuids to low order bits of the clock reading
+ */
+ *timestamp = time_now + uuids_this_tick;
+}
+
+/*
+ * Name: _get_random
+ *
+ * Description: Gets a random number.
+ *
+ * Returns: nbytes of random information.
+ *
+ */
+uint16_t
+_get_random(void)
+{
+ static int initted = 0;
+ uuid_time_t time_now;
+ long seed;
+
+ if (!initted) {
+ get_system_time(&time_now);
+ time_now = time_now/UUIDS_PER_TOD_CALL;
+ seed = (unsigned)(((time_now >> 32) ^ time_now)&0xffffffff);
+ srand48(seed);
+ initted = 1;
+ }
+ return (mrand48());
+}
+
+/*
+ * Name: uuid_compare
+ *
+ * Description: Compares 2 uuid strings
+ *
+ * Returns: -1 if u1 < u2, 1 if u1 > u2 and 0 if both are equal
+ */
+int
+uuid_compare(uuid_t uu1, uuid_t uu2)
+{
+
+ struct uuid uuid1, uuid2;
+
+ string_to_struct(&uuid1, uu1);
+ string_to_struct(&uuid2, uu2);
+ UUCMP(uuid1.time_low, uuid2.time_low);
+ UUCMP(uuid1.time_mid, uuid2.time_mid);
+ UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
+ UUCMP(uuid1.clock_seq_hi_and_reserved, uuid2.clock_seq_hi_and_reserved);
+ UUCMP(uuid1.clock_seq_low, uuid2.clock_seq_low);
+ return (memcmp(uuid1.node_addr, uuid2.node_addr, 6));
+}
+
+/*
+ * Name: get_system_time
+ *
+ * Description: system dependent call to get the current system time.
+ * Returned as 100ns ticks since Oct 15, 1582, but
+ * resolution may be less than 100ns.
+ *
+ * Returns: None
+ */
+void
+get_system_time(uuid_time_t *uuid_time)
+{
+ struct timeval tp;
+
+ (void) gettimeofday(&tp, (struct timezone *)0);
+
+ /*
+ * Offset between UUID formatted times and Unix formatted times.
+ * UUID UTC base time is October 15, 1582.
+ * Unix base time is January 1, 1970.
+ */
+ *uuid_time = (uint64_t)tp.tv_sec * 10000000;
+ *uuid_time += tp.tv_usec * 10;
+ *uuid_time += 0x01B21DD213814000;
+}
diff --git a/usr/src/lib/libuuid/common/uuid_misc.h b/usr/src/lib/libuuid/common/uuid_misc.h
new file mode 100644
index 0000000000..1504e076dc
--- /dev/null
+++ b/usr/src/lib/libuuid/common/uuid_misc.h
@@ -0,0 +1,78 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2000, 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _UUID_MISC_H
+#define _UUID_MISC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The copyright in this file is taken from the original Leach
+ * & Salz UUID specification, from which this implementation
+ * is derived.
+ */
+
+/*
+ * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+ * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
+ * Digital Equipment Corporation, Maynard, Mass. Copyright (c) 1998
+ * Microsoft. To anyone who acknowledges that this file is provided
+ * "AS IS" without any express or implied warranty: permission to use,
+ * copy, modify, and distribute this file for any purpose is hereby
+ * granted without fee, provided that the above copyright notices and
+ * this notice appears in all source code copies, and that none of the
+ * names of Open Software Foundation, Inc., Hewlett-Packard Company,
+ * or Digital Equipment Corporation be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission. Neither Open Software
+ * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
+ * Equipment Corporation makes any representations about the
+ * suitability of this software for any purpose.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <uuid/uuid.h>
+#include <sys/types.h>
+
+typedef uint64_t uuid_time_t;
+
+/*
+ * data type for UUID generator persistent state
+ */
+typedef struct {
+ uuid_time_t ts; /* saved timestamp */
+ uuid_node_t node; /* saved node ID */
+ uint16_t cs; /* saved clock sequence */
+} uuid_state_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UUID_MISC_H */