summaryrefslogtreecommitdiff
path: root/usr/src/lib/libuuid/common/etheraddr.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libuuid/common/etheraddr.c')
-rw-r--r--usr/src/lib/libuuid/common/etheraddr.c885
1 files changed, 885 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);
+}