xref: /titanic_50/usr/src/lib/libuuid/common/etheraddr.c (revision 05fa0d51e3dcc60bf87a28d2fd544362e368a474)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "etheraddr.h"
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <libdevinfo.h>
36 #include <stropts.h>
37 #include <unistd.h>
38 #include <uuid/uuid.h>
39 #include <sys/sockio.h>
40 #include <sys/utsname.h>
41 
42 #include <netdb.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 
46 #include <sys/dlpi.h>
47 /*
48  * debugging flag
49  */
50 static	int	debug = 0;
51 
52 
53 /* Timeout for DLPI acks */
54 static	int	dlpi_timeout = DLPI_TIMEOUT;
55 
56 /*
57  * Global functions
58  */
59 int	dlpi_get_address(char *, struct ether_addr *);
60 int	get_net_if_names(char ***);
61 void	free_net_if_names(char **);
62 
63 
64 /*
65  * local functions
66  */
67 static	int	dlpi_info_req(int, dl_info_ack_t *);
68 static	int	timed_getmsg(int, struct strbuf *, int *, int, char *, char *);
69 static	int	ifrm_num(char *, unsigned int *);
70 static	int	open_dev(dev_att_t *, int, int *, int);
71 static	void	pf_dev_att(dev_att_t *);
72 static	void	parse_ifname(dev_att_t *);
73 static	int	ifname_open(char *, dev_att_t *);
74 static	int	dlpi_open_attach(char *);
75 static	int	dlpi_attach(int, int, int);
76 static	int	dlpi_get_phys(int, uchar_t *);
77 static	int	dlpi_info_req(int, dl_info_ack_t *);
78 static	int	timed_getmsg(int, struct strbuf *, int *, int, char *, char *);
79 
80 /*
81  * get an individual arp entry
82  */
83 int
84 arp_get(uuid_node_t *node)
85 {
86 	struct utsname name;
87 	struct arpreq ar;
88 	struct hostent *hp;
89 	struct sockaddr_in *sin;
90 	int s;
91 
92 	if (uname(&name) == -1) {
93 		return (-1);
94 	}
95 	(void) memset(&ar, 0, sizeof (ar));
96 	ar.arp_pa.sa_family = AF_INET;
97 	/* LINTED pointer */
98 	sin = (struct sockaddr_in *)&ar.arp_pa;
99 	sin->sin_family = AF_INET;
100 	sin->sin_addr.s_addr = inet_addr(name.nodename);
101 	if (sin->sin_addr.s_addr == (in_addr_t)-1) {
102 		hp = gethostbyname(name.nodename);
103 		if (hp == NULL) {
104 			return (-1);
105 		}
106 		(void) memcpy(&sin->sin_addr, hp->h_addr,
107 		    sizeof (sin->sin_addr));
108 	}
109 	s = socket(AF_INET, SOCK_DGRAM, 0);
110 	if (s < 0) {
111 		return (-1);
112 	}
113 	if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) {
114 		(void) close(s);
115 		return (-1);
116 	}
117 	(void) close(s);
118 	if (ar.arp_flags & ATF_COM) {
119 		bcopy(&ar.arp_ha.sa_data, node, 6);
120 	} else
121 		return (-1);
122 	return (0);
123 }
124 
125 
126 /* Get all interface names.  This will include IPv6 names. */
127 int
128 get_net_if_names(char ***names)
129 {
130 	char *buf;		/* buffer for socket info */
131 	int sd;			/* socket descriptor */
132 	int ifn;	/* interface count structure */
133 	struct ifconf ifc;    /* interface config buffer */
134 	struct ifreq *ifrp;
135 	int numifs;
136 	char **tmpnames;
137 	int n;
138 	char *tmpname;
139 	sd = socket(AF_INET, SOCK_DGRAM, 0);
140 	if (sd < 0)
141 		return (-1);
142 
143 	if (ioctl(sd, SIOCGIFNUM, &ifn) < 0) {
144 		(void) close(sd);
145 		return (-1);
146 	}
147 
148 	if (!(buf = malloc(ifn * sizeof (struct ifreq)))) {
149 		(void) close(sd);
150 		return (-1);
151 	}
152 
153 	ifc.ifc_len = ifn * sizeof (struct ifreq);
154 	ifc.ifc_buf = (caddr_t)buf;
155 	if (ioctl(sd, SIOCGIFCONF, (char *)&ifc) < 0) {
156 		free(buf);
157 		(void) close(sd);
158 		return (-1);
159 	}
160 	(void) close(sd);
161 
162 	ifrp = ifc.ifc_req;
163 	numifs = ifc.ifc_len / sizeof (struct ifreq);
164 	tmpnames = (char **)calloc((numifs+1), sizeof (char *));
165 
166 	if (tmpnames == NULL) {
167 		free(buf);
168 		return (-1);
169 	}
170 	for (n = 0; n < numifs; n++, ifrp++) {
171 		if ((tmpnames[n] = strdup(ifrp->ifr_name)) == NULL)
172 			break;
173 	}
174 	free(buf);
175 	*names = tmpnames;
176 	return (0);
177 }
178 
179 /*
180  * frees previously-allocated array from get_net_if_names
181  */
182 void
183 free_net_if_names(char **ifnames)
184 {
185 	int	i;
186 
187 	i = 0;
188 	while (ifnames[i] != NULL) {
189 		free(ifnames[i]);
190 		i++;
191 	}
192 	free(ifnames);
193 }
194 
195 
196 /*
197  * attempt to remove ppa from end of file name
198  * return -1 if none found
199  * return ppa if found and remove the ppa from the filename
200  */
201 static int
202 ifrm_num(char *fname, unsigned int *ppa)
203 {
204 	int	i;
205 	uint_t	p = 0;
206 	unsigned int	m = 1;
207 
208 	i = strlen(fname) - 1;
209 	while (i >= 0 && '0' <= fname[i] && fname[i] <= '9') {
210 		p += (fname[i] - '0')*m;
211 		m *= 10;
212 		i--;
213 	}
214 	if (m == 1) {
215 		return (-1);
216 	}
217 	fname[i + 1] = '\0';
218 	*ppa = p;
219 	return (0);
220 }
221 
222 /*
223  * Open the device defined in dev_att with the given mode starting with
224  * the module indicated by mod_cnt (1 indexed).  If mod_cnt > 0, fd must
225  * contain the file descriptor that modules are to be pushed on.
226  * Returns -1 if device could not be opened, the index of
227  * the module that could not be pushed or 0 on success.
228  */
229 static int
230 open_dev(dev_att_t *dev_att, int mode, int *fd, int mod_cnt)
231 {
232 	int	cnt;
233 	int	local_fd;
234 
235 	if (debug)
236 		(void) printf("open_dev: ifname: %s : dev %s fd %d "
237 		    " mod_cnt %d\n",
238 		    dev_att->ifname, dev_att->devname, *fd, mod_cnt);
239 	/*
240 	 * if no module count is given, try and open the device
241 	 */
242 	if (mod_cnt == 0) {
243 		if (debug)
244 			(void) printf("open_dev: opening %s\n",
245 			    dev_att->devname);
246 		if ((local_fd = open(dev_att->devname, mode)) < 0) {
247 			if (debug) {
248 				perror("open_dev: device");
249 				(void) printf("\n");
250 			}
251 			*fd = local_fd;
252 			return (-1);
253 		}
254 		*fd = local_fd;
255 		cnt = 1;
256 	} else {
257 		local_fd = *fd;
258 		cnt = mod_cnt;
259 	}
260 
261 	/*
262 	 * Try and push modules (if any) onto the device stream
263 	 */
264 	for (; cnt <= dev_att->mod_cnt; cnt++) {
265 		if (debug)
266 			(void) printf(" pushing: mod %s",
267 			    dev_att->modlist[cnt - 1]);
268 		if (ioctl(local_fd, I_PUSH, dev_att->modlist[cnt - 1]) == -1) {
269 			if (debug) {
270 				perror("open_dev: push");
271 				(void) printf("\n");
272 			}
273 			return (cnt);
274 		}
275 	}
276 	if (debug)
277 		(void) printf("\n");
278 	return (0);
279 }
280 
281 /*
282  * Debug routine to print out dev_att_t structure
283  */
284 static void
285 pf_dev_att(dev_att_t *dev_att)
286 {
287 	int cnt;
288 
289 	(void) printf("\tifname: %s\n", dev_att->ifname);
290 	(void) printf("\t  style: %d\n", dev_att->style);
291 	(void) printf("\t  ppa: %d\n", dev_att->ppa);
292 	(void) printf("\t  mod_cnt: %d\n", dev_att->mod_cnt);
293 	(void) printf("\t  devname: %s\n", dev_att->devname);
294 	for (cnt = 0; cnt < dev_att->mod_cnt; cnt++) {
295 		(void) printf("\t      module: %s\n", dev_att->modlist[cnt]);
296 	}
297 }
298 
299 /*
300  * This function parses a '.' delimited interface name of the form
301  * dev[.module[.module...]][:lun]
302  * and places the device and module name into dev_att
303  */
304 static void
305 parse_ifname(dev_att_t *dev_att)
306 {
307 	char		*lunstr;
308 	char		*modlist = NULL; /* list of modules to push */
309 	int		cnt = 0; /* number of modules to push */
310 	char		modbuf[LIFNAMSIZ];
311 	char		*nxtmod;
312 
313 	/*
314 	 * check for specified lun at end of interface and
315 	 * strip it off.
316 	 */
317 	lunstr = strchr(dev_att->ifname, ':');
318 
319 	if (lunstr) {
320 		char *endptr;
321 
322 		*lunstr = '\0';
323 		lunstr++;
324 		endptr = lunstr;
325 		dev_att->lun = strtoul(lunstr, &endptr, 10);
326 
327 		if (endptr == lunstr || *endptr != '\0') {
328 			(void) printf("Invalid logical unit number:%s", lunstr);
329 			exit(-1);
330 		}
331 	} else {
332 		dev_att->lun = 0;
333 	}
334 
335 	(void) strlcpy(modbuf, dev_att->ifname, LIFNAMSIZ);
336 
337 	/* parse '.' delmited module list */
338 	modlist = strchr(modbuf, '.');
339 	if (modlist) {
340 		/* null-terminate interface name (device) */
341 		*modlist = '\0';
342 		modlist++;
343 		if (strlen(modlist) == 0)
344 			modlist = NULL;
345 		while (modlist && cnt < MAX_MODS) {
346 			nxtmod = strchr(modlist, '.');
347 			if (nxtmod) {
348 				*nxtmod = '\0';
349 				nxtmod++;
350 			}
351 			(void) strncpy(dev_att->modlist[cnt], modlist,
352 			    LIFNAMSIZ);
353 			cnt++;
354 			modlist = nxtmod;
355 		}
356 	}
357 	(void) snprintf(dev_att->devname, LIFNAMSIZ, "%s/%s", DEVDIR, modbuf);
358 	dev_att->mod_cnt = cnt;
359 }
360 
361 /*
362  * given a interface name (with possible modules to push)
363  * interface name must have the format of
364  * dev[ppa][.module[.module...][ppa]][:lun]
365  * where only one ppa may be specified e.g. ip0.foo.tun or ip.foo.tun0
366  */
367 static int
368 ifname_open(char *dev_name, dev_att_t *dev_att)
369 {
370 	int		fd;
371 	uint_t		ppa;
372 	int		res;
373 	int		style;
374 	dl_info_ack_t	dl_info;
375 	int		mod_id;
376 
377 	if (debug)
378 		(void) printf("ifname_open: %s\n", dev_name);
379 
380 	if (strlen(dev_name) > LIFNAMSIZ - 1) {
381 		errno = EINVAL;
382 		return (-1);
383 	}
384 
385 	/* save copy of original device name */
386 	(void) strncpy(dev_att->ifname, dev_name, LIFNAMSIZ);
387 
388 	/* parse modules */
389 	parse_ifname(dev_att);
390 
391 	/* try DLPI style 1 device first */
392 
393 	if (debug) {
394 		pf_dev_att(dev_att);
395 	}
396 	mod_id = open_dev(dev_att, O_RDWR, &fd, 0);
397 	if (mod_id != 0) {
398 		if (debug) {
399 			(void) printf("Error on open_dev style 1 mod_id: %d"
400 			    " attemping style 2\n", mod_id);
401 			pf_dev_att(dev_att);
402 		}
403 		if (mod_id == -1) {
404 			res = ifrm_num(dev_att->devname, &ppa);
405 			mod_id = 0;
406 			if (res < 0) {
407 				if (debug)
408 					(void) fprintf(stderr,
409 					    "%s: No such file or directory\n",
410 					    dev_att->devname);
411 				(void) close(fd);
412 				return (-1);
413 			}
414 			/*
415 			 * ensure that it's the last module
416 			 * in the list to extract
417 			 * ppa
418 			 */
419 		} else if ((mod_id != dev_att->mod_cnt) ||
420 		    (res = ifrm_num(dev_att->modlist[dev_att->mod_cnt - 1],
421 			&ppa)) < 0) {
422 			if (debug) {
423 				(void) fprintf(stderr,
424 				    "Error on open_dev style 2 mod_id: %d \n",
425 				    mod_id);
426 			}
427 			if (mod_id == dev_att->mod_cnt)
428 				(void) fprintf(stderr, "libuuid: could not "
429 				    "locate ppa in %s\n",
430 				    dev_att->ifname);
431 			(void) close(fd);
432 			return (-1);
433 		}
434 		goto style2;
435 	}
436 	dev_att->style = 1;
437 	dev_att->ppa = 0;
438 	style = DL_STYLE1;
439 	goto dl_info_chk;
440 style2:
441 	dev_att->ppa = ppa;
442 	mod_id = open_dev(dev_att, O_RDWR, &fd, mod_id);
443 	if (mod_id != 0) {
444 		if (debug) {
445 			(void) fprintf(stderr,
446 			    "Error on open_dev style 2 mod_id: %d \n",
447 			    mod_id);
448 			if (mod_id > 0) {
449 				(void) fprintf(stderr, "%s: No such module\n",
450 				    dev_att->modlist[mod_id - 2]);
451 			}
452 			pf_dev_att(dev_att);
453 		}
454 		(void) close(fd);
455 		return (-1);
456 	}
457 	dev_att->style = 2;
458 	style = DL_STYLE2;
459 dl_info_chk:
460 	if (dlpi_info_req(fd, &dl_info) < 0) {
461 		(void) close(fd);
462 		pf_dev_att(dev_att);
463 		return (-1);
464 	}
465 	if (dl_info.dl_provider_style != style) {
466 		if (debug) {
467 			(void) fprintf(stderr, "DLPI provider style mismatch: "
468 			    "expected style %s got style %s (0x%lx)\n",
469 			    style == DL_STYLE1 ? "1" : "2",
470 			    dl_info.dl_provider_style == DL_STYLE1 ? "1" : "2",
471 			    dl_info.dl_provider_style);
472 		}
473 		(void) close(fd);
474 		return (-1);
475 	}
476 	if (debug) {
477 		(void) printf("pars_dev_att() success\n");
478 		pf_dev_att(dev_att);
479 	}
480 	return (fd);
481 }
482 
483 static int
484 dlpi_open_attach(char *ifname)
485 {
486 	int			fd;
487 	dev_att_t		dev_att;
488 
489 	if (debug)
490 		(void) printf("dlpi_open_attach %s\n", ifname);
491 
492 	/* if lun is specified fail (backwards compat) */
493 	if (strchr(ifname, ':') != NULL) {
494 		return (-1);
495 	}
496 	if ((fd = ifname_open(ifname, &dev_att)) < 0) {
497 		/* Not found */
498 		errno = ENXIO;
499 		return (-1);
500 	}
501 	if (dlpi_attach(fd, dev_att.ppa, dev_att.style) < 0) {
502 		(void) close(fd);
503 		return (-1);
504 	}
505 	return (fd);
506 }
507 
508 static int
509 dlpi_attach(int fd, int ppa, int style)
510 {
511 	union DL_primitives	*dlp;
512 	char			*buf;
513 	struct strbuf		ctl;
514 	int			flags;
515 
516 	if (style != 2)
517 		return (0);
518 
519 	/* Allocate required buffers */
520 	if ((buf = malloc(BUFSIZ)) == NULL) {
521 		(void) fprintf(stderr, "libuuid: malloc() failed\n");
522 		return (-1);
523 	}
524 
525 	/* Issue DL_ATTACH_REQ */
526 	/* LINTED: malloc returns a pointer aligned for any use */
527 	dlp = (union DL_primitives *)buf;
528 	dlp->attach_req.dl_primitive = DL_ATTACH_REQ;
529 	dlp->attach_req.dl_ppa = ppa;
530 	ctl.buf = (char *)dlp;
531 	ctl.len = DL_ATTACH_REQ_SIZE;
532 	if (putmsg(fd, &ctl, NULL, 0) < 0) {
533 		perror("libuuid: putmsg");
534 		free(buf);
535 		return (-1);
536 	}
537 
538 	/* read reply */
539 	ctl.buf = (char *)dlp;
540 	ctl.len = 0;
541 	ctl.maxlen = BUFSIZ;
542 	flags = 0;
543 
544 	/* start timeout for DL_OK_ACK reply */
545 	if (timed_getmsg(fd, &ctl, &flags, dlpi_timeout,
546 	    "DL_OK_ACK", "DL_ATTACH_REQ") == 0) {
547 		free(buf);
548 		return (-1);
549 	}
550 
551 	if (debug) {
552 		(void) printf("ok_ack: ctl.len[%d] flags[%d]\n", ctl.len,
553 		    flags);
554 	}
555 
556 	/* Validate DL_OK_ACK reply.  */
557 	if (ctl.len < sizeof (t_uscalar_t)) {
558 		(void) fprintf(stderr,
559 		    "libuuid: attach failed: short reply to attach request\n");
560 		free(buf);
561 		return (-1);
562 	}
563 
564 	if (dlp->dl_primitive == DL_ERROR_ACK) {
565 		if (debug)
566 			(void) fprintf(stderr,
567 			    "attach failed:  dl_errno %lu errno %lu\n",
568 			    dlp->error_ack.dl_errno,
569 			    dlp->error_ack.dl_unix_errno);
570 		free(buf);
571 		errno = ENXIO;
572 		return (-1);
573 	}
574 	if (dlp->dl_primitive != DL_OK_ACK) {
575 		(void) fprintf(stderr,
576 		    "libuuid: attach failed: "
577 		    "unrecognizable dl_primitive %lu received",
578 		    dlp->dl_primitive);
579 		free(buf);
580 		return (-1);
581 	}
582 	if (ctl.len < DL_OK_ACK_SIZE) {
583 		(void) fprintf(stderr,
584 		    "libuuid: attach failed: "
585 		    "short attach acknowledgement received\n");
586 		free(buf);
587 		return (-1);
588 	}
589 	if (dlp->ok_ack.dl_correct_primitive != DL_ATTACH_REQ) {
590 		(void) fprintf(stderr,
591 		    "libuuid: attach failed: "
592 		    "returned prim %lu != requested prim %lu\n",
593 		    dlp->ok_ack.dl_correct_primitive,
594 		    (t_uscalar_t)DL_ATTACH_REQ);
595 		free(buf);
596 		return (-1);
597 	}
598 	if (debug)
599 		(void) printf("attach done\n");
600 
601 	free(buf);
602 	return (0);
603 }
604 
605 static int
606 dlpi_get_phys(int fd, uchar_t *eaddr)
607 {
608 	union DL_primitives	*dlp;
609 	char			*buf;
610 	struct strbuf		ctl;
611 	int			flags;
612 
613 	/* Allocate required buffers */
614 	if ((buf = malloc(BUFSIZ)) == NULL) {
615 		(void) fprintf(stderr, "libuuid: malloc() failed\n");
616 		return (-1);
617 	}
618 	/* Issue DL_PHYS_ADDR_REQ */
619 	/* LINTED: malloc returns a pointer aligned for any use */
620 	dlp = (union DL_primitives *)buf;
621 	dlp->physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
622 	dlp->physaddr_req.dl_addr_type = DL_CURR_PHYS_ADDR;
623 	ctl.buf = (char *)dlp;
624 	ctl.len = DL_PHYS_ADDR_REQ_SIZE;
625 	if (putmsg(fd, &ctl, NULL, 0) < 0) {
626 		perror("libuuid: putmsg");
627 		free(buf);
628 		return (-1);
629 	}
630 
631 	/* read reply */
632 	ctl.buf = (char *)dlp;
633 	ctl.len = 0;
634 	ctl.maxlen = BUFSIZ;
635 	flags = 0;
636 
637 	if (timed_getmsg(fd, &ctl, &flags, dlpi_timeout,
638 	    "DL_PHYS_ADDR_ACK", "DL_PHYS_ADDR_REQ (DL_CURR_PHYS_ADDR)") == 0) {
639 		free(buf);
640 		return (-1);
641 	}
642 
643 	if (debug) {
644 		(void) printf("phys_addr_ack: ctl.len[%d] flags[%d]\n", ctl.len,
645 		    flags);
646 	}
647 
648 	/* Validate DL_PHYS_ADDR_ACK reply.  */
649 	if (ctl.len < sizeof (t_uscalar_t)) {
650 		(void) fprintf(stderr, "libuuid: phys_addr failed: "
651 		    "short reply to phys_addr request\n");
652 		free(buf);
653 		return (-1);
654 	}
655 
656 	if (dlp->dl_primitive == DL_ERROR_ACK) {
657 		/*
658 		 * Do not print errors for DL_UNSUPPORTED and DL_NOTSUPPORTED
659 		 */
660 		if (dlp->error_ack.dl_errno != DL_UNSUPPORTED &&
661 		    dlp->error_ack.dl_errno != DL_NOTSUPPORTED) {
662 			(void) fprintf(stderr, "libuuid: phys_addr failed: "
663 			    "dl_errno %lu errno %lu\n",
664 			    dlp->error_ack.dl_errno,
665 			    dlp->error_ack.dl_unix_errno);
666 		}
667 		free(buf);
668 		return (-1);
669 	}
670 	if (dlp->dl_primitive != DL_PHYS_ADDR_ACK) {
671 		(void) fprintf(stderr, "libuuid: phys_addr failed: "
672 		    "unrecognizable dl_primitive %lu received\n",
673 		    dlp->dl_primitive);
674 		free(buf);
675 		return (-1);
676 	}
677 	if (ctl.len < DL_PHYS_ADDR_ACK_SIZE) {
678 		(void) fprintf(stderr, "libuuid: phys_addr failed: "
679 		    "short phys_addr acknowledgement received\n");
680 		free(buf);
681 		return (-1);
682 	}
683 	/* Check length of address. */
684 	if (dlp->physaddr_ack.dl_addr_length != ETHERADDRL) {
685 		free(buf);
686 		return (-1);
687 	}
688 
689 	/* copy Ethernet address */
690 	(void) memcpy(eaddr, &buf[dlp->physaddr_ack.dl_addr_offset],
691 	    ETHERADDRL);
692 
693 	free(buf);
694 	return (0);
695 }
696 
697 
698 
699 static int
700 dlpi_info_req(int fd, dl_info_ack_t *info_ack)
701 {
702 	dl_info_req_t   info_req;
703 	int	buf[BUFSIZ/sizeof (int)];
704 	union DL_primitives	*dlp = (union DL_primitives *)buf;
705 	struct  strbuf  ctl;
706 	int	flags;
707 
708 	info_req.dl_primitive = DL_INFO_REQ;
709 
710 	ctl.len = DL_INFO_REQ_SIZE;
711 	ctl.buf = (char *)&info_req;
712 
713 	flags = RS_HIPRI;
714 
715 	if (putmsg(fd, &ctl, (struct strbuf *)NULL, flags) < 0) {
716 		perror("libuuid: putmsg");
717 		return (-1);
718 	}
719 
720 	/* read reply */
721 	ctl.buf = (char *)dlp;
722 	ctl.len = 0;
723 	ctl.maxlen = BUFSIZ;
724 	flags = 0;
725 	/* start timeout for DL_BIND_ACK reply */
726 	if (timed_getmsg(fd, &ctl, &flags, dlpi_timeout, "DL_INFO_ACK",
727 	    "DL_INFO_ACK") == 0) {
728 		return (-1);
729 	}
730 
731 	if (debug) {
732 		(void) printf("info_ack: ctl.len[%d] flags[%d]\n", ctl.len,
733 		    flags);
734 	}
735 
736 	/* Validate DL_BIND_ACK reply.  */
737 	if (ctl.len < sizeof (t_uscalar_t)) {
738 		(void) fprintf(stderr,
739 		    "libuuid: info req failed: short reply to info request\n");
740 		return (-1);
741 	}
742 
743 	if (dlp->dl_primitive == DL_ERROR_ACK) {
744 		(void) fprintf(stderr,
745 		    "libuuid: info req failed:  dl_errno %lu errno %lu\n",
746 		    dlp->error_ack.dl_errno, dlp->error_ack.dl_unix_errno);
747 		return (-1);
748 	}
749 	if (dlp->dl_primitive != DL_INFO_ACK) {
750 		(void) fprintf(stderr,
751 		    "libuuid: info req failed: "
752 		    "unrecognizable dl_primitive %lu received\n",
753 		    dlp->dl_primitive);
754 		return (-1);
755 	}
756 	if (ctl.len < DL_INFO_ACK_SIZE) {
757 		(void) fprintf(stderr,
758 		    "libuuid: info req failed: "
759 		    "short info acknowledgement received\n");
760 		return (-1);
761 	}
762 	*info_ack = *(dl_info_ack_t *)dlp;
763 	return (0);
764 }
765 
766 
767 /*
768  * interface called from libuuid to get the ethernet address - jhf
769  */
770 int
771 dlpi_get_address(char *ifname, struct ether_addr *ea)
772 {
773 	int 	fd;
774 
775 	if (debug)
776 		(void) printf("dlpi_get_address: dlpi_open_attach\t");
777 	fd = dlpi_open_attach(ifname);
778 	if (fd < 0) {
779 		/* Do not report an error */
780 		return (-1);
781 	}
782 
783 	if (debug)
784 		(void) printf("dlpi_get_address: dlpi_get_phys %s\n", ifname);
785 	if (dlpi_get_phys(fd, (uchar_t *)ea) < 0) {
786 		(void) close(fd);
787 		return (-1);
788 	}
789 	(void) close(fd);
790 	return (0);
791 }
792 
793 static int
794 timed_getmsg(int fd, struct strbuf *ctlp, int *flagsp, int timeout, char *kind,
795     char *request)
796 {
797 	char		perrorbuf[BUFSIZ];
798 	struct pollfd	pfd;
799 	int		ret;
800 
801 	pfd.fd = fd;
802 
803 	pfd.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
804 	if ((ret = poll(&pfd, 1, timeout * 1000)) == 0) {
805 		(void) fprintf(stderr, "libuuid: %s timed out\n", kind);
806 		return (0);
807 	} else if (ret == -1) {
808 		(void) snprintf(perrorbuf, sizeof (perrorbuf),
809 		    "libuuid: poll for %s from %s", kind, request);
810 		perror(perrorbuf);
811 		return (0);
812 	}
813 
814 	/* poll returned > 0 for this fd so getmsg should not block */
815 	if ((ret = getmsg(fd, ctlp, NULL, flagsp)) < 0) {
816 		(void) snprintf(perrorbuf, sizeof (perrorbuf),
817 		    "libuuid: getmsg expecting %s for %s", kind, request);
818 		perror(perrorbuf);
819 		return (0);
820 	}
821 
822 	return (1);
823 }
824 
825 /*
826  * Name:	get_ethernet_address
827  *
828  * Description:	Obtains the system ethernet address.
829  *
830  * Returns:	0 on success, non-zero otherwise.  The system ethernet
831  *		address is copied into the passed-in variable.
832  */
833 int
834 get_ethernet_address(uuid_node_t *node)
835 {
836 	char			**ifnames;
837 	char			*ifname;
838 	int			i;
839 	struct ether_addr	addr;
840 	int			found;
841 
842 	if (arp_get(node) == 0)
843 		return (0);
844 
845 	/*
846 	 * go get all interface names
847 	 */
848 	if (get_net_if_names(&ifnames) != 0) {
849 		return (-1);
850 	}
851 
852 	/*
853 	 * Assume failure
854 	 */
855 	found = -1;
856 
857 	/*
858 	 * for each interface, query it through dlpi to get its physical
859 	 * (ethernet) address
860 	 */
861 	if (ifnames != NULL) {
862 		i = 0;
863 		while ((ifnames[i] != NULL) && found) {
864 			ifname = ifnames[i];
865 			/* Gross hack to avoid getting errors from /dev/lo0 */
866 			if (strcmp(ifname, LOOPBACK_IF) != 0) {
867 				if (dlpi_get_address(ifname, &addr) == 0) {
868 					bcopy(&addr, node, 6);
869 					/*
870 					 * found one, set result to successful
871 					 */
872 					found = 0;
873 					continue;
874 				}
875 			}
876 			i++;
877 		}
878 		free_net_if_names(ifnames);
879 	}
880 
881 	/*
882 	 * Couldn't get ethernet address from any interfaces...
883 	 */
884 	return (found);
885 }
886