xref: /titanic_50/usr/src/cmd/cmd-inet/usr.sbin/in.rarpd.c (revision 948f2876ce2a3010558f4f6937e16086ebcd36f2)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*948f2876Sss150715  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
267c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
307c478bd9Sstevel@tonic-gate  * under license from the Regents of the University of California.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate /*
367c478bd9Sstevel@tonic-gate  * rarpd.c  Reverse-ARP server.
377c478bd9Sstevel@tonic-gate  * Refer to RFC 903 "A Reverse Address Resolution Protocol".
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #define	_REENTRANT
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include	<thread.h>
437c478bd9Sstevel@tonic-gate #include	<synch.h>
447c478bd9Sstevel@tonic-gate #include	<stdlib.h>
457c478bd9Sstevel@tonic-gate #include	<unistd.h>
467c478bd9Sstevel@tonic-gate #include	<sys/resource.h>
477c478bd9Sstevel@tonic-gate #include	<stdio.h>
48004388ebScasper #include	<stdio_ext.h>
497c478bd9Sstevel@tonic-gate #include	<stdarg.h>
507c478bd9Sstevel@tonic-gate #include	<string.h>
517c478bd9Sstevel@tonic-gate #include	<fcntl.h>
527c478bd9Sstevel@tonic-gate #include	<sys/types.h>
537c478bd9Sstevel@tonic-gate #include	<dirent.h>
547c478bd9Sstevel@tonic-gate #include	<syslog.h>
557c478bd9Sstevel@tonic-gate #include	<netdb.h>
567c478bd9Sstevel@tonic-gate #include	<errno.h>
577c478bd9Sstevel@tonic-gate #include	<sys/socket.h>
587c478bd9Sstevel@tonic-gate #include	<sys/sockio.h>
597c478bd9Sstevel@tonic-gate #include	<net/if.h>
607c478bd9Sstevel@tonic-gate #include	<netinet/if_ether.h>
617c478bd9Sstevel@tonic-gate #include	<netinet/in.h>
627c478bd9Sstevel@tonic-gate #include	<arpa/inet.h>
637c478bd9Sstevel@tonic-gate #include	<stropts.h>
647c478bd9Sstevel@tonic-gate #include	<libinetutil.h>
65*948f2876Sss150715 #include	<libdlpi.h>
667c478bd9Sstevel@tonic-gate #include	<net/if_types.h>
677c478bd9Sstevel@tonic-gate #include	<net/if_dl.h>
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate #define	BOOTDIR		"/tftpboot"	/* boot files directory */
707c478bd9Sstevel@tonic-gate #define	DEVIP		"/dev/ip"	/* path to ip driver */
717c478bd9Sstevel@tonic-gate #define	DEVARP		"/dev/arp"	/* path to arp driver */
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #define	BUFSIZE		2048		/* max receive frame length */
747c478bd9Sstevel@tonic-gate #define	MAXPATHL	128		/* max path length */
757c478bd9Sstevel@tonic-gate #define	MAXHOSTL	128		/* max host name length */
767c478bd9Sstevel@tonic-gate #define	MAXIFS		256
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * Logical network devices
807c478bd9Sstevel@tonic-gate  */
817c478bd9Sstevel@tonic-gate struct	ifdev {
827c478bd9Sstevel@tonic-gate 	char		ldevice[IFNAMSIZ];
837c478bd9Sstevel@tonic-gate 	int		lunit;
847c478bd9Sstevel@tonic-gate 	ipaddr_t	ipaddr;			/* network order */
857c478bd9Sstevel@tonic-gate 	ipaddr_t	if_netmask;		/* host order */
867c478bd9Sstevel@tonic-gate 	ipaddr_t	if_ipaddr;		/* host order */
877c478bd9Sstevel@tonic-gate 	ipaddr_t	if_netnum;		/* host order, with subnet */
887c478bd9Sstevel@tonic-gate 	struct ifdev *next;
897c478bd9Sstevel@tonic-gate };
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate  * Physical network device
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate struct	rarpdev {
95*948f2876Sss150715 	char		device[DLPI_LINKNAME_MAX];
96*948f2876Sss150715 	uint_t		unit;
97*948f2876Sss150715 	dlpi_handle_t	dh_rarp;
98*948f2876Sss150715 	uchar_t		physaddr[DLPI_PHYSADDR_MAX];
99*948f2876Sss150715 						/* mac address of interface */
100*948f2876Sss150715 	uint_t		physaddrlen;		/* mac address length */
1017c478bd9Sstevel@tonic-gate 	int		ifrarplen;		/* size of rarp data packet */
1027c478bd9Sstevel@tonic-gate 	struct ifdev	*ifdev;			/* private interface info */
1037c478bd9Sstevel@tonic-gate 	struct rarpdev	*next;			/* list of managed devices */
1047c478bd9Sstevel@tonic-gate };
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate struct	rarpreply {
1077c478bd9Sstevel@tonic-gate 	struct rarpdev		*rdev;		/* which device reply for */
1087c478bd9Sstevel@tonic-gate 	struct timeval		tv;		/* send RARP reply by when */
1097c478bd9Sstevel@tonic-gate 	uchar_t			*lldest;	/* target mac to send reply */
1107c478bd9Sstevel@tonic-gate 	uchar_t			*arprep;	/* [R]ARP response */
1117c478bd9Sstevel@tonic-gate 	struct rarpreply	*next;
1127c478bd9Sstevel@tonic-gate };
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate static struct rarpreply	*delay_list;
1157c478bd9Sstevel@tonic-gate static sema_t		delay_sema;
1167c478bd9Sstevel@tonic-gate static mutex_t		delay_mutex;
1177c478bd9Sstevel@tonic-gate static mutex_t		debug_mutex;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static struct rarpdev	*rarpdev_head;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * Globals initialized before multi-threading
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate static char	*cmdname;		/* command name from argv[0] */
1257c478bd9Sstevel@tonic-gate static int	dflag = 0;		/* enable diagnostics */
1267c478bd9Sstevel@tonic-gate static int	aflag = 0;		/* start rarpd on all interfaces */
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static void	getintf(void);
1297c478bd9Sstevel@tonic-gate static struct rarpdev *find_device(ifspec_t *);
1307c478bd9Sstevel@tonic-gate static void	init_rarpdev(struct rarpdev *);
1317c478bd9Sstevel@tonic-gate static void	do_rarp(void *);
1327c478bd9Sstevel@tonic-gate static void	rarp_request(struct rarpdev *, struct arphdr *,
1337c478bd9Sstevel@tonic-gate 		    uchar_t *);
1347c478bd9Sstevel@tonic-gate static void	add_arp(struct rarpdev *, uchar_t *, uchar_t *);
1357c478bd9Sstevel@tonic-gate static void	arp_request(struct rarpdev *, struct arphdr *, uchar_t *);
1367c478bd9Sstevel@tonic-gate static void	do_delay_write(void *);
1377c478bd9Sstevel@tonic-gate static void	delay_write(struct rarpdev *, struct rarpreply *);
1387c478bd9Sstevel@tonic-gate static int	mightboot(ipaddr_t);
1397c478bd9Sstevel@tonic-gate static void	get_ifdata(char *, int, ipaddr_t *, ipaddr_t *);
1407c478bd9Sstevel@tonic-gate static int	get_ipaddr(struct rarpdev *, uchar_t *, uchar_t *, ipaddr_t *);
1417c478bd9Sstevel@tonic-gate static int	strioctl(int, int, int, int, char *);
1427c478bd9Sstevel@tonic-gate static void	usage();
143*948f2876Sss150715 static void	syserr(const char *);
144*948f2876Sss150715 /*PRINTFLIKE1*/
145*948f2876Sss150715 static void	error(const char *, ...);
1467c478bd9Sstevel@tonic-gate static void	debug(char *, ...);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate extern	int	optind;
1497c478bd9Sstevel@tonic-gate extern	char	*optarg;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate int
1527c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	int		c;
1557c478bd9Sstevel@tonic-gate 	struct rlimit rl;
1567c478bd9Sstevel@tonic-gate 	struct rarpdev	*rdev;
1577c478bd9Sstevel@tonic-gate 	int		i;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	cmdname = argv[0];
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "ad")) != -1) {
1627c478bd9Sstevel@tonic-gate 		switch (c) {
1637c478bd9Sstevel@tonic-gate 		case 'a':
1647c478bd9Sstevel@tonic-gate 			aflag = 1;
1657c478bd9Sstevel@tonic-gate 			break;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 		case 'd':
1687c478bd9Sstevel@tonic-gate 			dflag = 1;
1697c478bd9Sstevel@tonic-gate 			break;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		default:
1727c478bd9Sstevel@tonic-gate 			usage();
1737c478bd9Sstevel@tonic-gate 		}
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	if ((!aflag && (argc - optind) != 2) ||
1777c478bd9Sstevel@tonic-gate 	    (aflag && (argc - optind) != 0)) {
1787c478bd9Sstevel@tonic-gate 		usage();
1797c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	if (!dflag) {
1837c478bd9Sstevel@tonic-gate 		/*
1847c478bd9Sstevel@tonic-gate 		 * Background
1857c478bd9Sstevel@tonic-gate 		 */
1867c478bd9Sstevel@tonic-gate 		switch (fork()) {
1877c478bd9Sstevel@tonic-gate 			case -1:	/* error */
1887c478bd9Sstevel@tonic-gate 				syserr("fork");
1897c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 			case 0:		/* child */
1927c478bd9Sstevel@tonic-gate 				break;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 			default:	/* parent */
1957c478bd9Sstevel@tonic-gate 				return (0);
1967c478bd9Sstevel@tonic-gate 		}
1977c478bd9Sstevel@tonic-gate 		for (i = 0; i < 3; i++) {
1987c478bd9Sstevel@tonic-gate 			(void) close(i);
1997c478bd9Sstevel@tonic-gate 		}
2007c478bd9Sstevel@tonic-gate 		(void) open("/", O_RDONLY, 0);
2017c478bd9Sstevel@tonic-gate 		(void) dup2(0, 1);
2027c478bd9Sstevel@tonic-gate 		(void) dup2(0, 2);
2037c478bd9Sstevel@tonic-gate 		/*
2047c478bd9Sstevel@tonic-gate 		 * Detach terminal
2057c478bd9Sstevel@tonic-gate 		 */
2067c478bd9Sstevel@tonic-gate 		if (setsid() < 0)
2077c478bd9Sstevel@tonic-gate 			syserr("setsid");
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	rl.rlim_cur = RLIM_INFINITY;
2117c478bd9Sstevel@tonic-gate 	rl.rlim_max = RLIM_INFINITY;
2127c478bd9Sstevel@tonic-gate 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
2137c478bd9Sstevel@tonic-gate 		syserr("setrlimit");
214004388ebScasper 	(void) enable_extended_FILE_stdio(-1, -1);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	(void) openlog(cmdname, LOG_PID, LOG_DAEMON);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	if (aflag) {
2197c478bd9Sstevel@tonic-gate 		/*
220*948f2876Sss150715 		 * Get each interface name and load rarpdev list.
2217c478bd9Sstevel@tonic-gate 		 */
2227c478bd9Sstevel@tonic-gate 		getintf();
2237c478bd9Sstevel@tonic-gate 	} else {
2247c478bd9Sstevel@tonic-gate 		ifspec_t	ifsp;
2257c478bd9Sstevel@tonic-gate 		struct ifdev	*ifdev;
2267c478bd9Sstevel@tonic-gate 		char		buf[IFNAMSIZ + 1];
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 		/*
229*948f2876Sss150715 		 * Load specified device as only element of the list.
2307c478bd9Sstevel@tonic-gate 		 */
2317c478bd9Sstevel@tonic-gate 		rarpdev_head = (struct rarpdev *)calloc(1,
2327c478bd9Sstevel@tonic-gate 		    sizeof (struct rarpdev));
2337c478bd9Sstevel@tonic-gate 		if (rarpdev_head == NULL) {
2347c478bd9Sstevel@tonic-gate 			error("out of memory");
2357c478bd9Sstevel@tonic-gate 		}
2367c478bd9Sstevel@tonic-gate 		(void) strncpy(buf, argv[optind], IFNAMSIZ);
2377c478bd9Sstevel@tonic-gate 		(void) strncat(buf, argv[optind + 1], IFNAMSIZ - strlen(buf));
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 		if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL) {
2407c478bd9Sstevel@tonic-gate 			error("out of memory");
2417c478bd9Sstevel@tonic-gate 		}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 		if (!ifparse_ifspec(buf, &ifsp) || ifsp.ifsp_modcnt != 0) {
2447c478bd9Sstevel@tonic-gate 			error("invalid interface specification");
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 		if (ifsp.ifsp_lunvalid) {
2487c478bd9Sstevel@tonic-gate 			(void) snprintf(ifdev->ldevice,
2497c478bd9Sstevel@tonic-gate 			    sizeof (ifdev->ldevice), "%s%d:",
2507c478bd9Sstevel@tonic-gate 			    ifsp.ifsp_devnm, ifsp.ifsp_ppa);
2517c478bd9Sstevel@tonic-gate 			ifdev->lunit = ifsp.ifsp_lun;
252*948f2876Sss150715 		} else {
2537c478bd9Sstevel@tonic-gate 			ifdev->lunit = -1; /* no logical unit */
254*948f2876Sss150715 		}
2557c478bd9Sstevel@tonic-gate 		(void) strlcpy(rarpdev_head->device, ifsp.ifsp_devnm,
2567c478bd9Sstevel@tonic-gate 		    sizeof (rarpdev_head->device));
2577c478bd9Sstevel@tonic-gate 		rarpdev_head->unit = ifsp.ifsp_ppa;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 		ifdev->next = rarpdev_head->ifdev;
2607c478bd9Sstevel@tonic-gate 		rarpdev_head->ifdev = ifdev;
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	/*
264*948f2876Sss150715 	 * Initialize each rarpdev.
2657c478bd9Sstevel@tonic-gate 	 */
2667c478bd9Sstevel@tonic-gate 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
2677c478bd9Sstevel@tonic-gate 		init_rarpdev(rdev);
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	(void) sema_init(&delay_sema, 0, USYNC_THREAD, NULL);
2717c478bd9Sstevel@tonic-gate 	(void) mutex_init(&delay_mutex, USYNC_THREAD, NULL);
2727c478bd9Sstevel@tonic-gate 	(void) mutex_init(&debug_mutex, USYNC_THREAD, NULL);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	/*
275*948f2876Sss150715 	 * Start delayed processing thread.
2767c478bd9Sstevel@tonic-gate 	 */
2777c478bd9Sstevel@tonic-gate 	(void) thr_create(NULL, NULL, (void *(*)(void *))do_delay_write, NULL,
2787c478bd9Sstevel@tonic-gate 	    THR_NEW_LWP, NULL);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	/*
281*948f2876Sss150715 	 * Start RARP processing for each device.
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
284*948f2876Sss150715 		if (rdev->dh_rarp != NULL) {
2857c478bd9Sstevel@tonic-gate 			(void) thr_create(NULL, NULL,
2867c478bd9Sstevel@tonic-gate 			    (void *(*)(void *))do_rarp, (void *)rdev,
2877c478bd9Sstevel@tonic-gate 			    THR_NEW_LWP, NULL);
2887c478bd9Sstevel@tonic-gate 		}
2897c478bd9Sstevel@tonic-gate 	}
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	/*
2927c478bd9Sstevel@tonic-gate 	 * Exit main() thread
2937c478bd9Sstevel@tonic-gate 	 */
2947c478bd9Sstevel@tonic-gate 	thr_exit(NULL);
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	return (0);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate static void
3007c478bd9Sstevel@tonic-gate getintf(void)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate 	int		fd;
3037c478bd9Sstevel@tonic-gate 	int		numifs;
3047c478bd9Sstevel@tonic-gate 	unsigned	bufsize;
3057c478bd9Sstevel@tonic-gate 	struct ifreq	*reqbuf;
3067c478bd9Sstevel@tonic-gate 	struct ifconf	ifconf;
3077c478bd9Sstevel@tonic-gate 	struct ifreq	*ifr;
3087c478bd9Sstevel@tonic-gate 	struct rarpdev	*rdev;
3097c478bd9Sstevel@tonic-gate 	struct ifdev	*ifdev;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	/*
3127c478bd9Sstevel@tonic-gate 	 * Open the IP provider.
3137c478bd9Sstevel@tonic-gate 	 */
3147c478bd9Sstevel@tonic-gate 	if ((fd = open(DEVIP, 0)) < 0)
3157c478bd9Sstevel@tonic-gate 		syserr(DEVIP);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	/*
3187c478bd9Sstevel@tonic-gate 	 * Ask IP for the list of configured interfaces.
3197c478bd9Sstevel@tonic-gate 	 */
3207c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) {
3217c478bd9Sstevel@tonic-gate 		numifs = MAXIFS;
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate 	bufsize = numifs * sizeof (struct ifreq);
3247c478bd9Sstevel@tonic-gate 	reqbuf = (struct ifreq *)malloc(bufsize);
3257c478bd9Sstevel@tonic-gate 	if (reqbuf == NULL) {
3267c478bd9Sstevel@tonic-gate 		error("out of memory");
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	ifconf.ifc_len = bufsize;
3307c478bd9Sstevel@tonic-gate 	ifconf.ifc_buf = (caddr_t)reqbuf;
3317c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFCONF, (char *)&ifconf) < 0)
3327c478bd9Sstevel@tonic-gate 		syserr("SIOCGIFCONF");
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	/*
335*948f2876Sss150715 	 * Initialize a rarpdev for each interface.
3367c478bd9Sstevel@tonic-gate 	 */
3377c478bd9Sstevel@tonic-gate 	for (ifr = ifconf.ifc_req; ifconf.ifc_len > 0;
3387c478bd9Sstevel@tonic-gate 	    ifr++, ifconf.ifc_len -= sizeof (struct ifreq)) {
3397c478bd9Sstevel@tonic-gate 		ifspec_t	ifsp;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 		if (ioctl(fd, SIOCGIFFLAGS, (char *)ifr) < 0) {
3427c478bd9Sstevel@tonic-gate 			syserr("ioctl SIOCGIFFLAGS");
3437c478bd9Sstevel@tonic-gate 			exit(1);
3447c478bd9Sstevel@tonic-gate 		}
3457c478bd9Sstevel@tonic-gate 		if ((ifr->ifr_flags & IFF_LOOPBACK) ||
3467c478bd9Sstevel@tonic-gate 		    !(ifr->ifr_flags & IFF_UP) ||
3477c478bd9Sstevel@tonic-gate 		    !(ifr->ifr_flags & IFF_BROADCAST) ||
3487c478bd9Sstevel@tonic-gate 		    (ifr->ifr_flags & IFF_NOARP) ||
3497c478bd9Sstevel@tonic-gate 		    (ifr->ifr_flags & IFF_POINTOPOINT))
3507c478bd9Sstevel@tonic-gate 			continue;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		if (!ifparse_ifspec(ifr->ifr_name, &ifsp))
3537c478bd9Sstevel@tonic-gate 			error("ifparse_ifspec failed");
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 		/*
356*948f2876Sss150715 		 * Look for an existing device for logical interfaces.
3577c478bd9Sstevel@tonic-gate 		 */
3587c478bd9Sstevel@tonic-gate 		if ((rdev = find_device(&ifsp)) == NULL) {
3597c478bd9Sstevel@tonic-gate 			rdev = calloc(1, sizeof (struct rarpdev));
3607c478bd9Sstevel@tonic-gate 			if (rdev == NULL)
3617c478bd9Sstevel@tonic-gate 				error("out of memory");
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 			(void) strlcpy(rdev->device, ifsp.ifsp_devnm,
3647c478bd9Sstevel@tonic-gate 			    sizeof (rdev->device));
3657c478bd9Sstevel@tonic-gate 			rdev->unit = ifsp.ifsp_ppa;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 			rdev->next = rarpdev_head;
3687c478bd9Sstevel@tonic-gate 			rarpdev_head = rdev;
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 		if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL)
3727c478bd9Sstevel@tonic-gate 			error("out of memory");
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 		if (ifsp.ifsp_lunvalid) {
3757c478bd9Sstevel@tonic-gate 			(void) snprintf(ifdev->ldevice,
3767c478bd9Sstevel@tonic-gate 			    sizeof (ifdev->ldevice), "%s%d:",
3777c478bd9Sstevel@tonic-gate 			    ifsp.ifsp_devnm, ifsp.ifsp_ppa);
3787c478bd9Sstevel@tonic-gate 			ifdev->lunit = ifsp.ifsp_lun;
3797c478bd9Sstevel@tonic-gate 		} else
3807c478bd9Sstevel@tonic-gate 			ifdev->lunit = -1; /* no logical unit */
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 		ifdev->next = rdev->ifdev;
3837c478bd9Sstevel@tonic-gate 		rdev->ifdev = ifdev;
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 	(void) free((char *)reqbuf);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate static struct rarpdev *
3897c478bd9Sstevel@tonic-gate find_device(ifspec_t *specp)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	struct rarpdev	*rdev;
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
3947c478bd9Sstevel@tonic-gate 		if (specp->ifsp_ppa == rdev->unit &&
3957c478bd9Sstevel@tonic-gate 		    strcmp(specp->ifsp_devnm, rdev->device) == 0)
3967c478bd9Sstevel@tonic-gate 			return (rdev);
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 	return (NULL);
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate static void
4027c478bd9Sstevel@tonic-gate init_rarpdev(struct rarpdev *rdev)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	char 		*dev;
4057c478bd9Sstevel@tonic-gate 	int 		unit;
4067c478bd9Sstevel@tonic-gate 	struct ifdev 	*ifdev;
407*948f2876Sss150715 	int		retval;
408*948f2876Sss150715 	char		*str = NULL;
409*948f2876Sss150715 	uint_t		physaddrlen = DLPI_PHYSADDR_MAX;
410*948f2876Sss150715 	char		linkname[DLPI_LINKNAME_MAX];
411*948f2876Sss150715 	dlpi_handle_t	dh;
4127c478bd9Sstevel@tonic-gate 
413*948f2876Sss150715 	(void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", rdev->device,
414*948f2876Sss150715 	    rdev->unit);
4157c478bd9Sstevel@tonic-gate 	/*
4167c478bd9Sstevel@tonic-gate 	 * Open datalink provider and get our mac address.
4177c478bd9Sstevel@tonic-gate 	 */
418*948f2876Sss150715 	if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) {
419*948f2876Sss150715 		error("cannot open link %s: %s", linkname,
420*948f2876Sss150715 		    dlpi_strerror(retval));
421*948f2876Sss150715 	}
422*948f2876Sss150715 
423*948f2876Sss150715 	if ((retval = dlpi_bind(dh, ETHERTYPE_REVARP, NULL)) != DLPI_SUCCESS) {
424*948f2876Sss150715 		dlpi_close(dh);
425*948f2876Sss150715 		error("dlpi_bind failed: %s", dlpi_strerror(retval));
426*948f2876Sss150715 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	/*
429*948f2876Sss150715 	 * Save our mac address.
4307c478bd9Sstevel@tonic-gate 	 */
431*948f2876Sss150715 	if ((retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, rdev->physaddr,
432*948f2876Sss150715 	    &physaddrlen)) != DLPI_SUCCESS) {
433*948f2876Sss150715 		dlpi_close(dh);
434*948f2876Sss150715 		error("dlpi_get_physaddr failed: %s", dlpi_strerror(retval));
4357c478bd9Sstevel@tonic-gate 	}
4367c478bd9Sstevel@tonic-gate 
437*948f2876Sss150715 	rdev->physaddrlen = physaddrlen;
438*948f2876Sss150715 	rdev->ifrarplen = sizeof (struct arphdr) + (2 * sizeof (ipaddr_t)) +
439*948f2876Sss150715 	    (2 * physaddrlen);
440*948f2876Sss150715 
441*948f2876Sss150715 	if (dflag) {
442*948f2876Sss150715 		str = _link_ntoa(rdev->physaddr, str,
443*948f2876Sss150715 		    rdev->physaddrlen, IFT_OTHER);
444*948f2876Sss150715 		if (str != NULL) {
445*948f2876Sss150715 			debug("device %s physical address %s", linkname, str);
446*948f2876Sss150715 			free(str);
447*948f2876Sss150715 		}
448*948f2876Sss150715 	}
449*948f2876Sss150715 
450*948f2876Sss150715 	/*
451*948f2876Sss150715 	 * Assign dlpi handle to rdev.
452*948f2876Sss150715 	 */
453*948f2876Sss150715 	rdev->dh_rarp = dh;
454*948f2876Sss150715 
4557c478bd9Sstevel@tonic-gate 	/*
4567c478bd9Sstevel@tonic-gate 	 * Get the IP address and netmask from directory service for
4577c478bd9Sstevel@tonic-gate 	 * each logical interface.
4587c478bd9Sstevel@tonic-gate 	 */
4597c478bd9Sstevel@tonic-gate 	for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
4607c478bd9Sstevel@tonic-gate 		/*
461*948f2876Sss150715 		 * If lunit == -1 then this is the primary interface name.
4627c478bd9Sstevel@tonic-gate 		 */
4637c478bd9Sstevel@tonic-gate 		if (ifdev->lunit == -1) {
4647c478bd9Sstevel@tonic-gate 			dev = rdev->device;
4657c478bd9Sstevel@tonic-gate 			unit = rdev->unit;
4667c478bd9Sstevel@tonic-gate 		} else {
4677c478bd9Sstevel@tonic-gate 			dev = ifdev->ldevice;
4687c478bd9Sstevel@tonic-gate 			unit = ifdev->lunit;
4697c478bd9Sstevel@tonic-gate 		}
4707c478bd9Sstevel@tonic-gate 		get_ifdata(dev, unit, &ifdev->if_ipaddr, &ifdev->if_netmask);
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		/*
4737c478bd9Sstevel@tonic-gate 		 * Use IP address of the interface.
4747c478bd9Sstevel@tonic-gate 		 */
4757c478bd9Sstevel@tonic-gate 		ifdev->if_netnum = ifdev->if_ipaddr & ifdev->if_netmask;
4767c478bd9Sstevel@tonic-gate 		ifdev->ipaddr = (ipaddr_t)htonl(ifdev->if_ipaddr);
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate static void
4817c478bd9Sstevel@tonic-gate do_rarp(void *buf)
4827c478bd9Sstevel@tonic-gate {
483*948f2876Sss150715 	struct rarpdev *rdev = buf;
4847c478bd9Sstevel@tonic-gate 	char	*cause;
4857c478bd9Sstevel@tonic-gate 	struct arphdr *ans;
4867c478bd9Sstevel@tonic-gate 	uchar_t *shost;
487*948f2876Sss150715 	uint_t	saddrlen;
488*948f2876Sss150715 	size_t	anslen = rdev->ifrarplen;
4897c478bd9Sstevel@tonic-gate 	char	*str = NULL;
490*948f2876Sss150715 	int	retval;
4917c478bd9Sstevel@tonic-gate 
492*948f2876Sss150715 	if (((shost = malloc(rdev->physaddrlen)) == NULL) ||
493*948f2876Sss150715 	    ((ans = malloc(rdev->ifrarplen)) == NULL))
4947c478bd9Sstevel@tonic-gate 		syserr("malloc");
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	if (dflag) {
497*948f2876Sss150715 		str = _link_ntoa(rdev->physaddr, str, rdev->physaddrlen,
498*948f2876Sss150715 		    IFT_OTHER);
4997c478bd9Sstevel@tonic-gate 		if (str != NULL) {
500*948f2876Sss150715 			debug("starting rarp service on device %s%d physical"
501*948f2876Sss150715 			    " address %s", rdev->device, rdev->unit, str);
5027c478bd9Sstevel@tonic-gate 			free(str);
5037c478bd9Sstevel@tonic-gate 		}
5047c478bd9Sstevel@tonic-gate 	}
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	/*
507*948f2876Sss150715 	 * Read RARP packets and respond to them.
5087c478bd9Sstevel@tonic-gate 	 */
5097c478bd9Sstevel@tonic-gate 	for (;;) {
510*948f2876Sss150715 		saddrlen = DLPI_PHYSADDR_MAX;
511*948f2876Sss150715 		retval = dlpi_recv(rdev->dh_rarp, shost,
512*948f2876Sss150715 		    &saddrlen, ans, &anslen, -1, NULL);
513*948f2876Sss150715 		if (retval == DLPI_ETIMEDOUT) {
5147c478bd9Sstevel@tonic-gate 			continue;
515*948f2876Sss150715 		} else if (retval != DLPI_SUCCESS) {
516*948f2876Sss150715 			error("error in dlpi_recv %s: %s", rdev->dh_rarp,
517*948f2876Sss150715 			    dlpi_strerror(retval));
5187c478bd9Sstevel@tonic-gate 		}
5197c478bd9Sstevel@tonic-gate 
520*948f2876Sss150715 		cause = NULL;
521*948f2876Sss150715 
522*948f2876Sss150715 		if (anslen < rdev->ifrarplen)
523*948f2876Sss150715 			cause = "short packet";
524*948f2876Sss150715 		else if (ans->ar_hrd != htons(ARPHRD_ETHER))
525*948f2876Sss150715 			cause = "hardware type not Ethernet";
526*948f2876Sss150715 		else if (ans->ar_pro != htons(ETHERTYPE_IP))
527*948f2876Sss150715 			cause = "protocol type not IP";
528*948f2876Sss150715 		else if (ans->ar_hln != rdev->physaddrlen)
529*948f2876Sss150715 			cause = "unexpected hardware address length";
530*948f2876Sss150715 		else if (ans->ar_pln != sizeof (ipaddr_t))
531*948f2876Sss150715 			cause = "unexpected protocol address length";
532*948f2876Sss150715 		if (cause != NULL) {
533*948f2876Sss150715 			if (dflag)
534*948f2876Sss150715 				debug("RARP packet received but "
535*948f2876Sss150715 				    "discarded: %s", cause);
536*948f2876Sss150715 			continue;
537*948f2876Sss150715 		}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 		/*
5407c478bd9Sstevel@tonic-gate 		 * Handle the request.
5417c478bd9Sstevel@tonic-gate 		 */
5427c478bd9Sstevel@tonic-gate 		switch (ntohs(ans->ar_op)) {
5437c478bd9Sstevel@tonic-gate 		case REVARP_REQUEST:
5447c478bd9Sstevel@tonic-gate 			rarp_request(rdev, ans, shost);
5457c478bd9Sstevel@tonic-gate 			break;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 		case ARPOP_REQUEST:
5487c478bd9Sstevel@tonic-gate 			arp_request(rdev, ans, shost);
5497c478bd9Sstevel@tonic-gate 			break;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 		case REVARP_REPLY:
5527c478bd9Sstevel@tonic-gate 			if (dflag)
5537c478bd9Sstevel@tonic-gate 				debug("REVARP_REPLY ignored");
5547c478bd9Sstevel@tonic-gate 			break;
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 		case ARPOP_REPLY:
5577c478bd9Sstevel@tonic-gate 			if (dflag)
5587c478bd9Sstevel@tonic-gate 				debug("ARPOP_REPLY ignored");
5597c478bd9Sstevel@tonic-gate 			break;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 		default:
5627c478bd9Sstevel@tonic-gate 			if (dflag)
5637c478bd9Sstevel@tonic-gate 				debug("unknown opcode 0x%x", ans->ar_op);
5647c478bd9Sstevel@tonic-gate 			break;
5657c478bd9Sstevel@tonic-gate 		}
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate /*
5707c478bd9Sstevel@tonic-gate  * Reverse address determination and allocation code.
5717c478bd9Sstevel@tonic-gate  */
5727c478bd9Sstevel@tonic-gate static void
5737c478bd9Sstevel@tonic-gate rarp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost)
5747c478bd9Sstevel@tonic-gate {
5757c478bd9Sstevel@tonic-gate 	ipaddr_t		tpa,  spa;
5767c478bd9Sstevel@tonic-gate 	struct	rarpreply	*rrp;
5777c478bd9Sstevel@tonic-gate 	uchar_t			*shap, *thap, *spap, *tpap;
5787c478bd9Sstevel@tonic-gate 	char			*str = NULL;
579*948f2876Sss150715 	int			retval;
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	shap = (uchar_t *)rp + sizeof (struct arphdr);
5827c478bd9Sstevel@tonic-gate 	spap = shap + rp->ar_hln;
5837c478bd9Sstevel@tonic-gate 	thap = spap + rp->ar_pln;
5847c478bd9Sstevel@tonic-gate 	tpap = thap + rp->ar_hln;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	if (dflag) {
587*948f2876Sss150715 		str = _link_ntoa(thap, str, rdev->physaddrlen, IFT_OTHER);
5887c478bd9Sstevel@tonic-gate 		if (str != NULL) {
5897c478bd9Sstevel@tonic-gate 			debug("RARP_REQUEST for %s", str);
5907c478bd9Sstevel@tonic-gate 			free(str);
5917c478bd9Sstevel@tonic-gate 		}
5927c478bd9Sstevel@tonic-gate 	}
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	/*
595*948f2876Sss150715 	 * Third party lookups are rare and wonderful.
5967c478bd9Sstevel@tonic-gate 	 */
597*948f2876Sss150715 	if ((memcmp(shap, thap, rdev->physaddrlen) != 0) ||
598*948f2876Sss150715 	    (memcmp(shap, shost, rdev->physaddrlen) != 0)) {
5997c478bd9Sstevel@tonic-gate 		if (dflag)
6007c478bd9Sstevel@tonic-gate 			debug("weird (3rd party lookup)");
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	/*
604*948f2876Sss150715 	 * Fill in given parts of reply packet.
6057c478bd9Sstevel@tonic-gate 	 */
606*948f2876Sss150715 	(void) memcpy(shap, rdev->physaddr, rdev->physaddrlen);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	/*
6097c478bd9Sstevel@tonic-gate 	 * If a good address is stored in our lookup tables, return it
610*948f2876Sss150715 	 * immediately or after a delay.  Store it in our kernel's ARP cache.
6117c478bd9Sstevel@tonic-gate 	 */
6127c478bd9Sstevel@tonic-gate 	if (get_ipaddr(rdev, thap, tpap, &spa))
6137c478bd9Sstevel@tonic-gate 		return;
6147c478bd9Sstevel@tonic-gate 	(void) memcpy(spap, &spa, sizeof (spa));
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	add_arp(rdev, tpap, thap);
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	rp->ar_op = htons(REVARP_REPLY);
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	if (dflag) {
6217c478bd9Sstevel@tonic-gate 		struct in_addr addr;
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		(void) memcpy(&addr, tpap, sizeof (ipaddr_t));
6247c478bd9Sstevel@tonic-gate 		debug("good lookup, maps to %s", inet_ntoa(addr));
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 
627*948f2876Sss150715 	rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen +
628*948f2876Sss150715 	    rdev->ifrarplen);
6297c478bd9Sstevel@tonic-gate 	if (rrp == NULL)
6307c478bd9Sstevel@tonic-gate 		error("out of memory");
6317c478bd9Sstevel@tonic-gate 	rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply);
632*948f2876Sss150715 	rrp->arprep = rrp->lldest + rdev->physaddrlen;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	/*
6357c478bd9Sstevel@tonic-gate 	 * Create rarpreply structure.
6367c478bd9Sstevel@tonic-gate 	 */
6377c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&rrp->tv, NULL);
6387c478bd9Sstevel@tonic-gate 	rrp->tv.tv_sec += 3;	/* delay */
6397c478bd9Sstevel@tonic-gate 	rrp->rdev = rdev;
640*948f2876Sss150715 	(void) memcpy(rrp->lldest, shost, rdev->physaddrlen);
6417c478bd9Sstevel@tonic-gate 	(void) memcpy(rrp->arprep, rp, rdev->ifrarplen);
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	/*
6447c478bd9Sstevel@tonic-gate 	 * If this is diskless and we're not its bootserver, let the
6457c478bd9Sstevel@tonic-gate 	 * bootserver reply first by delaying a while.
6467c478bd9Sstevel@tonic-gate 	 */
6477c478bd9Sstevel@tonic-gate 	(void) memcpy(&tpa, tpap, sizeof (ipaddr_t));
6487c478bd9Sstevel@tonic-gate 	if (mightboot(ntohl(tpa))) {
649*948f2876Sss150715 		retval = dlpi_send(rdev->dh_rarp, rrp->lldest,
650*948f2876Sss150715 		    rdev->physaddrlen, rrp->arprep, rdev->ifrarplen, NULL);
651*948f2876Sss150715 		if (retval != DLPI_SUCCESS) {
652*948f2876Sss150715 			error("dlpi_send failed: %s", dlpi_strerror(retval));
653*948f2876Sss150715 		} else if (dflag) {
6547c478bd9Sstevel@tonic-gate 			debug("immediate reply sent");
655*948f2876Sss150715 		}
6567c478bd9Sstevel@tonic-gate 		(void) free(rrp);
6577c478bd9Sstevel@tonic-gate 	} else {
6587c478bd9Sstevel@tonic-gate 		delay_write(rdev, rrp);
6597c478bd9Sstevel@tonic-gate 	}
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate /*
6637c478bd9Sstevel@tonic-gate  * Download an ARP entry into our kernel.
6647c478bd9Sstevel@tonic-gate  */
6657c478bd9Sstevel@tonic-gate static void
6667c478bd9Sstevel@tonic-gate add_arp(struct rarpdev *rdev, uchar_t *ip, uchar_t *laddr)
6677c478bd9Sstevel@tonic-gate {
6687c478bd9Sstevel@tonic-gate 	struct xarpreq ar;
6697c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin;
6707c478bd9Sstevel@tonic-gate 	int	fd;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	/*
673*948f2876Sss150715 	 * Common part of query or set.
6747c478bd9Sstevel@tonic-gate 	 */
6757c478bd9Sstevel@tonic-gate 	(void) memset(&ar, 0, sizeof (ar));
6767c478bd9Sstevel@tonic-gate 	ar.xarp_pa.ss_family = AF_INET;
6777c478bd9Sstevel@tonic-gate 	sin = (struct sockaddr_in *)&ar.xarp_pa;
6787c478bd9Sstevel@tonic-gate 	(void) memcpy(&sin->sin_addr, ip, sizeof (ipaddr_t));
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	/*
6817c478bd9Sstevel@tonic-gate 	 * Open the IP provider.
6827c478bd9Sstevel@tonic-gate 	 */
6837c478bd9Sstevel@tonic-gate 	if ((fd = open(DEVARP, 0)) < 0)
6847c478bd9Sstevel@tonic-gate 		syserr(DEVARP);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	/*
687*948f2876Sss150715 	 * Set the entry.
6887c478bd9Sstevel@tonic-gate 	 */
689*948f2876Sss150715 	(void) memcpy(LLADDR(&ar.xarp_ha), laddr, rdev->physaddrlen);
690*948f2876Sss150715 	ar.xarp_ha.sdl_alen = rdev->physaddrlen;
6917c478bd9Sstevel@tonic-gate 	ar.xarp_ha.sdl_family = AF_LINK;
6927c478bd9Sstevel@tonic-gate 	(void) strioctl(fd, SIOCDXARP, -1, sizeof (struct xarpreq),
6937c478bd9Sstevel@tonic-gate 	    (char *)&ar);
6947c478bd9Sstevel@tonic-gate 	if (strioctl(fd, SIOCSXARP, -1, sizeof (struct xarpreq),
6957c478bd9Sstevel@tonic-gate 	    (char *)&ar) < 0)
6967c478bd9Sstevel@tonic-gate 		syserr("SIOCSXARP");
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	(void) close(fd);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate  * The RARP spec says we must be able to process ARP requests,
7037c478bd9Sstevel@tonic-gate  * even through the packet type is RARP.  Let's hope this feature
7047c478bd9Sstevel@tonic-gate  * is not heavily used.
7057c478bd9Sstevel@tonic-gate  */
7067c478bd9Sstevel@tonic-gate static void
7077c478bd9Sstevel@tonic-gate arp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost)
7087c478bd9Sstevel@tonic-gate {
7097c478bd9Sstevel@tonic-gate 	struct	rarpreply	*rrp;
7107c478bd9Sstevel@tonic-gate 	struct ifdev		*ifdev;
7117c478bd9Sstevel@tonic-gate 	uchar_t			*shap, *thap, *spap, *tpap;
712*948f2876Sss150715 	int			retval;
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	shap = (uchar_t *)rp + sizeof (struct arphdr);
7157c478bd9Sstevel@tonic-gate 	spap = shap + rp->ar_hln;
7167c478bd9Sstevel@tonic-gate 	thap = spap + rp->ar_pln;
7177c478bd9Sstevel@tonic-gate 	tpap = thap + rp->ar_hln;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	if (dflag)
7207c478bd9Sstevel@tonic-gate 		debug("ARPOP_REQUEST");
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
7237c478bd9Sstevel@tonic-gate 		if (memcmp(&ifdev->ipaddr, tpap, sizeof (ipaddr_t)) == 0)
7247c478bd9Sstevel@tonic-gate 			break;
7257c478bd9Sstevel@tonic-gate 	}
7267c478bd9Sstevel@tonic-gate 	if (ifdev == NULL)
7277c478bd9Sstevel@tonic-gate 		return;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	rp->ar_op = ARPOP_REPLY;
730*948f2876Sss150715 	(void) memcpy(shap, rdev->physaddr, rdev->physaddrlen);
7317c478bd9Sstevel@tonic-gate 	(void) memcpy(spap, &ifdev->ipaddr, sizeof (ipaddr_t));
732*948f2876Sss150715 	(void) memcpy(thap, rdev->physaddr, rdev->physaddrlen);
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	add_arp(rdev, tpap, thap);
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	/*
7377c478bd9Sstevel@tonic-gate 	 * Create rarp reply structure.
7387c478bd9Sstevel@tonic-gate 	 */
739*948f2876Sss150715 	rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen +
740*948f2876Sss150715 	    rdev->ifrarplen);
7417c478bd9Sstevel@tonic-gate 	if (rrp == NULL)
7427c478bd9Sstevel@tonic-gate 		error("out of memory");
7437c478bd9Sstevel@tonic-gate 	rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply);
744*948f2876Sss150715 	rrp->arprep = rrp->lldest + rdev->physaddrlen;
7457c478bd9Sstevel@tonic-gate 	rrp->rdev = rdev;
7467c478bd9Sstevel@tonic-gate 
747*948f2876Sss150715 	(void) memcpy(rrp->lldest, shost, rdev->physaddrlen);
7487c478bd9Sstevel@tonic-gate 	(void) memcpy(rrp->arprep, rp, rdev->ifrarplen);
7497c478bd9Sstevel@tonic-gate 
750*948f2876Sss150715 	retval = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen,
751*948f2876Sss150715 	    rrp->arprep, rdev->ifrarplen, NULL);
7527c478bd9Sstevel@tonic-gate 	free(rrp);
753*948f2876Sss150715 	if (retval != DLPI_SUCCESS)
754*948f2876Sss150715 		error("dlpi_send failed: %s", dlpi_strerror(retval));
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate /* ARGSUSED */
7587c478bd9Sstevel@tonic-gate static void
7597c478bd9Sstevel@tonic-gate do_delay_write(void *buf)
7607c478bd9Sstevel@tonic-gate {
7617c478bd9Sstevel@tonic-gate 	struct	timeval		tv;
7627c478bd9Sstevel@tonic-gate 	struct	rarpreply	*rrp;
763*948f2876Sss150715 	struct	rarpdev		*rdev;
7647c478bd9Sstevel@tonic-gate 	int			err;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	for (;;) {
7677c478bd9Sstevel@tonic-gate 		if ((err = sema_wait(&delay_sema)) != 0) {
7687c478bd9Sstevel@tonic-gate 			if (err == EINTR)
7697c478bd9Sstevel@tonic-gate 				continue;
7707c478bd9Sstevel@tonic-gate 			error("do_delay_write: sema_wait failed");
7717c478bd9Sstevel@tonic-gate 		}
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&delay_mutex);
7747c478bd9Sstevel@tonic-gate 		rrp = delay_list;
775*948f2876Sss150715 		rdev = rrp->rdev;
7767c478bd9Sstevel@tonic-gate 		delay_list = delay_list->next;
7777c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&delay_mutex);
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 		(void) gettimeofday(&tv, NULL);
7807c478bd9Sstevel@tonic-gate 		if (tv.tv_sec < rrp->tv.tv_sec)
7817c478bd9Sstevel@tonic-gate 			(void) sleep(rrp->tv.tv_sec - tv.tv_sec);
7827c478bd9Sstevel@tonic-gate 
783*948f2876Sss150715 		err = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen,
784*948f2876Sss150715 		    rrp->arprep, rdev->ifrarplen, NULL);
785*948f2876Sss150715 		if (err != DLPI_SUCCESS)
786*948f2876Sss150715 			error("dlpi_send failed: %s", dlpi_strerror(err));
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 		(void) free(rrp);
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate /* ARGSUSED */
7937c478bd9Sstevel@tonic-gate static void
7947c478bd9Sstevel@tonic-gate delay_write(struct rarpdev *rdev, struct rarpreply *rrp)
7957c478bd9Sstevel@tonic-gate {
7967c478bd9Sstevel@tonic-gate 	struct	rarpreply	*trp;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&delay_mutex);
7997c478bd9Sstevel@tonic-gate 	if (delay_list == NULL) {
8007c478bd9Sstevel@tonic-gate 		delay_list = rrp;
8017c478bd9Sstevel@tonic-gate 	} else {
8027c478bd9Sstevel@tonic-gate 		trp = delay_list;
8037c478bd9Sstevel@tonic-gate 		while (trp->next != NULL)
8047c478bd9Sstevel@tonic-gate 			trp = trp->next;
8057c478bd9Sstevel@tonic-gate 		trp->next = rrp;
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&delay_mutex);
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	(void) sema_post(&delay_sema);
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate /*
8137c478bd9Sstevel@tonic-gate  * See if we have a TFTP boot file for this guy. Filenames in TFTP
8147c478bd9Sstevel@tonic-gate  * boot requests are of the form <ipaddr> for Sun-3's and of the form
8157c478bd9Sstevel@tonic-gate  * <ipaddr>.<arch> for all other architectures.  Since we don't know
8167c478bd9Sstevel@tonic-gate  * the client's architecture, either format will do.
8177c478bd9Sstevel@tonic-gate  */
8187c478bd9Sstevel@tonic-gate static int
8197c478bd9Sstevel@tonic-gate mightboot(ipaddr_t ipa)
8207c478bd9Sstevel@tonic-gate {
8217c478bd9Sstevel@tonic-gate 	char path[MAXPATHL];
8227c478bd9Sstevel@tonic-gate 	DIR *dirp;
8237c478bd9Sstevel@tonic-gate 	struct dirent *dp;
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s/%08X", BOOTDIR, ipa);
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	/*
8287c478bd9Sstevel@tonic-gate 	 * Try a quick access() first.
8297c478bd9Sstevel@tonic-gate 	 */
8307c478bd9Sstevel@tonic-gate 	if (access(path, 0) == 0)
8317c478bd9Sstevel@tonic-gate 		return (1);
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	/*
8347c478bd9Sstevel@tonic-gate 	 * Not there, do it the slow way by
8357c478bd9Sstevel@tonic-gate 	 * reading through the directory.
8367c478bd9Sstevel@tonic-gate 	 */
8377c478bd9Sstevel@tonic-gate 	(void) sprintf(path, "%08X", ipa);
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	if (!(dirp = opendir(BOOTDIR)))
8407c478bd9Sstevel@tonic-gate 		return (0);
8417c478bd9Sstevel@tonic-gate 
8424bc0a2efScasper 	while ((dp = readdir(dirp)) != NULL) {
8437c478bd9Sstevel@tonic-gate 		if (strncmp(dp->d_name, path, 8) != 0)
8447c478bd9Sstevel@tonic-gate 			continue;
8457c478bd9Sstevel@tonic-gate 		if ((strlen(dp->d_name) != 8) && (dp->d_name[8] != '.'))
8467c478bd9Sstevel@tonic-gate 			continue;
8477c478bd9Sstevel@tonic-gate 		break;
8487c478bd9Sstevel@tonic-gate 	}
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	(void) closedir(dirp);
8517c478bd9Sstevel@tonic-gate 
852*948f2876Sss150715 	return ((dp != NULL) ? 1 : 0);
8537c478bd9Sstevel@tonic-gate }
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate /*
8567c478bd9Sstevel@tonic-gate  * Get our IP address and local netmask.
8577c478bd9Sstevel@tonic-gate  */
8587c478bd9Sstevel@tonic-gate static void
8597c478bd9Sstevel@tonic-gate get_ifdata(char *dev, int unit, ipaddr_t *ipp, ipaddr_t *maskp)
8607c478bd9Sstevel@tonic-gate {
8617c478bd9Sstevel@tonic-gate 	int	fd;
8627c478bd9Sstevel@tonic-gate 	struct	ifreq	ifr;
8637c478bd9Sstevel@tonic-gate 	struct	sockaddr_in	*sin;
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	/* LINTED pointer */
8667c478bd9Sstevel@tonic-gate 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	/*
8697c478bd9Sstevel@tonic-gate 	 * Open the IP provider.
8707c478bd9Sstevel@tonic-gate 	 */
8717c478bd9Sstevel@tonic-gate 	if ((fd = open(DEVIP, 0)) < 0)
8727c478bd9Sstevel@tonic-gate 		syserr(DEVIP);
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	/*
8757c478bd9Sstevel@tonic-gate 	 * Ask IP for our IP address.
8767c478bd9Sstevel@tonic-gate 	 */
8777c478bd9Sstevel@tonic-gate 	(void) snprintf(ifr.ifr_name, sizeof (ifr.ifr_name), "%s%d", dev, unit);
8787c478bd9Sstevel@tonic-gate 	if (strioctl(fd, SIOCGIFADDR, -1, sizeof (struct ifreq),
8797c478bd9Sstevel@tonic-gate 	    (char *)&ifr) < 0)
8807c478bd9Sstevel@tonic-gate 		syserr("SIOCGIFADDR");
8817c478bd9Sstevel@tonic-gate 	*ipp = (ipaddr_t)ntohl(sin->sin_addr.s_addr);
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	if (dflag)
884*948f2876Sss150715 		debug("device %s%d address %s", dev, unit,
885*948f2876Sss150715 		    inet_ntoa(sin->sin_addr));
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	/*
8887c478bd9Sstevel@tonic-gate 	 * Ask IP for our netmask.
8897c478bd9Sstevel@tonic-gate 	 */
8907c478bd9Sstevel@tonic-gate 	if (strioctl(fd, SIOCGIFNETMASK, -1, sizeof (struct ifreq),
8917c478bd9Sstevel@tonic-gate 	    (char *)&ifr) < 0)
8927c478bd9Sstevel@tonic-gate 		syserr("SIOCGIFNETMASK");
8937c478bd9Sstevel@tonic-gate 	*maskp = (ipaddr_t)ntohl(sin->sin_addr.s_addr);
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	if (dflag)
896*948f2876Sss150715 		debug("device %s%d subnet mask %s", dev, unit,
897*948f2876Sss150715 		    inet_ntoa(sin->sin_addr));
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	/*
9007c478bd9Sstevel@tonic-gate 	 * Thankyou ip.
9017c478bd9Sstevel@tonic-gate 	 */
9027c478bd9Sstevel@tonic-gate 	(void) close(fd);
9037c478bd9Sstevel@tonic-gate }
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate /*
9067c478bd9Sstevel@tonic-gate  * Translate mac address to IP address.
9077c478bd9Sstevel@tonic-gate  * Return 0 on success, nonzero on failure.
9087c478bd9Sstevel@tonic-gate  */
9097c478bd9Sstevel@tonic-gate static int
9107c478bd9Sstevel@tonic-gate get_ipaddr(struct rarpdev *rdev, uchar_t *laddr, uchar_t *ipp, ipaddr_t *ipaddr)
9117c478bd9Sstevel@tonic-gate {
9127c478bd9Sstevel@tonic-gate 	char host[MAXHOSTL];
9137c478bd9Sstevel@tonic-gate 	char hbuffer[BUFSIZE];
9147c478bd9Sstevel@tonic-gate 	struct hostent *hp, res;
9157c478bd9Sstevel@tonic-gate 	int herror;
9167c478bd9Sstevel@tonic-gate 	struct in_addr addr;
9177c478bd9Sstevel@tonic-gate 	char	**p;
9187c478bd9Sstevel@tonic-gate 	struct ifdev *ifdev;
9197c478bd9Sstevel@tonic-gate 
920*948f2876Sss150715 	if (rdev->physaddrlen != ETHERADDRL) {
9217c478bd9Sstevel@tonic-gate 		if (dflag)
9227c478bd9Sstevel@tonic-gate 			debug("%s %s", " cannot map non 6 byte hardware ",
9237c478bd9Sstevel@tonic-gate 			    "address to IP address");
9247c478bd9Sstevel@tonic-gate 		return (1);
9257c478bd9Sstevel@tonic-gate 	}
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	/*
928*948f2876Sss150715 	 * Translate mac address to hostname and IP address.
9297c478bd9Sstevel@tonic-gate 	 */
9307c478bd9Sstevel@tonic-gate 	if (ether_ntohost(host, (struct ether_addr *)laddr) != 0 ||
9317c478bd9Sstevel@tonic-gate 	    !(hp = gethostbyname_r(host, &res, hbuffer, sizeof (hbuffer),
9327c478bd9Sstevel@tonic-gate 	    &herror)) ||
9337c478bd9Sstevel@tonic-gate 	    hp->h_addrtype != AF_INET || hp->h_length != sizeof (ipaddr_t)) {
9347c478bd9Sstevel@tonic-gate 		if (dflag)
9357c478bd9Sstevel@tonic-gate 			debug("could not map hardware address to IP address");
9367c478bd9Sstevel@tonic-gate 		return (1);
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	/*
9407c478bd9Sstevel@tonic-gate 	 * Find the IP address on the right net.
9417c478bd9Sstevel@tonic-gate 	 */
9427c478bd9Sstevel@tonic-gate 	for (p = hp->h_addr_list; *p; p++) {
9437c478bd9Sstevel@tonic-gate 		(void) memcpy(&addr, *p, sizeof (ipaddr_t));
9447c478bd9Sstevel@tonic-gate 		for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
9457c478bd9Sstevel@tonic-gate 			if (dflag) {
9467c478bd9Sstevel@tonic-gate 				struct in_addr daddr;
9477c478bd9Sstevel@tonic-gate 				ipaddr_t netnum;
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 				netnum = htonl(ifdev->if_netnum);
9507c478bd9Sstevel@tonic-gate 				(void) memcpy(&daddr, &netnum,
9517c478bd9Sstevel@tonic-gate 				    sizeof (ipaddr_t));
9527c478bd9Sstevel@tonic-gate 				if (ifdev->lunit == -1)
953*948f2876Sss150715 					debug("trying physical netnum %s"
954*948f2876Sss150715 					    " mask %x", inet_ntoa(daddr),
9557c478bd9Sstevel@tonic-gate 					    ifdev->if_netmask);
9567c478bd9Sstevel@tonic-gate 				else
957*948f2876Sss150715 					debug("trying logical %d netnum %s"
958*948f2876Sss150715 					    " mask %x", ifdev->lunit,
9597c478bd9Sstevel@tonic-gate 					    inet_ntoa(daddr),
9607c478bd9Sstevel@tonic-gate 					    ifdev->if_netmask);
9617c478bd9Sstevel@tonic-gate 			}
9627c478bd9Sstevel@tonic-gate 			if ((ntohl(addr.s_addr) & ifdev->if_netmask) ==
9637c478bd9Sstevel@tonic-gate 			    ifdev->if_netnum) {
9647c478bd9Sstevel@tonic-gate 				/*
9657c478bd9Sstevel@tonic-gate 				 * Return the correct IP address.
9667c478bd9Sstevel@tonic-gate 				 */
9677c478bd9Sstevel@tonic-gate 				(void) memcpy(ipp, &addr, sizeof (ipaddr_t));
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 				/*
9707c478bd9Sstevel@tonic-gate 				 * Return the interface's ipaddr
9717c478bd9Sstevel@tonic-gate 				 */
9727c478bd9Sstevel@tonic-gate 				(void) memcpy(ipaddr, &ifdev->ipaddr,
9737c478bd9Sstevel@tonic-gate 				    sizeof (ipaddr_t));
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 				return (0);
9767c478bd9Sstevel@tonic-gate 			}
9777c478bd9Sstevel@tonic-gate 		}
9787c478bd9Sstevel@tonic-gate 	}
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	if (dflag)
9817c478bd9Sstevel@tonic-gate 		debug("got host entry but no IP address on this net");
9827c478bd9Sstevel@tonic-gate 	return (1);
9837c478bd9Sstevel@tonic-gate }
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate static int
9867c478bd9Sstevel@tonic-gate strioctl(int fd, int cmd, int timout, int len, char *dp)
9877c478bd9Sstevel@tonic-gate {
9887c478bd9Sstevel@tonic-gate 	struct	strioctl	si;
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 	si.ic_cmd = cmd;
9917c478bd9Sstevel@tonic-gate 	si.ic_timout = timout;
9927c478bd9Sstevel@tonic-gate 	si.ic_len = len;
9937c478bd9Sstevel@tonic-gate 	si.ic_dp = dp;
9947c478bd9Sstevel@tonic-gate 	return (ioctl(fd, I_STR, &si));
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate static void
998*948f2876Sss150715 usage(void)
9997c478bd9Sstevel@tonic-gate {
10007c478bd9Sstevel@tonic-gate 	error("Usage:  %s [ -ad ] device unit", cmdname);
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate static void
1004*948f2876Sss150715 syserr(const char *s)
10057c478bd9Sstevel@tonic-gate {
10067c478bd9Sstevel@tonic-gate 	char buf[256];
10077c478bd9Sstevel@tonic-gate 	int status = 1;
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s: %s", s, strerror(errno));
10107c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:  %s\n", cmdname, buf);
10117c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, "%s", buf);
10127c478bd9Sstevel@tonic-gate 	thr_exit(&status);
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate static void
1016*948f2876Sss150715 error(const char *fmt, ...)
10177c478bd9Sstevel@tonic-gate {
10187c478bd9Sstevel@tonic-gate 	char buf[256];
10197c478bd9Sstevel@tonic-gate 	va_list ap;
10207c478bd9Sstevel@tonic-gate 	int status = 1;
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
10237c478bd9Sstevel@tonic-gate 	(void) vsprintf(buf, fmt, ap);
10247c478bd9Sstevel@tonic-gate 	va_end(ap);
10257c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:  %s\n", cmdname, buf);
10267c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, buf);
10277c478bd9Sstevel@tonic-gate 	thr_exit(&status);
10287c478bd9Sstevel@tonic-gate }
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
10317c478bd9Sstevel@tonic-gate static void
10327c478bd9Sstevel@tonic-gate debug(char *fmt, ...)
10337c478bd9Sstevel@tonic-gate {
10347c478bd9Sstevel@tonic-gate 	va_list ap;
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&debug_mutex);
10377c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
10387c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:[%u]  ", cmdname, thr_self());
10397c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
10407c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
10417c478bd9Sstevel@tonic-gate 	va_end(ap);
10427c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&debug_mutex);
10437c478bd9Sstevel@tonic-gate }
1044