diff options
Diffstat (limited to 'usr/src/lib/libuuid/common/etheraddr.c')
-rw-r--r-- | usr/src/lib/libuuid/common/etheraddr.c | 885 |
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); +} |