xref: /titanic_50/usr/src/cmd/cmd-inet/usr.sbin/in.rarpd.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
27*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
31*7c478bd9Sstevel@tonic-gate  * under license from the Regents of the University of California.
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate /*
37*7c478bd9Sstevel@tonic-gate  * rarpd.c  Reverse-ARP server.
38*7c478bd9Sstevel@tonic-gate  * Refer to RFC 903 "A Reverse Address Resolution Protocol".
39*7c478bd9Sstevel@tonic-gate  */
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #define	_REENTRANT
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include	<thread.h>
44*7c478bd9Sstevel@tonic-gate #include	<synch.h>
45*7c478bd9Sstevel@tonic-gate #include	<stdlib.h>
46*7c478bd9Sstevel@tonic-gate #include	<unistd.h>
47*7c478bd9Sstevel@tonic-gate #include	<sys/resource.h>
48*7c478bd9Sstevel@tonic-gate #include	<stdio.h>
49*7c478bd9Sstevel@tonic-gate #include	<stdarg.h>
50*7c478bd9Sstevel@tonic-gate #include	<string.h>
51*7c478bd9Sstevel@tonic-gate #include	<ctype.h>
52*7c478bd9Sstevel@tonic-gate #include	<fcntl.h>
53*7c478bd9Sstevel@tonic-gate #include	<sys/types.h>
54*7c478bd9Sstevel@tonic-gate #include	<dirent.h>
55*7c478bd9Sstevel@tonic-gate #include	<syslog.h>
56*7c478bd9Sstevel@tonic-gate #include	<signal.h>
57*7c478bd9Sstevel@tonic-gate #include	<netdb.h>
58*7c478bd9Sstevel@tonic-gate #include	<errno.h>
59*7c478bd9Sstevel@tonic-gate #include	<sys/socket.h>
60*7c478bd9Sstevel@tonic-gate #include	<sys/sockio.h>
61*7c478bd9Sstevel@tonic-gate #include	<net/if.h>
62*7c478bd9Sstevel@tonic-gate #include	<netinet/if_ether.h>
63*7c478bd9Sstevel@tonic-gate #include	<netinet/in.h>
64*7c478bd9Sstevel@tonic-gate #include	<arpa/inet.h>
65*7c478bd9Sstevel@tonic-gate #include	<stropts.h>
66*7c478bd9Sstevel@tonic-gate #include	<sys/dlpi.h>
67*7c478bd9Sstevel@tonic-gate #include	<libinetutil.h>
68*7c478bd9Sstevel@tonic-gate #include	<net/if_types.h>
69*7c478bd9Sstevel@tonic-gate #include	<net/if_dl.h>
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate #define	BOOTDIR		"/tftpboot"	/* boot files directory */
72*7c478bd9Sstevel@tonic-gate #define	DEVDIR		"/dev"		/* devices directory */
73*7c478bd9Sstevel@tonic-gate #define	DEVIP		"/dev/ip"	/* path to ip driver */
74*7c478bd9Sstevel@tonic-gate #define	DEVARP		"/dev/arp"	/* path to arp driver */
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate #define	BUFSIZE		2048		/* max receive frame length */
77*7c478bd9Sstevel@tonic-gate #define	MAXPATHL	128		/* max path length */
78*7c478bd9Sstevel@tonic-gate #define	MAXHOSTL	128		/* max host name length */
79*7c478bd9Sstevel@tonic-gate #define	MAXIFS		256
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * Logical network devices
83*7c478bd9Sstevel@tonic-gate  */
84*7c478bd9Sstevel@tonic-gate struct	ifdev {
85*7c478bd9Sstevel@tonic-gate 	char		ldevice[IFNAMSIZ];
86*7c478bd9Sstevel@tonic-gate 	int		lunit;
87*7c478bd9Sstevel@tonic-gate 	ipaddr_t	ipaddr;			/* network order */
88*7c478bd9Sstevel@tonic-gate 	ipaddr_t	if_netmask;		/* host order */
89*7c478bd9Sstevel@tonic-gate 	ipaddr_t	if_ipaddr;		/* host order */
90*7c478bd9Sstevel@tonic-gate 	ipaddr_t	if_netnum;		/* host order, with subnet */
91*7c478bd9Sstevel@tonic-gate 	struct ifdev *next;
92*7c478bd9Sstevel@tonic-gate };
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate /*
95*7c478bd9Sstevel@tonic-gate  * Physical network device
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate struct	rarpdev {
98*7c478bd9Sstevel@tonic-gate 	char		device[IFNAMSIZ];
99*7c478bd9Sstevel@tonic-gate 	int		unit;
100*7c478bd9Sstevel@tonic-gate 	int		fd;
101*7c478bd9Sstevel@tonic-gate 	uchar_t		*lladdr;		/* mac address of interface */
102*7c478bd9Sstevel@tonic-gate 	int		ifaddrlen;		/* mac address length */
103*7c478bd9Sstevel@tonic-gate 	int		ifsaplen;		/* indicates dlsap format */
104*7c478bd9Sstevel@tonic-gate 	int		ifrarplen;		/* size of rarp data packet */
105*7c478bd9Sstevel@tonic-gate 	struct ifdev	*ifdev;			/* private interface info */
106*7c478bd9Sstevel@tonic-gate 	struct rarpdev	*next;			/* list of managed devices */
107*7c478bd9Sstevel@tonic-gate };
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate struct	rarpreply {
110*7c478bd9Sstevel@tonic-gate 	struct rarpdev		*rdev;		/* which device reply for */
111*7c478bd9Sstevel@tonic-gate 	struct timeval		tv;		/* send RARP reply by when */
112*7c478bd9Sstevel@tonic-gate 	uchar_t			*lldest;	/* target mac to send reply */
113*7c478bd9Sstevel@tonic-gate 	uchar_t			*arprep;	/* [R]ARP response */
114*7c478bd9Sstevel@tonic-gate 	struct rarpreply	*next;
115*7c478bd9Sstevel@tonic-gate };
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate static struct rarpreply	*delay_list;
118*7c478bd9Sstevel@tonic-gate static sema_t		delay_sema;
119*7c478bd9Sstevel@tonic-gate static mutex_t		delay_mutex;
120*7c478bd9Sstevel@tonic-gate static mutex_t		debug_mutex;
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate static struct rarpdev	*rarpdev_head;
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate /*
125*7c478bd9Sstevel@tonic-gate  * Globals initialized before multi-threading
126*7c478bd9Sstevel@tonic-gate  */
127*7c478bd9Sstevel@tonic-gate static char	*cmdname;		/* command name from argv[0] */
128*7c478bd9Sstevel@tonic-gate static int	dflag = 0;		/* enable diagnostics */
129*7c478bd9Sstevel@tonic-gate static int	aflag = 0;		/* start rarpd on all interfaces */
130*7c478bd9Sstevel@tonic-gate static char	*alarmmsg;		/* alarm() error message */
131*7c478bd9Sstevel@tonic-gate static long	pc_name_max;		/* pathconf maximum path name */
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate static void	getintf(void);
134*7c478bd9Sstevel@tonic-gate static struct rarpdev *find_device(ifspec_t *);
135*7c478bd9Sstevel@tonic-gate static void	init_rarpdev(struct rarpdev *);
136*7c478bd9Sstevel@tonic-gate static void	do_rarp(void *);
137*7c478bd9Sstevel@tonic-gate static void	rarp_request(struct rarpdev *, struct arphdr *,
138*7c478bd9Sstevel@tonic-gate 		    uchar_t *);
139*7c478bd9Sstevel@tonic-gate static void	add_arp(struct rarpdev *, uchar_t *, uchar_t *);
140*7c478bd9Sstevel@tonic-gate static void	arp_request(struct rarpdev *, struct arphdr *, uchar_t *);
141*7c478bd9Sstevel@tonic-gate static int	rarp_open(struct rarpdev *, ushort_t);
142*7c478bd9Sstevel@tonic-gate static void	do_delay_write(void *);
143*7c478bd9Sstevel@tonic-gate static void	delay_write(struct rarpdev *, struct rarpreply *);
144*7c478bd9Sstevel@tonic-gate static int	rarp_write(int, struct rarpreply *);
145*7c478bd9Sstevel@tonic-gate static int	mightboot(ipaddr_t);
146*7c478bd9Sstevel@tonic-gate static void	get_ifdata(char *, int, ipaddr_t *, ipaddr_t *);
147*7c478bd9Sstevel@tonic-gate static int	get_ipaddr(struct rarpdev *, uchar_t *, uchar_t *, ipaddr_t *);
148*7c478bd9Sstevel@tonic-gate static void	sigalarm(int);
149*7c478bd9Sstevel@tonic-gate static int	strioctl(int, int, int, int, char *);
150*7c478bd9Sstevel@tonic-gate static void	usage();
151*7c478bd9Sstevel@tonic-gate static void	syserr(char *);
152*7c478bd9Sstevel@tonic-gate static void	error(char *, ...);
153*7c478bd9Sstevel@tonic-gate static void	debug(char *, ...);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate extern	int	optind;
156*7c478bd9Sstevel@tonic-gate extern	char	*optarg;
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate int
159*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
160*7c478bd9Sstevel@tonic-gate {
161*7c478bd9Sstevel@tonic-gate 	int		c;
162*7c478bd9Sstevel@tonic-gate 	struct rlimit rl;
163*7c478bd9Sstevel@tonic-gate 	struct rarpdev	*rdev;
164*7c478bd9Sstevel@tonic-gate 	int		i;
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	cmdname = argv[0];
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "ad")) != -1) {
169*7c478bd9Sstevel@tonic-gate 		switch (c) {
170*7c478bd9Sstevel@tonic-gate 		case 'a':
171*7c478bd9Sstevel@tonic-gate 			aflag = 1;
172*7c478bd9Sstevel@tonic-gate 			break;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 		case 'd':
175*7c478bd9Sstevel@tonic-gate 			dflag = 1;
176*7c478bd9Sstevel@tonic-gate 			break;
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 		default:
179*7c478bd9Sstevel@tonic-gate 			usage();
180*7c478bd9Sstevel@tonic-gate 		}
181*7c478bd9Sstevel@tonic-gate 	}
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	if ((!aflag && (argc - optind) != 2) ||
184*7c478bd9Sstevel@tonic-gate 					(aflag && (argc - optind) != 0)) {
185*7c478bd9Sstevel@tonic-gate 		usage();
186*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
187*7c478bd9Sstevel@tonic-gate 	}
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	if (!dflag) {
190*7c478bd9Sstevel@tonic-gate 		/*
191*7c478bd9Sstevel@tonic-gate 		 * Background
192*7c478bd9Sstevel@tonic-gate 		 */
193*7c478bd9Sstevel@tonic-gate 		switch (fork()) {
194*7c478bd9Sstevel@tonic-gate 			case -1:	/* error */
195*7c478bd9Sstevel@tonic-gate 				syserr("fork");
196*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 			case 0:		/* child */
199*7c478bd9Sstevel@tonic-gate 				break;
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 			default:	/* parent */
202*7c478bd9Sstevel@tonic-gate 				return (0);
203*7c478bd9Sstevel@tonic-gate 		}
204*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 3; i++) {
205*7c478bd9Sstevel@tonic-gate 			(void) close(i);
206*7c478bd9Sstevel@tonic-gate 		}
207*7c478bd9Sstevel@tonic-gate 		(void) open("/", O_RDONLY, 0);
208*7c478bd9Sstevel@tonic-gate 		(void) dup2(0, 1);
209*7c478bd9Sstevel@tonic-gate 		(void) dup2(0, 2);
210*7c478bd9Sstevel@tonic-gate 		/*
211*7c478bd9Sstevel@tonic-gate 		 * Detach terminal
212*7c478bd9Sstevel@tonic-gate 		 */
213*7c478bd9Sstevel@tonic-gate 		if (setsid() < 0)
214*7c478bd9Sstevel@tonic-gate 			syserr("setsid");
215*7c478bd9Sstevel@tonic-gate 	}
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	rl.rlim_cur = RLIM_INFINITY;
218*7c478bd9Sstevel@tonic-gate 	rl.rlim_max = RLIM_INFINITY;
219*7c478bd9Sstevel@tonic-gate 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
220*7c478bd9Sstevel@tonic-gate 		syserr("setrlimit");
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	/*
223*7c478bd9Sstevel@tonic-gate 	 * Look up the maximum name length of the BOOTDIR, it may not
224*7c478bd9Sstevel@tonic-gate 	 * exist so use /, if that fails use a reasonable sized buffer.
225*7c478bd9Sstevel@tonic-gate 	 */
226*7c478bd9Sstevel@tonic-gate 	if ((pc_name_max = pathconf(BOOTDIR, _PC_NAME_MAX)) == -1) {
227*7c478bd9Sstevel@tonic-gate 		if ((pc_name_max = pathconf("/", _PC_NAME_MAX)) == -1) {
228*7c478bd9Sstevel@tonic-gate 			pc_name_max = 255;
229*7c478bd9Sstevel@tonic-gate 		}
230*7c478bd9Sstevel@tonic-gate 	}
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	(void) openlog(cmdname, LOG_PID, LOG_DAEMON);
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	if (aflag) {
235*7c478bd9Sstevel@tonic-gate 		/*
236*7c478bd9Sstevel@tonic-gate 		 * Get each interface name and load rarpdev list
237*7c478bd9Sstevel@tonic-gate 		 */
238*7c478bd9Sstevel@tonic-gate 		getintf();
239*7c478bd9Sstevel@tonic-gate 	} else {
240*7c478bd9Sstevel@tonic-gate 		ifspec_t	ifsp;
241*7c478bd9Sstevel@tonic-gate 		struct ifdev	*ifdev;
242*7c478bd9Sstevel@tonic-gate 		char		buf[IFNAMSIZ + 1];
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 		/*
245*7c478bd9Sstevel@tonic-gate 		 * Load specified device as only element of the list
246*7c478bd9Sstevel@tonic-gate 		 */
247*7c478bd9Sstevel@tonic-gate 		rarpdev_head = (struct rarpdev *)calloc(1,
248*7c478bd9Sstevel@tonic-gate 						sizeof (struct rarpdev));
249*7c478bd9Sstevel@tonic-gate 		if (rarpdev_head == NULL) {
250*7c478bd9Sstevel@tonic-gate 			error("out of memory");
251*7c478bd9Sstevel@tonic-gate 		}
252*7c478bd9Sstevel@tonic-gate 		(void) strncpy(buf, argv[optind], IFNAMSIZ);
253*7c478bd9Sstevel@tonic-gate 		(void) strncat(buf, argv[optind + 1], IFNAMSIZ - strlen(buf));
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 		if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL) {
256*7c478bd9Sstevel@tonic-gate 			error("out of memory");
257*7c478bd9Sstevel@tonic-gate 		}
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 		if (!ifparse_ifspec(buf, &ifsp) || ifsp.ifsp_modcnt != 0) {
260*7c478bd9Sstevel@tonic-gate 			error("invalid interface specification");
261*7c478bd9Sstevel@tonic-gate 		}
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 		if (ifsp.ifsp_lunvalid) {
264*7c478bd9Sstevel@tonic-gate 			(void) snprintf(ifdev->ldevice,
265*7c478bd9Sstevel@tonic-gate 			    sizeof (ifdev->ldevice), "%s%d:",
266*7c478bd9Sstevel@tonic-gate 			    ifsp.ifsp_devnm, ifsp.ifsp_ppa);
267*7c478bd9Sstevel@tonic-gate 			ifdev->lunit = ifsp.ifsp_lun;
268*7c478bd9Sstevel@tonic-gate 		} else
269*7c478bd9Sstevel@tonic-gate 			ifdev->lunit = -1; /* no logical unit */
270*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(rarpdev_head->device, ifsp.ifsp_devnm,
271*7c478bd9Sstevel@tonic-gate 		    sizeof (rarpdev_head->device));
272*7c478bd9Sstevel@tonic-gate 		rarpdev_head->unit = ifsp.ifsp_ppa;
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 		ifdev->next = rarpdev_head->ifdev;
275*7c478bd9Sstevel@tonic-gate 		rarpdev_head->ifdev = ifdev;
276*7c478bd9Sstevel@tonic-gate 	}
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	/*
279*7c478bd9Sstevel@tonic-gate 	 * Initialize each rarpdev
280*7c478bd9Sstevel@tonic-gate 	 */
281*7c478bd9Sstevel@tonic-gate 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
282*7c478bd9Sstevel@tonic-gate 		init_rarpdev(rdev);
283*7c478bd9Sstevel@tonic-gate 	}
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	(void) sema_init(&delay_sema, 0, USYNC_THREAD, NULL);
286*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&delay_mutex, USYNC_THREAD, NULL);
287*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&debug_mutex, USYNC_THREAD, NULL);
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	/*
290*7c478bd9Sstevel@tonic-gate 	 * Start delayed processing thread
291*7c478bd9Sstevel@tonic-gate 	 */
292*7c478bd9Sstevel@tonic-gate 	(void) thr_create(NULL, NULL, (void *(*)(void *))do_delay_write, NULL,
293*7c478bd9Sstevel@tonic-gate 	    THR_NEW_LWP, NULL);
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	/*
296*7c478bd9Sstevel@tonic-gate 	 * Start RARP processing for each device
297*7c478bd9Sstevel@tonic-gate 	 */
298*7c478bd9Sstevel@tonic-gate 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
299*7c478bd9Sstevel@tonic-gate 		if (rdev->fd != -1) {
300*7c478bd9Sstevel@tonic-gate 			(void) thr_create(NULL, NULL,
301*7c478bd9Sstevel@tonic-gate 			    (void *(*)(void *))do_rarp, (void *)rdev,
302*7c478bd9Sstevel@tonic-gate 			    THR_NEW_LWP, NULL);
303*7c478bd9Sstevel@tonic-gate 		}
304*7c478bd9Sstevel@tonic-gate 	}
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	/*
307*7c478bd9Sstevel@tonic-gate 	 * Exit main() thread
308*7c478bd9Sstevel@tonic-gate 	 */
309*7c478bd9Sstevel@tonic-gate 	thr_exit(NULL);
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	return (0);
312*7c478bd9Sstevel@tonic-gate }
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate static void
315*7c478bd9Sstevel@tonic-gate getintf(void)
316*7c478bd9Sstevel@tonic-gate {
317*7c478bd9Sstevel@tonic-gate 	int		fd;
318*7c478bd9Sstevel@tonic-gate 	int		numifs;
319*7c478bd9Sstevel@tonic-gate 	unsigned	bufsize;
320*7c478bd9Sstevel@tonic-gate 	struct ifreq	*reqbuf;
321*7c478bd9Sstevel@tonic-gate 	struct ifconf	ifconf;
322*7c478bd9Sstevel@tonic-gate 	struct ifreq	*ifr;
323*7c478bd9Sstevel@tonic-gate 	struct rarpdev	*rdev;
324*7c478bd9Sstevel@tonic-gate 	struct ifdev	*ifdev;
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	/*
327*7c478bd9Sstevel@tonic-gate 	 * Open the IP provider.
328*7c478bd9Sstevel@tonic-gate 	 */
329*7c478bd9Sstevel@tonic-gate 	if ((fd = open(DEVIP, 0)) < 0)
330*7c478bd9Sstevel@tonic-gate 		syserr(DEVIP);
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	/*
333*7c478bd9Sstevel@tonic-gate 	 * Ask IP for the list of configured interfaces.
334*7c478bd9Sstevel@tonic-gate 	 */
335*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) {
336*7c478bd9Sstevel@tonic-gate 		numifs = MAXIFS;
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 	bufsize = numifs * sizeof (struct ifreq);
339*7c478bd9Sstevel@tonic-gate 	reqbuf = (struct ifreq *)malloc(bufsize);
340*7c478bd9Sstevel@tonic-gate 	if (reqbuf == NULL) {
341*7c478bd9Sstevel@tonic-gate 		error("out of memory");
342*7c478bd9Sstevel@tonic-gate 	}
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	ifconf.ifc_len = bufsize;
345*7c478bd9Sstevel@tonic-gate 	ifconf.ifc_buf = (caddr_t)reqbuf;
346*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFCONF, (char *)&ifconf) < 0)
347*7c478bd9Sstevel@tonic-gate 		syserr("SIOCGIFCONF");
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	/*
350*7c478bd9Sstevel@tonic-gate 	 * Initialize a rarpdev for each interface
351*7c478bd9Sstevel@tonic-gate 	 */
352*7c478bd9Sstevel@tonic-gate 	for (ifr = ifconf.ifc_req; ifconf.ifc_len > 0;
353*7c478bd9Sstevel@tonic-gate 	    ifr++, ifconf.ifc_len -= sizeof (struct ifreq)) {
354*7c478bd9Sstevel@tonic-gate 		ifspec_t	ifsp;
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 		if (ioctl(fd, SIOCGIFFLAGS, (char *)ifr) < 0) {
357*7c478bd9Sstevel@tonic-gate 			syserr("ioctl SIOCGIFFLAGS");
358*7c478bd9Sstevel@tonic-gate 			exit(1);
359*7c478bd9Sstevel@tonic-gate 		}
360*7c478bd9Sstevel@tonic-gate 		if ((ifr->ifr_flags & IFF_LOOPBACK) ||
361*7c478bd9Sstevel@tonic-gate 		    !(ifr->ifr_flags & IFF_UP) ||
362*7c478bd9Sstevel@tonic-gate 		    !(ifr->ifr_flags & IFF_BROADCAST) ||
363*7c478bd9Sstevel@tonic-gate 		    (ifr->ifr_flags & IFF_NOARP) ||
364*7c478bd9Sstevel@tonic-gate 		    (ifr->ifr_flags & IFF_POINTOPOINT))
365*7c478bd9Sstevel@tonic-gate 			continue;
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 		if (!ifparse_ifspec(ifr->ifr_name, &ifsp))
368*7c478bd9Sstevel@tonic-gate 			error("ifparse_ifspec failed");
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 		/*
371*7c478bd9Sstevel@tonic-gate 		 * Look for an existing device for logical interfaces
372*7c478bd9Sstevel@tonic-gate 		 */
373*7c478bd9Sstevel@tonic-gate 		if ((rdev = find_device(&ifsp)) == NULL) {
374*7c478bd9Sstevel@tonic-gate 			rdev = calloc(1, sizeof (struct rarpdev));
375*7c478bd9Sstevel@tonic-gate 			if (rdev == NULL)
376*7c478bd9Sstevel@tonic-gate 				error("out of memory");
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(rdev->device, ifsp.ifsp_devnm,
379*7c478bd9Sstevel@tonic-gate 			    sizeof (rdev->device));
380*7c478bd9Sstevel@tonic-gate 			rdev->unit = ifsp.ifsp_ppa;
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 			rdev->next = rarpdev_head;
383*7c478bd9Sstevel@tonic-gate 			rarpdev_head = rdev;
384*7c478bd9Sstevel@tonic-gate 		}
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 		if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL)
387*7c478bd9Sstevel@tonic-gate 			error("out of memory");
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 		if (ifsp.ifsp_lunvalid) {
390*7c478bd9Sstevel@tonic-gate 			(void) snprintf(ifdev->ldevice,
391*7c478bd9Sstevel@tonic-gate 			    sizeof (ifdev->ldevice), "%s%d:",
392*7c478bd9Sstevel@tonic-gate 			    ifsp.ifsp_devnm, ifsp.ifsp_ppa);
393*7c478bd9Sstevel@tonic-gate 			ifdev->lunit = ifsp.ifsp_lun;
394*7c478bd9Sstevel@tonic-gate 		} else
395*7c478bd9Sstevel@tonic-gate 			ifdev->lunit = -1; /* no logical unit */
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 		ifdev->next = rdev->ifdev;
398*7c478bd9Sstevel@tonic-gate 		rdev->ifdev = ifdev;
399*7c478bd9Sstevel@tonic-gate 	}
400*7c478bd9Sstevel@tonic-gate 	(void) free((char *)reqbuf);
401*7c478bd9Sstevel@tonic-gate }
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate static struct rarpdev *
404*7c478bd9Sstevel@tonic-gate find_device(ifspec_t *specp)
405*7c478bd9Sstevel@tonic-gate {
406*7c478bd9Sstevel@tonic-gate 	struct rarpdev	*rdev;
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
409*7c478bd9Sstevel@tonic-gate 		if (specp->ifsp_ppa == rdev->unit &&
410*7c478bd9Sstevel@tonic-gate 		    strcmp(specp->ifsp_devnm, rdev->device) == 0)
411*7c478bd9Sstevel@tonic-gate 			return (rdev);
412*7c478bd9Sstevel@tonic-gate 	}
413*7c478bd9Sstevel@tonic-gate 	return (NULL);
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate static void
417*7c478bd9Sstevel@tonic-gate init_rarpdev(struct rarpdev *rdev)
418*7c478bd9Sstevel@tonic-gate {
419*7c478bd9Sstevel@tonic-gate 	char *dev;
420*7c478bd9Sstevel@tonic-gate 	int unit;
421*7c478bd9Sstevel@tonic-gate 	struct ifdev *ifdev;
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	/*
424*7c478bd9Sstevel@tonic-gate 	 * Open datalink provider and get our mac address.
425*7c478bd9Sstevel@tonic-gate 	 */
426*7c478bd9Sstevel@tonic-gate 	rdev->fd = rarp_open(rdev, ETHERTYPE_REVARP);
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	/*
429*7c478bd9Sstevel@tonic-gate 	 * rarp_open may fail on certain types of interfaces
430*7c478bd9Sstevel@tonic-gate 	 */
431*7c478bd9Sstevel@tonic-gate 	if (rdev->fd < 0) {
432*7c478bd9Sstevel@tonic-gate 		rdev->fd = -1;
433*7c478bd9Sstevel@tonic-gate 		return;
434*7c478bd9Sstevel@tonic-gate 	}
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	/*
437*7c478bd9Sstevel@tonic-gate 	 * Get the IP address and netmask from directory service for
438*7c478bd9Sstevel@tonic-gate 	 * each logical interface.
439*7c478bd9Sstevel@tonic-gate 	 */
440*7c478bd9Sstevel@tonic-gate 	for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
441*7c478bd9Sstevel@tonic-gate 		/*
442*7c478bd9Sstevel@tonic-gate 		 * If lunit == -1 then this is the primary interface name
443*7c478bd9Sstevel@tonic-gate 		 */
444*7c478bd9Sstevel@tonic-gate 		if (ifdev->lunit == -1) {
445*7c478bd9Sstevel@tonic-gate 			dev = rdev->device;
446*7c478bd9Sstevel@tonic-gate 			unit = rdev->unit;
447*7c478bd9Sstevel@tonic-gate 		} else {
448*7c478bd9Sstevel@tonic-gate 			dev = ifdev->ldevice;
449*7c478bd9Sstevel@tonic-gate 			unit = ifdev->lunit;
450*7c478bd9Sstevel@tonic-gate 		}
451*7c478bd9Sstevel@tonic-gate 		get_ifdata(dev, unit, &ifdev->if_ipaddr, &ifdev->if_netmask);
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 		/*
454*7c478bd9Sstevel@tonic-gate 		 * Use IP address of the interface.
455*7c478bd9Sstevel@tonic-gate 		 */
456*7c478bd9Sstevel@tonic-gate 		ifdev->if_netnum = ifdev->if_ipaddr & ifdev->if_netmask;
457*7c478bd9Sstevel@tonic-gate 		ifdev->ipaddr = (ipaddr_t)htonl(ifdev->if_ipaddr);
458*7c478bd9Sstevel@tonic-gate 	}
459*7c478bd9Sstevel@tonic-gate }
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate static void
462*7c478bd9Sstevel@tonic-gate do_rarp(void *buf)
463*7c478bd9Sstevel@tonic-gate {
464*7c478bd9Sstevel@tonic-gate 	struct rarpdev *rdev = (struct rarpdev *)buf;
465*7c478bd9Sstevel@tonic-gate 	struct strbuf ctl;
466*7c478bd9Sstevel@tonic-gate 	char	ctlbuf[BUFSIZE];
467*7c478bd9Sstevel@tonic-gate 	struct strbuf data;
468*7c478bd9Sstevel@tonic-gate 	char	databuf[BUFSIZE];
469*7c478bd9Sstevel@tonic-gate 	char	*cause;
470*7c478bd9Sstevel@tonic-gate 	struct arphdr *ans;
471*7c478bd9Sstevel@tonic-gate 	uchar_t	*shost;
472*7c478bd9Sstevel@tonic-gate 	int	flags, ret;
473*7c478bd9Sstevel@tonic-gate 	union	DL_primitives	*dlp;
474*7c478bd9Sstevel@tonic-gate 	uchar_t	*laddrp;
475*7c478bd9Sstevel@tonic-gate 	char	*str = NULL;
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	/*
478*7c478bd9Sstevel@tonic-gate 	 * Sanity check; if we hit this limit, ctlbuf/databuf needs
479*7c478bd9Sstevel@tonic-gate 	 * to be malloc'ed.
480*7c478bd9Sstevel@tonic-gate 	 */
481*7c478bd9Sstevel@tonic-gate 	if ((sizeof (ctlbuf) < (DL_UNITDATA_IND_SIZE + rdev->ifaddrlen)) ||
482*7c478bd9Sstevel@tonic-gate 	    (sizeof (databuf) < rdev->ifrarplen))
483*7c478bd9Sstevel@tonic-gate 		error("unsupported media");
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	if (((shost = (uchar_t *)malloc(rdev->ifaddrlen)) == NULL) ||
486*7c478bd9Sstevel@tonic-gate 	    ((ans = (struct arphdr *)malloc(rdev->ifrarplen)) == NULL))
487*7c478bd9Sstevel@tonic-gate 		syserr("malloc");
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 	if (dflag) {
490*7c478bd9Sstevel@tonic-gate 		str = _link_ntoa(rdev->lladdr, str, rdev->ifaddrlen, IFT_OTHER);
491*7c478bd9Sstevel@tonic-gate 		if (str != NULL) {
492*7c478bd9Sstevel@tonic-gate 			debug("starting rarp service on device %s%d address %s",
493*7c478bd9Sstevel@tonic-gate 			    rdev->device, rdev->unit, str);
494*7c478bd9Sstevel@tonic-gate 			free(str);
495*7c478bd9Sstevel@tonic-gate 		}
496*7c478bd9Sstevel@tonic-gate 	}
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	/*
499*7c478bd9Sstevel@tonic-gate 	 * read RARP packets and respond to them.
500*7c478bd9Sstevel@tonic-gate 	 */
501*7c478bd9Sstevel@tonic-gate 	for (;;) {
502*7c478bd9Sstevel@tonic-gate 		ctl.len = 0;
503*7c478bd9Sstevel@tonic-gate 		ctl.maxlen = BUFSIZE;
504*7c478bd9Sstevel@tonic-gate 		ctl.buf = ctlbuf;
505*7c478bd9Sstevel@tonic-gate 		data.len = 0;
506*7c478bd9Sstevel@tonic-gate 		data.maxlen = BUFSIZE;
507*7c478bd9Sstevel@tonic-gate 		data.buf = databuf;
508*7c478bd9Sstevel@tonic-gate 		flags = 0;
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 		if ((ret = getmsg(rdev->fd, &ctl, &data, &flags)) < 0)
511*7c478bd9Sstevel@tonic-gate 			syserr("getmsg");
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 		/*
514*7c478bd9Sstevel@tonic-gate 		 * Validate DL_UNITDATA_IND.
515*7c478bd9Sstevel@tonic-gate 		 */
516*7c478bd9Sstevel@tonic-gate 		/* LINTED pointer */
517*7c478bd9Sstevel@tonic-gate 		dlp = (union DL_primitives *)ctlbuf;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 		(void) memcpy(ans, databuf, rdev->ifrarplen);
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 		cause = NULL;
522*7c478bd9Sstevel@tonic-gate 		if (ctl.len == 0)
523*7c478bd9Sstevel@tonic-gate 			cause = "missing control part of message";
524*7c478bd9Sstevel@tonic-gate 		else if (ctl.len < 0)
525*7c478bd9Sstevel@tonic-gate 			cause = "short control part of message";
526*7c478bd9Sstevel@tonic-gate 		else if (dlp->dl_primitive != DL_UNITDATA_IND)
527*7c478bd9Sstevel@tonic-gate 			cause = "not unitdata_ind";
528*7c478bd9Sstevel@tonic-gate 		else if (ret & MORECTL)
529*7c478bd9Sstevel@tonic-gate 			cause = "MORECTL flag";
530*7c478bd9Sstevel@tonic-gate 		else if (ret & MOREDATA)
531*7c478bd9Sstevel@tonic-gate 			cause = "MOREDATA flag";
532*7c478bd9Sstevel@tonic-gate 		else if (ctl.len < DL_UNITDATA_IND_SIZE)
533*7c478bd9Sstevel@tonic-gate 			cause = "short unitdata_ind";
534*7c478bd9Sstevel@tonic-gate 		else if (data.len < rdev->ifrarplen)
535*7c478bd9Sstevel@tonic-gate 			cause = "short arp";
536*7c478bd9Sstevel@tonic-gate 		else if (ans->ar_hrd != htons(ARPHRD_ETHER))
537*7c478bd9Sstevel@tonic-gate 			cause = "hrd";
538*7c478bd9Sstevel@tonic-gate 		else if (ans->ar_pro != htons(ETHERTYPE_IP))
539*7c478bd9Sstevel@tonic-gate 			cause = "pro";
540*7c478bd9Sstevel@tonic-gate 		else if (ans->ar_hln != rdev->ifaddrlen)
541*7c478bd9Sstevel@tonic-gate 			cause = "hln";
542*7c478bd9Sstevel@tonic-gate 		else if (ans->ar_pln != sizeof (ipaddr_t))
543*7c478bd9Sstevel@tonic-gate 			cause = "pln";
544*7c478bd9Sstevel@tonic-gate 		if (cause) {
545*7c478bd9Sstevel@tonic-gate 			if (dflag)
546*7c478bd9Sstevel@tonic-gate 				debug("receive check failed: cause: %s",
547*7c478bd9Sstevel@tonic-gate 					cause);
548*7c478bd9Sstevel@tonic-gate 			continue;
549*7c478bd9Sstevel@tonic-gate 		}
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 		/*
552*7c478bd9Sstevel@tonic-gate 		 * Good request.
553*7c478bd9Sstevel@tonic-gate 		 * Pick out the mac source address of this RARP request.
554*7c478bd9Sstevel@tonic-gate 		 */
555*7c478bd9Sstevel@tonic-gate 		laddrp = (uchar_t *)ctlbuf +
556*7c478bd9Sstevel@tonic-gate 		    dlp->unitdata_ind.dl_src_addr_offset;
557*7c478bd9Sstevel@tonic-gate 		(void) memcpy(shost, laddrp, ans->ar_hln);
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 		/*
560*7c478bd9Sstevel@tonic-gate 		 * Handle the request.
561*7c478bd9Sstevel@tonic-gate 		 */
562*7c478bd9Sstevel@tonic-gate 		switch (ntohs(ans->ar_op)) {
563*7c478bd9Sstevel@tonic-gate 		case REVARP_REQUEST:
564*7c478bd9Sstevel@tonic-gate 			rarp_request(rdev, ans, shost);
565*7c478bd9Sstevel@tonic-gate 			break;
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 		case ARPOP_REQUEST:
568*7c478bd9Sstevel@tonic-gate 			arp_request(rdev, ans, shost);
569*7c478bd9Sstevel@tonic-gate 			break;
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 		case REVARP_REPLY:
572*7c478bd9Sstevel@tonic-gate 			if (dflag)
573*7c478bd9Sstevel@tonic-gate 				debug("REVARP_REPLY ignored");
574*7c478bd9Sstevel@tonic-gate 			break;
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 		case ARPOP_REPLY:
577*7c478bd9Sstevel@tonic-gate 			if (dflag)
578*7c478bd9Sstevel@tonic-gate 				debug("ARPOP_REPLY ignored");
579*7c478bd9Sstevel@tonic-gate 			break;
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 		default:
582*7c478bd9Sstevel@tonic-gate 			if (dflag)
583*7c478bd9Sstevel@tonic-gate 				debug("unknown opcode 0x%x", ans->ar_op);
584*7c478bd9Sstevel@tonic-gate 			break;
585*7c478bd9Sstevel@tonic-gate 		}
586*7c478bd9Sstevel@tonic-gate 	}
587*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
588*7c478bd9Sstevel@tonic-gate }
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate /*
591*7c478bd9Sstevel@tonic-gate  * Reverse address determination and allocation code.
592*7c478bd9Sstevel@tonic-gate  */
593*7c478bd9Sstevel@tonic-gate static void
594*7c478bd9Sstevel@tonic-gate rarp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost)
595*7c478bd9Sstevel@tonic-gate {
596*7c478bd9Sstevel@tonic-gate 	ipaddr_t		tpa,  spa;
597*7c478bd9Sstevel@tonic-gate 	struct	rarpreply	*rrp;
598*7c478bd9Sstevel@tonic-gate 	uchar_t			*shap, *thap, *spap, *tpap;
599*7c478bd9Sstevel@tonic-gate 	char			*str = NULL;
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 	shap = (uchar_t *)rp + sizeof (struct arphdr);
602*7c478bd9Sstevel@tonic-gate 	spap = shap + rp->ar_hln;
603*7c478bd9Sstevel@tonic-gate 	thap = spap + rp->ar_pln;
604*7c478bd9Sstevel@tonic-gate 	tpap = thap + rp->ar_hln;
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	if (dflag) {
607*7c478bd9Sstevel@tonic-gate 		str = _link_ntoa(thap, str, rdev->ifaddrlen, IFT_OTHER);
608*7c478bd9Sstevel@tonic-gate 		if (str != NULL) {
609*7c478bd9Sstevel@tonic-gate 			debug("RARP_REQUEST for %s", str);
610*7c478bd9Sstevel@tonic-gate 			free(str);
611*7c478bd9Sstevel@tonic-gate 		}
612*7c478bd9Sstevel@tonic-gate 	}
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	/*
615*7c478bd9Sstevel@tonic-gate 	 * third party lookups are rare and wonderful
616*7c478bd9Sstevel@tonic-gate 	 */
617*7c478bd9Sstevel@tonic-gate 	if ((memcmp(shap, thap, rdev->ifaddrlen) != 0) ||
618*7c478bd9Sstevel@tonic-gate 	    (memcmp(shap, shost, rdev->ifaddrlen) != 0)) {
619*7c478bd9Sstevel@tonic-gate 		if (dflag)
620*7c478bd9Sstevel@tonic-gate 			debug("weird (3rd party lookup)");
621*7c478bd9Sstevel@tonic-gate 	}
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 	/*
624*7c478bd9Sstevel@tonic-gate 	 * fill in given parts of reply packet
625*7c478bd9Sstevel@tonic-gate 	 */
626*7c478bd9Sstevel@tonic-gate 	(void) memcpy(shap, rdev->lladdr, rdev->ifaddrlen);
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 	/*
629*7c478bd9Sstevel@tonic-gate 	 * If a good address is stored in our lookup tables, return it
630*7c478bd9Sstevel@tonic-gate 	 * immediately or after a delay.  Store it our kernel's ARP cache.
631*7c478bd9Sstevel@tonic-gate 	 */
632*7c478bd9Sstevel@tonic-gate 	if (get_ipaddr(rdev, thap, tpap, &spa))
633*7c478bd9Sstevel@tonic-gate 		return;
634*7c478bd9Sstevel@tonic-gate 	(void) memcpy(spap, &spa, sizeof (spa));
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	add_arp(rdev, tpap, thap);
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 	rp->ar_op = htons(REVARP_REPLY);
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	if (dflag) {
641*7c478bd9Sstevel@tonic-gate 		struct in_addr addr;
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 		(void) memcpy(&addr, tpap, sizeof (ipaddr_t));
644*7c478bd9Sstevel@tonic-gate 		debug("good lookup, maps to %s", inet_ntoa(addr));
645*7c478bd9Sstevel@tonic-gate 	}
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	rrp = (struct rarpreply *)calloc(1, sizeof (struct rarpreply) +
648*7c478bd9Sstevel@tonic-gate 	    rdev->ifaddrlen + rdev->ifrarplen);
649*7c478bd9Sstevel@tonic-gate 	if (rrp == NULL)
650*7c478bd9Sstevel@tonic-gate 		error("out of memory");
651*7c478bd9Sstevel@tonic-gate 	rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply);
652*7c478bd9Sstevel@tonic-gate 	rrp->arprep = rrp->lldest + rdev->ifaddrlen;
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 	/*
655*7c478bd9Sstevel@tonic-gate 	 * Create rarpreply structure.
656*7c478bd9Sstevel@tonic-gate 	 */
657*7c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&rrp->tv, NULL);
658*7c478bd9Sstevel@tonic-gate 	rrp->tv.tv_sec += 3;	/* delay */
659*7c478bd9Sstevel@tonic-gate 	rrp->rdev = rdev;
660*7c478bd9Sstevel@tonic-gate 	(void) memcpy(rrp->lldest, shost, rdev->ifaddrlen);
661*7c478bd9Sstevel@tonic-gate 	(void) memcpy(rrp->arprep, rp, rdev->ifrarplen);
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	/*
664*7c478bd9Sstevel@tonic-gate 	 * If this is diskless and we're not its bootserver, let the
665*7c478bd9Sstevel@tonic-gate 	 * bootserver reply first by delaying a while.
666*7c478bd9Sstevel@tonic-gate 	 */
667*7c478bd9Sstevel@tonic-gate 	(void) memcpy(&tpa, tpap, sizeof (ipaddr_t));
668*7c478bd9Sstevel@tonic-gate 	if (mightboot(ntohl(tpa))) {
669*7c478bd9Sstevel@tonic-gate 		if (rarp_write(rdev->fd, rrp) < 0)
670*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "Bad rarp_write:  %m");
671*7c478bd9Sstevel@tonic-gate 		if (dflag)
672*7c478bd9Sstevel@tonic-gate 			debug("immediate reply sent");
673*7c478bd9Sstevel@tonic-gate 		(void) free(rrp);
674*7c478bd9Sstevel@tonic-gate 	} else {
675*7c478bd9Sstevel@tonic-gate 		delay_write(rdev, rrp);
676*7c478bd9Sstevel@tonic-gate 	}
677*7c478bd9Sstevel@tonic-gate }
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate /*
680*7c478bd9Sstevel@tonic-gate  * Download an ARP entry into our kernel.
681*7c478bd9Sstevel@tonic-gate  */
682*7c478bd9Sstevel@tonic-gate static void
683*7c478bd9Sstevel@tonic-gate add_arp(struct rarpdev *rdev, uchar_t *ip, uchar_t *laddr)
684*7c478bd9Sstevel@tonic-gate {
685*7c478bd9Sstevel@tonic-gate 	struct xarpreq ar;
686*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin;
687*7c478bd9Sstevel@tonic-gate 	int	fd;
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 	/*
690*7c478bd9Sstevel@tonic-gate 	 * Common part of query or set
691*7c478bd9Sstevel@tonic-gate 	 */
692*7c478bd9Sstevel@tonic-gate 	(void) memset(&ar, 0, sizeof (ar));
693*7c478bd9Sstevel@tonic-gate 	ar.xarp_pa.ss_family = AF_INET;
694*7c478bd9Sstevel@tonic-gate 	sin = (struct sockaddr_in *)&ar.xarp_pa;
695*7c478bd9Sstevel@tonic-gate 	(void) memcpy(&sin->sin_addr, ip, sizeof (ipaddr_t));
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	/*
698*7c478bd9Sstevel@tonic-gate 	 * Open the IP provider.
699*7c478bd9Sstevel@tonic-gate 	 */
700*7c478bd9Sstevel@tonic-gate 	if ((fd = open(DEVARP, 0)) < 0)
701*7c478bd9Sstevel@tonic-gate 		syserr(DEVARP);
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	/*
704*7c478bd9Sstevel@tonic-gate 	 * Set the entry
705*7c478bd9Sstevel@tonic-gate 	 */
706*7c478bd9Sstevel@tonic-gate 	(void) memcpy(LLADDR(&ar.xarp_ha), laddr, rdev->ifaddrlen);
707*7c478bd9Sstevel@tonic-gate 	ar.xarp_ha.sdl_alen = rdev->ifaddrlen;
708*7c478bd9Sstevel@tonic-gate 	ar.xarp_ha.sdl_family = AF_LINK;
709*7c478bd9Sstevel@tonic-gate 	(void) strioctl(fd, SIOCDXARP, -1, sizeof (struct xarpreq),
710*7c478bd9Sstevel@tonic-gate 	    (char *)&ar);
711*7c478bd9Sstevel@tonic-gate 	if (strioctl(fd, SIOCSXARP, -1, sizeof (struct xarpreq),
712*7c478bd9Sstevel@tonic-gate 	    (char *)&ar) < 0)
713*7c478bd9Sstevel@tonic-gate 		syserr("SIOCSXARP");
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
716*7c478bd9Sstevel@tonic-gate }
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate /*
719*7c478bd9Sstevel@tonic-gate  * The RARP spec says we must be able to process ARP requests,
720*7c478bd9Sstevel@tonic-gate  * even through the packet type is RARP.  Let's hope this feature
721*7c478bd9Sstevel@tonic-gate  * is not heavily used.
722*7c478bd9Sstevel@tonic-gate  */
723*7c478bd9Sstevel@tonic-gate static void
724*7c478bd9Sstevel@tonic-gate arp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost)
725*7c478bd9Sstevel@tonic-gate {
726*7c478bd9Sstevel@tonic-gate 	struct	rarpreply	*rrp;
727*7c478bd9Sstevel@tonic-gate 	struct ifdev		*ifdev;
728*7c478bd9Sstevel@tonic-gate 	uchar_t			*shap, *thap, *spap, *tpap;
729*7c478bd9Sstevel@tonic-gate 	int			ret;
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 	shap = (uchar_t *)rp + sizeof (struct arphdr);
732*7c478bd9Sstevel@tonic-gate 	spap = shap + rp->ar_hln;
733*7c478bd9Sstevel@tonic-gate 	thap = spap + rp->ar_pln;
734*7c478bd9Sstevel@tonic-gate 	tpap = thap + rp->ar_hln;
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	if (dflag)
737*7c478bd9Sstevel@tonic-gate 		debug("ARPOP_REQUEST");
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 	for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
740*7c478bd9Sstevel@tonic-gate 		if (memcmp(&ifdev->ipaddr, tpap, sizeof (ipaddr_t)) == 0)
741*7c478bd9Sstevel@tonic-gate 			break;
742*7c478bd9Sstevel@tonic-gate 	}
743*7c478bd9Sstevel@tonic-gate 	if (ifdev == NULL)
744*7c478bd9Sstevel@tonic-gate 		return;
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 	rp->ar_op = ARPOP_REPLY;
747*7c478bd9Sstevel@tonic-gate 	(void) memcpy(shap, rdev->lladdr, rdev->ifaddrlen);
748*7c478bd9Sstevel@tonic-gate 	(void) memcpy(spap, &ifdev->ipaddr, sizeof (ipaddr_t));
749*7c478bd9Sstevel@tonic-gate 	(void) memcpy(thap, rdev->lladdr, rdev->ifaddrlen);
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 	add_arp(rdev, tpap, thap);
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 	/*
754*7c478bd9Sstevel@tonic-gate 	 * Create rarp reply structure.
755*7c478bd9Sstevel@tonic-gate 	 */
756*7c478bd9Sstevel@tonic-gate 	rrp = (struct rarpreply *)calloc(1, sizeof (struct rarpreply) +
757*7c478bd9Sstevel@tonic-gate 	    rdev->ifaddrlen + rdev->ifrarplen);
758*7c478bd9Sstevel@tonic-gate 	if (rrp == NULL)
759*7c478bd9Sstevel@tonic-gate 		error("out of memory");
760*7c478bd9Sstevel@tonic-gate 	rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply);
761*7c478bd9Sstevel@tonic-gate 	rrp->arprep = rrp->lldest + rdev->ifaddrlen;
762*7c478bd9Sstevel@tonic-gate 	rrp->rdev = rdev;
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 	(void) memcpy(rrp->lldest, shost, rdev->ifaddrlen);
765*7c478bd9Sstevel@tonic-gate 	(void) memcpy(rrp->arprep, rp, rdev->ifrarplen);
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 	ret = rarp_write(rdev->fd, rrp);
768*7c478bd9Sstevel@tonic-gate 	free(rrp);
769*7c478bd9Sstevel@tonic-gate 	if (ret < 0)
770*7c478bd9Sstevel@tonic-gate 		error("rarp_write error");
771*7c478bd9Sstevel@tonic-gate }
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate /*
774*7c478bd9Sstevel@tonic-gate  * OPEN the datalink provider device, ATTACH to the unit,
775*7c478bd9Sstevel@tonic-gate  * and BIND to the revarp type.
776*7c478bd9Sstevel@tonic-gate  * Return the resulting descriptor.
777*7c478bd9Sstevel@tonic-gate  *
778*7c478bd9Sstevel@tonic-gate  * MT-UNSAFE
779*7c478bd9Sstevel@tonic-gate  */
780*7c478bd9Sstevel@tonic-gate static int
781*7c478bd9Sstevel@tonic-gate rarp_open(struct rarpdev *rarpdev, ushort_t type)
782*7c478bd9Sstevel@tonic-gate {
783*7c478bd9Sstevel@tonic-gate 	register int fd;
784*7c478bd9Sstevel@tonic-gate 	char	path[MAXPATHL];
785*7c478bd9Sstevel@tonic-gate 	union DL_primitives *dlp;
786*7c478bd9Sstevel@tonic-gate 	char	buf[BUFSIZE];
787*7c478bd9Sstevel@tonic-gate 	struct	strbuf	ctl;
788*7c478bd9Sstevel@tonic-gate 	int	flags;
789*7c478bd9Sstevel@tonic-gate 	uchar_t	*eap;
790*7c478bd9Sstevel@tonic-gate 	char	*device = rarpdev->device;
791*7c478bd9Sstevel@tonic-gate 	int	unit = rarpdev->unit;
792*7c478bd9Sstevel@tonic-gate 	char	*str = NULL;
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	/*
795*7c478bd9Sstevel@tonic-gate 	 * Prefix the device name with "/dev/" if it doesn't
796*7c478bd9Sstevel@tonic-gate 	 * start with a "/" .
797*7c478bd9Sstevel@tonic-gate 	 */
798*7c478bd9Sstevel@tonic-gate 	if (*device == '/')
799*7c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s", device);
800*7c478bd9Sstevel@tonic-gate 	else
801*7c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s/%s", DEVDIR, device);
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 	/*
804*7c478bd9Sstevel@tonic-gate 	 * Open the datalink provider.
805*7c478bd9Sstevel@tonic-gate 	 */
806*7c478bd9Sstevel@tonic-gate 	if ((fd = open(path, O_RDWR)) < 0)
807*7c478bd9Sstevel@tonic-gate 		syserr(path);
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 	/*
810*7c478bd9Sstevel@tonic-gate 	 * Issue DL_INFO_REQ and check DL_INFO_ACK for sanity.
811*7c478bd9Sstevel@tonic-gate 	 */
812*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer */
813*7c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)buf;
814*7c478bd9Sstevel@tonic-gate 	dlp->info_req.dl_primitive = DL_INFO_REQ;
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	ctl.buf = (char *)dlp;
817*7c478bd9Sstevel@tonic-gate 	ctl.len = DL_INFO_REQ_SIZE;
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	if (putmsg(fd, &ctl, NULL, 0) < 0)
820*7c478bd9Sstevel@tonic-gate 		syserr("putmsg");
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGALRM, sigalarm);
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 	alarmmsg = "DL_INFO_REQ failed: timeout waiting for DL_INFO_ACK";
825*7c478bd9Sstevel@tonic-gate 	(void) alarm(10);
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 	ctl.buf = (char *)dlp;
828*7c478bd9Sstevel@tonic-gate 	ctl.len = 0;
829*7c478bd9Sstevel@tonic-gate 	ctl.maxlen = BUFSIZE;
830*7c478bd9Sstevel@tonic-gate 	flags = 0;
831*7c478bd9Sstevel@tonic-gate 	if (getmsg(fd, &ctl, NULL, &flags) < 0)
832*7c478bd9Sstevel@tonic-gate 		syserr("getmsg");
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	(void) alarm(0);
835*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGALRM, SIG_DFL);
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 	/*
838*7c478bd9Sstevel@tonic-gate 	 * Validate DL_INFO_ACK reply.
839*7c478bd9Sstevel@tonic-gate 	 */
840*7c478bd9Sstevel@tonic-gate 	if (ctl.len < sizeof (ulong_t))
841*7c478bd9Sstevel@tonic-gate 		error("DL_INFO_REQ failed:  short reply to DL_INFO_REQ");
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_primitive != DL_INFO_ACK)
844*7c478bd9Sstevel@tonic-gate 		error("DL_INFO_REQ failed:  dl_primitive 0x%lx received",
845*7c478bd9Sstevel@tonic-gate 			dlp->dl_primitive);
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	if (ctl.len < DL_INFO_ACK_SIZE)
848*7c478bd9Sstevel@tonic-gate 		error("DL_INFO_REQ failed:  short info_ack:  %d bytes",
849*7c478bd9Sstevel@tonic-gate 			ctl.len);
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 	if (dlp->info_ack.dl_version != DL_VERSION_2)
852*7c478bd9Sstevel@tonic-gate 		error("DL_INFO_ACK:  incompatible version:  %lu",
853*7c478bd9Sstevel@tonic-gate 			dlp->info_ack.dl_version);
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	if (dlp->info_ack.dl_sap_length != -2) {
856*7c478bd9Sstevel@tonic-gate 		if (dflag)
857*7c478bd9Sstevel@tonic-gate 			debug(
858*7c478bd9Sstevel@tonic-gate "%s%d DL_INFO_ACK:  incompatible dl_sap_length:  %ld",
859*7c478bd9Sstevel@tonic-gate 				device, unit, dlp->info_ack.dl_sap_length);
860*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
861*7c478bd9Sstevel@tonic-gate 		return (-1);
862*7c478bd9Sstevel@tonic-gate 	}
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	if ((dlp->info_ack.dl_service_mode & DL_CLDLS) == 0) {
865*7c478bd9Sstevel@tonic-gate 		if (dflag)
866*7c478bd9Sstevel@tonic-gate 			debug(
867*7c478bd9Sstevel@tonic-gate "%s%d DL_INFO_ACK:  incompatible dl_service_mode:  0x%lx",
868*7c478bd9Sstevel@tonic-gate 				device, unit, dlp->info_ack.dl_service_mode);
869*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
870*7c478bd9Sstevel@tonic-gate 		return (-1);
871*7c478bd9Sstevel@tonic-gate 	}
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	rarpdev->ifsaplen = dlp->info_ack.dl_sap_length;
874*7c478bd9Sstevel@tonic-gate 	rarpdev->ifaddrlen = dlp->info_ack.dl_addr_length -
875*7c478bd9Sstevel@tonic-gate 	    abs(rarpdev->ifsaplen);
876*7c478bd9Sstevel@tonic-gate 	rarpdev->ifrarplen = sizeof (struct arphdr) +
877*7c478bd9Sstevel@tonic-gate 	    (2 * sizeof (ipaddr_t)) + (2 * rarpdev->ifaddrlen);
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 	/*
880*7c478bd9Sstevel@tonic-gate 	 * Issue DL_ATTACH_REQ.
881*7c478bd9Sstevel@tonic-gate 	 */
882*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer */
883*7c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)buf;
884*7c478bd9Sstevel@tonic-gate 	dlp->attach_req.dl_primitive = DL_ATTACH_REQ;
885*7c478bd9Sstevel@tonic-gate 	dlp->attach_req.dl_ppa = unit;
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	ctl.buf = (char *)dlp;
888*7c478bd9Sstevel@tonic-gate 	ctl.len = DL_ATTACH_REQ_SIZE;
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 	if (putmsg(fd, &ctl, NULL, 0) < 0)
891*7c478bd9Sstevel@tonic-gate 		syserr("putmsg");
892*7c478bd9Sstevel@tonic-gate 
893*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGALRM, sigalarm);
894*7c478bd9Sstevel@tonic-gate 	alarmmsg = "DL_ATTACH_REQ failed: timeout waiting for DL_OK_ACK";
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate 	(void) alarm(10);
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate 	ctl.buf = (char *)dlp;
899*7c478bd9Sstevel@tonic-gate 	ctl.len = 0;
900*7c478bd9Sstevel@tonic-gate 	ctl.maxlen = BUFSIZE;
901*7c478bd9Sstevel@tonic-gate 	flags = 0;
902*7c478bd9Sstevel@tonic-gate 	if (getmsg(fd, &ctl, NULL, &flags) < 0)
903*7c478bd9Sstevel@tonic-gate 		syserr("getmsg");
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	(void) alarm(0);
906*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGALRM, SIG_DFL);
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	/*
909*7c478bd9Sstevel@tonic-gate 	 * Validate DL_OK_ACK reply.
910*7c478bd9Sstevel@tonic-gate 	 */
911*7c478bd9Sstevel@tonic-gate 	if (ctl.len < sizeof (ulong_t))
912*7c478bd9Sstevel@tonic-gate 		error("DL_ATTACH_REQ failed:  short reply to attach request");
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_primitive == DL_ERROR_ACK)
915*7c478bd9Sstevel@tonic-gate 		error("DL_ATTACH_REQ failed:  dl_errno %lu unix_errno %lu",
916*7c478bd9Sstevel@tonic-gate 			dlp->error_ack.dl_errno, dlp->error_ack.dl_unix_errno);
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_primitive != DL_OK_ACK)
919*7c478bd9Sstevel@tonic-gate 		error("DL_ATTACH_REQ failed:  dl_primitive 0x%lx received",
920*7c478bd9Sstevel@tonic-gate 			dlp->dl_primitive);
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	if (ctl.len < DL_OK_ACK_SIZE)
923*7c478bd9Sstevel@tonic-gate 		error("attach failed:  short ok_ack:  %d bytes",
924*7c478bd9Sstevel@tonic-gate 			ctl.len);
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	/*
927*7c478bd9Sstevel@tonic-gate 	 * Issue DL_BIND_REQ.
928*7c478bd9Sstevel@tonic-gate 	 */
929*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer */
930*7c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)buf;
931*7c478bd9Sstevel@tonic-gate 	dlp->bind_req.dl_primitive = DL_BIND_REQ;
932*7c478bd9Sstevel@tonic-gate 	dlp->bind_req.dl_sap = type;
933*7c478bd9Sstevel@tonic-gate 	dlp->bind_req.dl_max_conind = 0;
934*7c478bd9Sstevel@tonic-gate 	dlp->bind_req.dl_service_mode = DL_CLDLS;
935*7c478bd9Sstevel@tonic-gate 	dlp->bind_req.dl_conn_mgmt = 0;
936*7c478bd9Sstevel@tonic-gate 	dlp->bind_req.dl_xidtest_flg = 0;
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	ctl.buf = (char *)dlp;
939*7c478bd9Sstevel@tonic-gate 	ctl.len = DL_BIND_REQ_SIZE;
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 	if (putmsg(fd, &ctl, NULL, 0) < 0)
942*7c478bd9Sstevel@tonic-gate 		syserr("putmsg");
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGALRM, sigalarm);
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 	alarmmsg = "DL_BIND_REQ failed:  timeout waiting for DL_BIND_ACK";
947*7c478bd9Sstevel@tonic-gate 	(void) alarm(10);
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	ctl.buf = (char *)dlp;
950*7c478bd9Sstevel@tonic-gate 	ctl.len = 0;
951*7c478bd9Sstevel@tonic-gate 	ctl.maxlen = BUFSIZE;
952*7c478bd9Sstevel@tonic-gate 	flags = 0;
953*7c478bd9Sstevel@tonic-gate 	if (getmsg(fd, &ctl, NULL, &flags) < 0)
954*7c478bd9Sstevel@tonic-gate 		syserr("getmsg");
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 	(void) alarm(0);
957*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGALRM, SIG_DFL);
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate 	/*
960*7c478bd9Sstevel@tonic-gate 	 * Validate DL_BIND_ACK reply.
961*7c478bd9Sstevel@tonic-gate 	 */
962*7c478bd9Sstevel@tonic-gate 	if (ctl.len < sizeof (ulong_t))
963*7c478bd9Sstevel@tonic-gate 		error("DL_BIND_REQ failed:  short reply");
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_primitive == DL_ERROR_ACK)
966*7c478bd9Sstevel@tonic-gate 		error("DL_BIND_REQ failed:  dl_errno %lu unix_errno %lu",
967*7c478bd9Sstevel@tonic-gate 			dlp->error_ack.dl_errno, dlp->error_ack.dl_unix_errno);
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_primitive != DL_BIND_ACK)
970*7c478bd9Sstevel@tonic-gate 		error("DL_BIND_REQ failed:  dl_primitive 0x%lx received",
971*7c478bd9Sstevel@tonic-gate 			dlp->dl_primitive);
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	if (ctl.len < DL_BIND_ACK_SIZE)
974*7c478bd9Sstevel@tonic-gate 		error(
975*7c478bd9Sstevel@tonic-gate "DL_BIND_REQ failed:  short bind acknowledgement received");
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 	if (dlp->bind_ack.dl_sap != type)
978*7c478bd9Sstevel@tonic-gate 		error(
979*7c478bd9Sstevel@tonic-gate "DL_BIND_REQ failed:  returned dl_sap %lu != requested sap %d",
980*7c478bd9Sstevel@tonic-gate 			dlp->bind_ack.dl_sap, type);
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	/*
983*7c478bd9Sstevel@tonic-gate 	 * Issue DL_PHYS_ADDR_REQ to get our local mac address.
984*7c478bd9Sstevel@tonic-gate 	 */
985*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer */
986*7c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)buf;
987*7c478bd9Sstevel@tonic-gate 	dlp->physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
988*7c478bd9Sstevel@tonic-gate 	dlp->physaddr_req.dl_addr_type = DL_CURR_PHYS_ADDR;
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 	ctl.buf = (char *)dlp;
991*7c478bd9Sstevel@tonic-gate 	ctl.len = DL_PHYS_ADDR_REQ_SIZE;
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate 	if (putmsg(fd, &ctl, NULL, 0) < 0)
994*7c478bd9Sstevel@tonic-gate 		syserr("putmsg");
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGALRM, sigalarm);
997*7c478bd9Sstevel@tonic-gate 
998*7c478bd9Sstevel@tonic-gate 	alarmmsg =
999*7c478bd9Sstevel@tonic-gate 	    "DL_PHYS_ADDR_REQ failed:  timeout waiting for DL_PHYS_ADDR_ACK";
1000*7c478bd9Sstevel@tonic-gate 	(void) alarm(10);
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 	ctl.buf = (char *)dlp;
1003*7c478bd9Sstevel@tonic-gate 	ctl.len = 0;
1004*7c478bd9Sstevel@tonic-gate 	ctl.maxlen = BUFSIZE;
1005*7c478bd9Sstevel@tonic-gate 	flags = 0;
1006*7c478bd9Sstevel@tonic-gate 	if (getmsg(fd, &ctl, NULL, &flags) < 0)
1007*7c478bd9Sstevel@tonic-gate 		syserr("getmsg");
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	(void) alarm(0);
1010*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGALRM, SIG_DFL);
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate 	/*
1013*7c478bd9Sstevel@tonic-gate 	 * Validate DL_PHYS_ADDR_ACK reply.
1014*7c478bd9Sstevel@tonic-gate 	 */
1015*7c478bd9Sstevel@tonic-gate 	if (ctl.len < sizeof (ulong_t))
1016*7c478bd9Sstevel@tonic-gate 		error("DL_PHYS_ADDR_REQ failed:  short reply");
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_primitive == DL_ERROR_ACK)
1019*7c478bd9Sstevel@tonic-gate 		error("DL_PHYS_ADDR_REQ failed:  dl_errno %lu unix_errno %lu",
1020*7c478bd9Sstevel@tonic-gate 			dlp->error_ack.dl_errno, dlp->error_ack.dl_unix_errno);
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_primitive != DL_PHYS_ADDR_ACK)
1023*7c478bd9Sstevel@tonic-gate 		error("DL_PHYS_ADDR_REQ failed:  dl_primitive 0x%lx received",
1024*7c478bd9Sstevel@tonic-gate 			dlp->dl_primitive);
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate 	if (ctl.len < DL_PHYS_ADDR_ACK_SIZE)
1027*7c478bd9Sstevel@tonic-gate 		error("DL_PHYS_ADDR_REQ failed:  short ack received");
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	if (dlp->physaddr_ack.dl_addr_length != rarpdev->ifaddrlen) {
1030*7c478bd9Sstevel@tonic-gate 		if (dflag)
1031*7c478bd9Sstevel@tonic-gate 			debug(
1032*7c478bd9Sstevel@tonic-gate "%s%d DL_PHYS_ADDR_ACK failed:  incompatible dl_addr_length:  %lu",
1033*7c478bd9Sstevel@tonic-gate 			device, unit, dlp->physaddr_ack.dl_addr_length);
1034*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1035*7c478bd9Sstevel@tonic-gate 		return (-1);
1036*7c478bd9Sstevel@tonic-gate 	}
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 	/*
1039*7c478bd9Sstevel@tonic-gate 	 * Save our mac address.
1040*7c478bd9Sstevel@tonic-gate 	 */
1041*7c478bd9Sstevel@tonic-gate 	if ((rarpdev->lladdr = (uchar_t *)malloc(rarpdev->ifaddrlen)) == NULL) {
1042*7c478bd9Sstevel@tonic-gate 		if (dflag)
1043*7c478bd9Sstevel@tonic-gate 			debug(" %s%d malloc failed: %d bytes", device,
1044*7c478bd9Sstevel@tonic-gate 			    unit, rarpdev->ifaddrlen);
1045*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1046*7c478bd9Sstevel@tonic-gate 		return (-1);
1047*7c478bd9Sstevel@tonic-gate 	}
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 	eap = (uchar_t *)dlp + dlp->physaddr_ack.dl_addr_offset;
1050*7c478bd9Sstevel@tonic-gate 	(void) memcpy(rarpdev->lladdr, eap, dlp->physaddr_ack.dl_addr_length);
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate 	if (dflag) {
1053*7c478bd9Sstevel@tonic-gate 		str = _link_ntoa(rarpdev->lladdr, str, rarpdev->ifaddrlen,
1054*7c478bd9Sstevel@tonic-gate 		    IFT_OTHER);
1055*7c478bd9Sstevel@tonic-gate 		if (str != NULL) {
1056*7c478bd9Sstevel@tonic-gate 			debug("device %s%d lladdress %s", device, unit, str);
1057*7c478bd9Sstevel@tonic-gate 			free(str);
1058*7c478bd9Sstevel@tonic-gate 		}
1059*7c478bd9Sstevel@tonic-gate 	}
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	return (fd);
1062*7c478bd9Sstevel@tonic-gate }
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1065*7c478bd9Sstevel@tonic-gate static void
1066*7c478bd9Sstevel@tonic-gate do_delay_write(void *buf)
1067*7c478bd9Sstevel@tonic-gate {
1068*7c478bd9Sstevel@tonic-gate 	struct	timeval		tv;
1069*7c478bd9Sstevel@tonic-gate 	struct	rarpreply	*rrp;
1070*7c478bd9Sstevel@tonic-gate 	int			err;
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate 	for (;;) {
1073*7c478bd9Sstevel@tonic-gate 		if ((err = sema_wait(&delay_sema)) != 0) {
1074*7c478bd9Sstevel@tonic-gate 			if (err == EINTR)
1075*7c478bd9Sstevel@tonic-gate 				continue;
1076*7c478bd9Sstevel@tonic-gate 			error("do_delay_write: sema_wait failed");
1077*7c478bd9Sstevel@tonic-gate 		}
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&delay_mutex);
1080*7c478bd9Sstevel@tonic-gate 		rrp = delay_list;
1081*7c478bd9Sstevel@tonic-gate 		delay_list = delay_list->next;
1082*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&delay_mutex);
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate 		(void) gettimeofday(&tv, NULL);
1085*7c478bd9Sstevel@tonic-gate 		if (tv.tv_sec < rrp->tv.tv_sec)
1086*7c478bd9Sstevel@tonic-gate 			(void) sleep(rrp->tv.tv_sec - tv.tv_sec);
1087*7c478bd9Sstevel@tonic-gate 
1088*7c478bd9Sstevel@tonic-gate 		if (rarp_write(rrp->rdev->fd, rrp) < 0)
1089*7c478bd9Sstevel@tonic-gate 			error("rarp_write error");
1090*7c478bd9Sstevel@tonic-gate 
1091*7c478bd9Sstevel@tonic-gate 		(void) free(rrp);
1092*7c478bd9Sstevel@tonic-gate 	}
1093*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1094*7c478bd9Sstevel@tonic-gate }
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1097*7c478bd9Sstevel@tonic-gate static void
1098*7c478bd9Sstevel@tonic-gate delay_write(struct rarpdev *rdev, struct rarpreply *rrp)
1099*7c478bd9Sstevel@tonic-gate {
1100*7c478bd9Sstevel@tonic-gate 	struct	rarpreply	*trp;
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&delay_mutex);
1103*7c478bd9Sstevel@tonic-gate 	if (delay_list == NULL) {
1104*7c478bd9Sstevel@tonic-gate 		delay_list = rrp;
1105*7c478bd9Sstevel@tonic-gate 	} else {
1106*7c478bd9Sstevel@tonic-gate 		trp = delay_list;
1107*7c478bd9Sstevel@tonic-gate 		while (trp->next != NULL)
1108*7c478bd9Sstevel@tonic-gate 			trp = trp->next;
1109*7c478bd9Sstevel@tonic-gate 		trp->next = rrp;
1110*7c478bd9Sstevel@tonic-gate 	}
1111*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&delay_mutex);
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate 	(void) sema_post(&delay_sema);
1114*7c478bd9Sstevel@tonic-gate }
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate static int
1117*7c478bd9Sstevel@tonic-gate rarp_write(int fd, struct rarpreply *rrp)
1118*7c478bd9Sstevel@tonic-gate {
1119*7c478bd9Sstevel@tonic-gate 	struct	strbuf	ctl, data;
1120*7c478bd9Sstevel@tonic-gate 	union	DL_primitives	*dlp;
1121*7c478bd9Sstevel@tonic-gate 	char	ctlbuf[BUFSIZE];
1122*7c478bd9Sstevel@tonic-gate 	ushort_t etype = ETHERTYPE_REVARP;
1123*7c478bd9Sstevel@tonic-gate 	int	ifaddrlen = rrp->rdev->ifaddrlen;
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate 	/*
1126*7c478bd9Sstevel@tonic-gate 	 * Construct DL_UNITDATA_REQ.
1127*7c478bd9Sstevel@tonic-gate 	 */
1128*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer */
1129*7c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)ctlbuf;
1130*7c478bd9Sstevel@tonic-gate 	ctl.len = DL_UNITDATA_REQ_SIZE + ifaddrlen + abs(rrp->rdev->ifsaplen);
1131*7c478bd9Sstevel@tonic-gate 	ctl.buf = ctlbuf;
1132*7c478bd9Sstevel@tonic-gate 	data.len = rrp->rdev->ifrarplen;
1133*7c478bd9Sstevel@tonic-gate 	data.buf = (char *)rrp->arprep;
1134*7c478bd9Sstevel@tonic-gate 	if (ctl.len > sizeof (ctlbuf))
1135*7c478bd9Sstevel@tonic-gate 		return (-1);
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate 	dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
1138*7c478bd9Sstevel@tonic-gate 	dlp->unitdata_req.dl_dest_addr_length = ifaddrlen +
1139*7c478bd9Sstevel@tonic-gate 	    abs(rrp->rdev->ifsaplen);
1140*7c478bd9Sstevel@tonic-gate 	dlp->unitdata_req.dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE;
1141*7c478bd9Sstevel@tonic-gate 	dlp->unitdata_req.dl_priority.dl_min = 0;
1142*7c478bd9Sstevel@tonic-gate 	dlp->unitdata_req.dl_priority.dl_max = 0;
1143*7c478bd9Sstevel@tonic-gate 	(void) memcpy(ctlbuf + DL_UNITDATA_REQ_SIZE, rrp->lldest, ifaddrlen);
1144*7c478bd9Sstevel@tonic-gate 	(void) memcpy(ctlbuf + DL_UNITDATA_REQ_SIZE + ifaddrlen, &etype,
1145*7c478bd9Sstevel@tonic-gate 	    sizeof (etype));
1146*7c478bd9Sstevel@tonic-gate 
1147*7c478bd9Sstevel@tonic-gate 	/*
1148*7c478bd9Sstevel@tonic-gate 	 * Send DL_UNITDATA_REQ.
1149*7c478bd9Sstevel@tonic-gate 	 */
1150*7c478bd9Sstevel@tonic-gate 	return (putmsg(fd, &ctl, &data, 0));
1151*7c478bd9Sstevel@tonic-gate }
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate /*
1154*7c478bd9Sstevel@tonic-gate  * See if we have a TFTP boot file for this guy. Filenames in TFTP
1155*7c478bd9Sstevel@tonic-gate  * boot requests are of the form <ipaddr> for Sun-3's and of the form
1156*7c478bd9Sstevel@tonic-gate  * <ipaddr>.<arch> for all other architectures.  Since we don't know
1157*7c478bd9Sstevel@tonic-gate  * the client's architecture, either format will do.
1158*7c478bd9Sstevel@tonic-gate  */
1159*7c478bd9Sstevel@tonic-gate static int
1160*7c478bd9Sstevel@tonic-gate mightboot(ipaddr_t ipa)
1161*7c478bd9Sstevel@tonic-gate {
1162*7c478bd9Sstevel@tonic-gate 	char path[MAXPATHL];
1163*7c478bd9Sstevel@tonic-gate 	DIR *dirp;
1164*7c478bd9Sstevel@tonic-gate 	struct dirent *dp;
1165*7c478bd9Sstevel@tonic-gate 	struct dirent *dentry;
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s/%08X", BOOTDIR, ipa);
1168*7c478bd9Sstevel@tonic-gate 
1169*7c478bd9Sstevel@tonic-gate 	/*
1170*7c478bd9Sstevel@tonic-gate 	 * Try a quick access() first.
1171*7c478bd9Sstevel@tonic-gate 	 */
1172*7c478bd9Sstevel@tonic-gate 	if (access(path, 0) == 0)
1173*7c478bd9Sstevel@tonic-gate 		return (1);
1174*7c478bd9Sstevel@tonic-gate 
1175*7c478bd9Sstevel@tonic-gate 	/*
1176*7c478bd9Sstevel@tonic-gate 	 * Not there, do it the slow way by
1177*7c478bd9Sstevel@tonic-gate 	 * reading through the directory.
1178*7c478bd9Sstevel@tonic-gate 	 */
1179*7c478bd9Sstevel@tonic-gate 	(void) sprintf(path, "%08X", ipa);
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate 	if (!(dirp = opendir(BOOTDIR)))
1182*7c478bd9Sstevel@tonic-gate 		return (0);
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	dentry = (struct dirent *)malloc(sizeof (struct dirent) +
1185*7c478bd9Sstevel@tonic-gate 							pc_name_max + 1);
1186*7c478bd9Sstevel@tonic-gate 	if (dentry == NULL) {
1187*7c478bd9Sstevel@tonic-gate 		error("out of memory");
1188*7c478bd9Sstevel@tonic-gate 	}
1189*7c478bd9Sstevel@tonic-gate #ifdef _POSIX_PTHREAD_SEMANTICS
1190*7c478bd9Sstevel@tonic-gate 	while ((readdir_r(dirp, dentry, &dp)) != 0) {
1191*7c478bd9Sstevel@tonic-gate 		if (dp == NULL)
1192*7c478bd9Sstevel@tonic-gate 			break;
1193*7c478bd9Sstevel@tonic-gate #else
1194*7c478bd9Sstevel@tonic-gate 	while ((dp = readdir_r(dirp, dentry)) != NULL) {
1195*7c478bd9Sstevel@tonic-gate #endif
1196*7c478bd9Sstevel@tonic-gate 		if (strncmp(dp->d_name, path, 8) != 0)
1197*7c478bd9Sstevel@tonic-gate 			continue;
1198*7c478bd9Sstevel@tonic-gate 		if ((strlen(dp->d_name) != 8) && (dp->d_name[8] != '.'))
1199*7c478bd9Sstevel@tonic-gate 			continue;
1200*7c478bd9Sstevel@tonic-gate 		break;
1201*7c478bd9Sstevel@tonic-gate 	}
1202*7c478bd9Sstevel@tonic-gate 
1203*7c478bd9Sstevel@tonic-gate 	(void) closedir(dirp);
1204*7c478bd9Sstevel@tonic-gate 	(void) free(dentry);
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate 	return (dp? 1: 0);
1207*7c478bd9Sstevel@tonic-gate }
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate /*
1210*7c478bd9Sstevel@tonic-gate  * Get our IP address and local netmask.
1211*7c478bd9Sstevel@tonic-gate  */
1212*7c478bd9Sstevel@tonic-gate static void
1213*7c478bd9Sstevel@tonic-gate get_ifdata(char *dev, int unit, ipaddr_t *ipp, ipaddr_t *maskp)
1214*7c478bd9Sstevel@tonic-gate {
1215*7c478bd9Sstevel@tonic-gate 	int	fd;
1216*7c478bd9Sstevel@tonic-gate 	struct	ifreq	ifr;
1217*7c478bd9Sstevel@tonic-gate 	struct	sockaddr_in	*sin;
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer */
1220*7c478bd9Sstevel@tonic-gate 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 	/*
1223*7c478bd9Sstevel@tonic-gate 	 * Open the IP provider.
1224*7c478bd9Sstevel@tonic-gate 	 */
1225*7c478bd9Sstevel@tonic-gate 	if ((fd = open(DEVIP, 0)) < 0)
1226*7c478bd9Sstevel@tonic-gate 		syserr(DEVIP);
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	/*
1229*7c478bd9Sstevel@tonic-gate 	 * Ask IP for our IP address.
1230*7c478bd9Sstevel@tonic-gate 	 */
1231*7c478bd9Sstevel@tonic-gate 	(void) snprintf(ifr.ifr_name, sizeof (ifr.ifr_name), "%s%d", dev, unit);
1232*7c478bd9Sstevel@tonic-gate 	if (strioctl(fd, SIOCGIFADDR, -1, sizeof (struct ifreq),
1233*7c478bd9Sstevel@tonic-gate 		(char *)&ifr) < 0)
1234*7c478bd9Sstevel@tonic-gate 		syserr("SIOCGIFADDR");
1235*7c478bd9Sstevel@tonic-gate 	*ipp = (ipaddr_t)ntohl(sin->sin_addr.s_addr);
1236*7c478bd9Sstevel@tonic-gate 
1237*7c478bd9Sstevel@tonic-gate 	if (dflag)
1238*7c478bd9Sstevel@tonic-gate 		debug("device %s%d address %s",
1239*7c478bd9Sstevel@tonic-gate 			dev, unit, inet_ntoa(sin->sin_addr));
1240*7c478bd9Sstevel@tonic-gate 
1241*7c478bd9Sstevel@tonic-gate 	/*
1242*7c478bd9Sstevel@tonic-gate 	 * Ask IP for our netmask.
1243*7c478bd9Sstevel@tonic-gate 	 */
1244*7c478bd9Sstevel@tonic-gate 	if (strioctl(fd, SIOCGIFNETMASK, -1, sizeof (struct ifreq),
1245*7c478bd9Sstevel@tonic-gate 		(char *)&ifr) < 0)
1246*7c478bd9Sstevel@tonic-gate 		syserr("SIOCGIFNETMASK");
1247*7c478bd9Sstevel@tonic-gate 	*maskp = (ipaddr_t)ntohl(sin->sin_addr.s_addr);
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 	if (dflag)
1250*7c478bd9Sstevel@tonic-gate 		debug("device %s%d subnet mask %s",
1251*7c478bd9Sstevel@tonic-gate 			dev, unit, inet_ntoa(sin->sin_addr));
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate 	/*
1254*7c478bd9Sstevel@tonic-gate 	 * Thankyou ip.
1255*7c478bd9Sstevel@tonic-gate 	 */
1256*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1257*7c478bd9Sstevel@tonic-gate }
1258*7c478bd9Sstevel@tonic-gate 
1259*7c478bd9Sstevel@tonic-gate /*
1260*7c478bd9Sstevel@tonic-gate  * Translate mac address to IP address.
1261*7c478bd9Sstevel@tonic-gate  * Return 0 on success, nonzero on failure.
1262*7c478bd9Sstevel@tonic-gate  */
1263*7c478bd9Sstevel@tonic-gate static int
1264*7c478bd9Sstevel@tonic-gate get_ipaddr(struct rarpdev *rdev, uchar_t *laddr, uchar_t *ipp, ipaddr_t *ipaddr)
1265*7c478bd9Sstevel@tonic-gate {
1266*7c478bd9Sstevel@tonic-gate 	char host[MAXHOSTL];
1267*7c478bd9Sstevel@tonic-gate 	char hbuffer[BUFSIZE];
1268*7c478bd9Sstevel@tonic-gate 	struct hostent *hp, res;
1269*7c478bd9Sstevel@tonic-gate 	int herror;
1270*7c478bd9Sstevel@tonic-gate 	struct in_addr addr;
1271*7c478bd9Sstevel@tonic-gate 	char	**p;
1272*7c478bd9Sstevel@tonic-gate 	struct ifdev *ifdev;
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate 	if (rdev->ifaddrlen != ETHERADDRL) {
1275*7c478bd9Sstevel@tonic-gate 		if (dflag)
1276*7c478bd9Sstevel@tonic-gate 			debug("%s %s", " can not map non 6 byte hardware ",
1277*7c478bd9Sstevel@tonic-gate 			    "address to IP address");
1278*7c478bd9Sstevel@tonic-gate 		return (1);
1279*7c478bd9Sstevel@tonic-gate 	}
1280*7c478bd9Sstevel@tonic-gate 
1281*7c478bd9Sstevel@tonic-gate 	/*
1282*7c478bd9Sstevel@tonic-gate 	 * Translate mac address to hostname
1283*7c478bd9Sstevel@tonic-gate 	 * and IP address.
1284*7c478bd9Sstevel@tonic-gate 	 */
1285*7c478bd9Sstevel@tonic-gate 	if (ether_ntohost(host, (struct ether_addr *)laddr) != 0 ||
1286*7c478bd9Sstevel@tonic-gate 	    !(hp = gethostbyname_r(host, &res, hbuffer, sizeof (hbuffer),
1287*7c478bd9Sstevel@tonic-gate 	    &herror)) ||
1288*7c478bd9Sstevel@tonic-gate 	    hp->h_addrtype != AF_INET || hp->h_length != sizeof (ipaddr_t)) {
1289*7c478bd9Sstevel@tonic-gate 		if (dflag)
1290*7c478bd9Sstevel@tonic-gate 			debug("could not map hardware address to IP address");
1291*7c478bd9Sstevel@tonic-gate 		return (1);
1292*7c478bd9Sstevel@tonic-gate 	}
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate 	/*
1295*7c478bd9Sstevel@tonic-gate 	 * Find the IP address on the right net.
1296*7c478bd9Sstevel@tonic-gate 	 */
1297*7c478bd9Sstevel@tonic-gate 	for (p = hp->h_addr_list; *p; p++) {
1298*7c478bd9Sstevel@tonic-gate 		(void) memcpy(&addr, *p, sizeof (ipaddr_t));
1299*7c478bd9Sstevel@tonic-gate 		for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
1300*7c478bd9Sstevel@tonic-gate 			if (dflag) {
1301*7c478bd9Sstevel@tonic-gate 				struct in_addr daddr;
1302*7c478bd9Sstevel@tonic-gate 				ipaddr_t netnum;
1303*7c478bd9Sstevel@tonic-gate 
1304*7c478bd9Sstevel@tonic-gate 				netnum = htonl(ifdev->if_netnum);
1305*7c478bd9Sstevel@tonic-gate 				(void) memcpy(&daddr, &netnum,
1306*7c478bd9Sstevel@tonic-gate 				    sizeof (ipaddr_t));
1307*7c478bd9Sstevel@tonic-gate 				if (ifdev->lunit == -1)
1308*7c478bd9Sstevel@tonic-gate 					debug(
1309*7c478bd9Sstevel@tonic-gate "trying physical netnum %s mask %x",
1310*7c478bd9Sstevel@tonic-gate 					inet_ntoa(daddr),
1311*7c478bd9Sstevel@tonic-gate 					ifdev->if_netmask);
1312*7c478bd9Sstevel@tonic-gate 				else
1313*7c478bd9Sstevel@tonic-gate 					debug(
1314*7c478bd9Sstevel@tonic-gate "trying logical %d netnum %s mask %x",
1315*7c478bd9Sstevel@tonic-gate 					ifdev->lunit,
1316*7c478bd9Sstevel@tonic-gate 					inet_ntoa(daddr),
1317*7c478bd9Sstevel@tonic-gate 					ifdev->if_netmask);
1318*7c478bd9Sstevel@tonic-gate 			}
1319*7c478bd9Sstevel@tonic-gate 			if ((ntohl(addr.s_addr) & ifdev->if_netmask) ==
1320*7c478bd9Sstevel@tonic-gate 							ifdev->if_netnum) {
1321*7c478bd9Sstevel@tonic-gate 				/*
1322*7c478bd9Sstevel@tonic-gate 				 * Return the correct IP address.
1323*7c478bd9Sstevel@tonic-gate 				 */
1324*7c478bd9Sstevel@tonic-gate 				(void) memcpy(ipp, &addr, sizeof (ipaddr_t));
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate 				/*
1327*7c478bd9Sstevel@tonic-gate 				 * Return the interface's ipaddr
1328*7c478bd9Sstevel@tonic-gate 				 */
1329*7c478bd9Sstevel@tonic-gate 				(void) memcpy(ipaddr, &ifdev->ipaddr,
1330*7c478bd9Sstevel@tonic-gate 				    sizeof (ipaddr_t));
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 				return (0);
1333*7c478bd9Sstevel@tonic-gate 			}
1334*7c478bd9Sstevel@tonic-gate 		}
1335*7c478bd9Sstevel@tonic-gate 	}
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate 	if (dflag)
1338*7c478bd9Sstevel@tonic-gate 		debug("got host entry but no IP address on this net");
1339*7c478bd9Sstevel@tonic-gate 	return (1);
1340*7c478bd9Sstevel@tonic-gate }
1341*7c478bd9Sstevel@tonic-gate 
1342*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1343*7c478bd9Sstevel@tonic-gate void
1344*7c478bd9Sstevel@tonic-gate sigalarm(int i)
1345*7c478bd9Sstevel@tonic-gate {
1346*7c478bd9Sstevel@tonic-gate 	error(alarmmsg);
1347*7c478bd9Sstevel@tonic-gate }
1348*7c478bd9Sstevel@tonic-gate 
1349*7c478bd9Sstevel@tonic-gate static int
1350*7c478bd9Sstevel@tonic-gate strioctl(int fd, int cmd, int timout, int len, char *dp)
1351*7c478bd9Sstevel@tonic-gate {
1352*7c478bd9Sstevel@tonic-gate 	struct	strioctl	si;
1353*7c478bd9Sstevel@tonic-gate 
1354*7c478bd9Sstevel@tonic-gate 	si.ic_cmd = cmd;
1355*7c478bd9Sstevel@tonic-gate 	si.ic_timout = timout;
1356*7c478bd9Sstevel@tonic-gate 	si.ic_len = len;
1357*7c478bd9Sstevel@tonic-gate 	si.ic_dp = dp;
1358*7c478bd9Sstevel@tonic-gate 	return (ioctl(fd, I_STR, &si));
1359*7c478bd9Sstevel@tonic-gate }
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate static void
1362*7c478bd9Sstevel@tonic-gate usage()
1363*7c478bd9Sstevel@tonic-gate {
1364*7c478bd9Sstevel@tonic-gate 	error("Usage:  %s [ -ad ] device unit", cmdname);
1365*7c478bd9Sstevel@tonic-gate }
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate static void
1368*7c478bd9Sstevel@tonic-gate syserr(s)
1369*7c478bd9Sstevel@tonic-gate char	*s;
1370*7c478bd9Sstevel@tonic-gate {
1371*7c478bd9Sstevel@tonic-gate 	char buf[256];
1372*7c478bd9Sstevel@tonic-gate 	int status = 1;
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s: %s", s, strerror(errno));
1375*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:  %s\n", cmdname, buf);
1376*7c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, "%s", buf);
1377*7c478bd9Sstevel@tonic-gate 	thr_exit(&status);
1378*7c478bd9Sstevel@tonic-gate }
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
1381*7c478bd9Sstevel@tonic-gate static void
1382*7c478bd9Sstevel@tonic-gate error(char *fmt, ...)
1383*7c478bd9Sstevel@tonic-gate {
1384*7c478bd9Sstevel@tonic-gate 	char buf[256];
1385*7c478bd9Sstevel@tonic-gate 	va_list ap;
1386*7c478bd9Sstevel@tonic-gate 	int status = 1;
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
1389*7c478bd9Sstevel@tonic-gate 	(void) vsprintf(buf, fmt, ap);
1390*7c478bd9Sstevel@tonic-gate 	va_end(ap);
1391*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:  %s\n", cmdname, buf);
1392*7c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, buf);
1393*7c478bd9Sstevel@tonic-gate 	thr_exit(&status);
1394*7c478bd9Sstevel@tonic-gate }
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
1397*7c478bd9Sstevel@tonic-gate static void
1398*7c478bd9Sstevel@tonic-gate debug(char *fmt, ...)
1399*7c478bd9Sstevel@tonic-gate {
1400*7c478bd9Sstevel@tonic-gate 	va_list ap;
1401*7c478bd9Sstevel@tonic-gate 
1402*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&debug_mutex);
1403*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
1404*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:[%u]  ", cmdname, thr_self());
1405*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
1406*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
1407*7c478bd9Sstevel@tonic-gate 	va_end(ap);
1408*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&debug_mutex);
1409*7c478bd9Sstevel@tonic-gate }
1410