xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.rarpd.c (revision 10616:3be00c4a6835)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51914Scasper  * Common Development and Distribution License (the "License").
61914Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*10616SSebastien.Roy@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
260Sstevel@tonic-gate /*	  All Rights Reserved  	*/
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
300Sstevel@tonic-gate  * under license from the Regents of the University of California.
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate /*
340Sstevel@tonic-gate  * rarpd.c  Reverse-ARP server.
350Sstevel@tonic-gate  * Refer to RFC 903 "A Reverse Address Resolution Protocol".
360Sstevel@tonic-gate  */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #define	_REENTRANT
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include	<thread.h>
410Sstevel@tonic-gate #include	<synch.h>
420Sstevel@tonic-gate #include	<stdlib.h>
430Sstevel@tonic-gate #include	<unistd.h>
440Sstevel@tonic-gate #include	<sys/resource.h>
450Sstevel@tonic-gate #include	<stdio.h>
461914Scasper #include	<stdio_ext.h>
470Sstevel@tonic-gate #include	<stdarg.h>
480Sstevel@tonic-gate #include	<string.h>
490Sstevel@tonic-gate #include	<fcntl.h>
500Sstevel@tonic-gate #include	<sys/types.h>
510Sstevel@tonic-gate #include	<dirent.h>
520Sstevel@tonic-gate #include	<syslog.h>
530Sstevel@tonic-gate #include	<netdb.h>
540Sstevel@tonic-gate #include	<errno.h>
550Sstevel@tonic-gate #include	<sys/socket.h>
560Sstevel@tonic-gate #include	<sys/sockio.h>
570Sstevel@tonic-gate #include	<net/if.h>
580Sstevel@tonic-gate #include	<netinet/if_ether.h>
590Sstevel@tonic-gate #include	<netinet/in.h>
600Sstevel@tonic-gate #include	<arpa/inet.h>
610Sstevel@tonic-gate #include	<stropts.h>
620Sstevel@tonic-gate #include	<libinetutil.h>
634456Sss150715 #include	<libdlpi.h>
640Sstevel@tonic-gate #include	<net/if_types.h>
650Sstevel@tonic-gate #include	<net/if_dl.h>
660Sstevel@tonic-gate 
670Sstevel@tonic-gate #define	BOOTDIR		"/tftpboot"	/* boot files directory */
680Sstevel@tonic-gate #define	DEVIP		"/dev/ip"	/* path to ip driver */
690Sstevel@tonic-gate #define	DEVARP		"/dev/arp"	/* path to arp driver */
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #define	BUFSIZE		2048		/* max receive frame length */
720Sstevel@tonic-gate #define	MAXPATHL	128		/* max path length */
730Sstevel@tonic-gate #define	MAXHOSTL	128		/* max host name length */
740Sstevel@tonic-gate #define	MAXIFS		256
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate  * Logical network devices
780Sstevel@tonic-gate  */
790Sstevel@tonic-gate struct	ifdev {
800Sstevel@tonic-gate 	char		ldevice[IFNAMSIZ];
810Sstevel@tonic-gate 	int		lunit;
820Sstevel@tonic-gate 	ipaddr_t	ipaddr;			/* network order */
830Sstevel@tonic-gate 	ipaddr_t	if_netmask;		/* host order */
840Sstevel@tonic-gate 	ipaddr_t	if_ipaddr;		/* host order */
850Sstevel@tonic-gate 	ipaddr_t	if_netnum;		/* host order, with subnet */
860Sstevel@tonic-gate 	struct ifdev *next;
870Sstevel@tonic-gate };
880Sstevel@tonic-gate 
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate  * Physical network device
910Sstevel@tonic-gate  */
920Sstevel@tonic-gate struct	rarpdev {
934456Sss150715 	char		device[DLPI_LINKNAME_MAX];
944456Sss150715 	uint_t		unit;
954456Sss150715 	dlpi_handle_t	dh_rarp;
964456Sss150715 	uchar_t		physaddr[DLPI_PHYSADDR_MAX];
974456Sss150715 						/* mac address of interface */
984456Sss150715 	uint_t		physaddrlen;		/* mac address length */
990Sstevel@tonic-gate 	int		ifrarplen;		/* size of rarp data packet */
1000Sstevel@tonic-gate 	struct ifdev	*ifdev;			/* private interface info */
1010Sstevel@tonic-gate 	struct rarpdev	*next;			/* list of managed devices */
1020Sstevel@tonic-gate };
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate struct	rarpreply {
1050Sstevel@tonic-gate 	struct rarpdev		*rdev;		/* which device reply for */
1060Sstevel@tonic-gate 	struct timeval		tv;		/* send RARP reply by when */
1070Sstevel@tonic-gate 	uchar_t			*lldest;	/* target mac to send reply */
1080Sstevel@tonic-gate 	uchar_t			*arprep;	/* [R]ARP response */
1090Sstevel@tonic-gate 	struct rarpreply	*next;
1100Sstevel@tonic-gate };
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate static struct rarpreply	*delay_list;
1130Sstevel@tonic-gate static sema_t		delay_sema;
1140Sstevel@tonic-gate static mutex_t		delay_mutex;
1150Sstevel@tonic-gate static mutex_t		debug_mutex;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate static struct rarpdev	*rarpdev_head;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate  * Globals initialized before multi-threading
1210Sstevel@tonic-gate  */
1220Sstevel@tonic-gate static char	*cmdname;		/* command name from argv[0] */
1230Sstevel@tonic-gate static int	dflag = 0;		/* enable diagnostics */
1240Sstevel@tonic-gate static int	aflag = 0;		/* start rarpd on all interfaces */
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate static void	getintf(void);
1270Sstevel@tonic-gate static struct rarpdev *find_device(ifspec_t *);
1280Sstevel@tonic-gate static void	init_rarpdev(struct rarpdev *);
1290Sstevel@tonic-gate static void	do_rarp(void *);
1300Sstevel@tonic-gate static void	rarp_request(struct rarpdev *, struct arphdr *,
1310Sstevel@tonic-gate 		    uchar_t *);
1320Sstevel@tonic-gate static void	add_arp(struct rarpdev *, uchar_t *, uchar_t *);
1330Sstevel@tonic-gate static void	arp_request(struct rarpdev *, struct arphdr *, uchar_t *);
1340Sstevel@tonic-gate static void	do_delay_write(void *);
1350Sstevel@tonic-gate static void	delay_write(struct rarpdev *, struct rarpreply *);
1360Sstevel@tonic-gate static int	mightboot(ipaddr_t);
1370Sstevel@tonic-gate static void	get_ifdata(char *, int, ipaddr_t *, ipaddr_t *);
1380Sstevel@tonic-gate static int	get_ipaddr(struct rarpdev *, uchar_t *, uchar_t *, ipaddr_t *);
1390Sstevel@tonic-gate static int	strioctl(int, int, int, int, char *);
1400Sstevel@tonic-gate static void	usage();
1414456Sss150715 static void	syserr(const char *);
1424456Sss150715 /*PRINTFLIKE1*/
1434456Sss150715 static void	error(const char *, ...);
1440Sstevel@tonic-gate static void	debug(char *, ...);
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate extern	int	optind;
1470Sstevel@tonic-gate extern	char	*optarg;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate int
main(int argc,char * argv[])1500Sstevel@tonic-gate main(int argc, char *argv[])
1510Sstevel@tonic-gate {
1520Sstevel@tonic-gate 	int		c;
1530Sstevel@tonic-gate 	struct rlimit rl;
1540Sstevel@tonic-gate 	struct rarpdev	*rdev;
1550Sstevel@tonic-gate 	int		i;
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	cmdname = argv[0];
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "ad")) != -1) {
1600Sstevel@tonic-gate 		switch (c) {
1610Sstevel@tonic-gate 		case 'a':
1620Sstevel@tonic-gate 			aflag = 1;
1630Sstevel@tonic-gate 			break;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 		case 'd':
1660Sstevel@tonic-gate 			dflag = 1;
1670Sstevel@tonic-gate 			break;
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 		default:
1700Sstevel@tonic-gate 			usage();
1710Sstevel@tonic-gate 		}
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	if ((!aflag && (argc - optind) != 2) ||
1754456Sss150715 	    (aflag && (argc - optind) != 0)) {
1760Sstevel@tonic-gate 		usage();
1770Sstevel@tonic-gate 		/* NOTREACHED */
1780Sstevel@tonic-gate 	}
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	if (!dflag) {
1810Sstevel@tonic-gate 		/*
1820Sstevel@tonic-gate 		 * Background
1830Sstevel@tonic-gate 		 */
1840Sstevel@tonic-gate 		switch (fork()) {
1850Sstevel@tonic-gate 			case -1:	/* error */
1860Sstevel@tonic-gate 				syserr("fork");
1870Sstevel@tonic-gate 				/*NOTREACHED*/
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 			case 0:		/* child */
1900Sstevel@tonic-gate 				break;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 			default:	/* parent */
1930Sstevel@tonic-gate 				return (0);
1940Sstevel@tonic-gate 		}
1950Sstevel@tonic-gate 		for (i = 0; i < 3; i++) {
1960Sstevel@tonic-gate 			(void) close(i);
1970Sstevel@tonic-gate 		}
1980Sstevel@tonic-gate 		(void) open("/", O_RDONLY, 0);
1990Sstevel@tonic-gate 		(void) dup2(0, 1);
2000Sstevel@tonic-gate 		(void) dup2(0, 2);
2010Sstevel@tonic-gate 		/*
2020Sstevel@tonic-gate 		 * Detach terminal
2030Sstevel@tonic-gate 		 */
2040Sstevel@tonic-gate 		if (setsid() < 0)
2050Sstevel@tonic-gate 			syserr("setsid");
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	rl.rlim_cur = RLIM_INFINITY;
2090Sstevel@tonic-gate 	rl.rlim_max = RLIM_INFINITY;
2100Sstevel@tonic-gate 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
2110Sstevel@tonic-gate 		syserr("setrlimit");
2121914Scasper 	(void) enable_extended_FILE_stdio(-1, -1);
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	(void) openlog(cmdname, LOG_PID, LOG_DAEMON);
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	if (aflag) {
2170Sstevel@tonic-gate 		/*
2184456Sss150715 		 * Get each interface name and load rarpdev list.
2190Sstevel@tonic-gate 		 */
2200Sstevel@tonic-gate 		getintf();
2210Sstevel@tonic-gate 	} else {
2220Sstevel@tonic-gate 		ifspec_t	ifsp;
2230Sstevel@tonic-gate 		struct ifdev	*ifdev;
2240Sstevel@tonic-gate 		char		buf[IFNAMSIZ + 1];
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 		/*
2274456Sss150715 		 * Load specified device as only element of the list.
2280Sstevel@tonic-gate 		 */
2290Sstevel@tonic-gate 		rarpdev_head = (struct rarpdev *)calloc(1,
2304456Sss150715 		    sizeof (struct rarpdev));
2310Sstevel@tonic-gate 		if (rarpdev_head == NULL) {
2320Sstevel@tonic-gate 			error("out of memory");
2330Sstevel@tonic-gate 		}
2340Sstevel@tonic-gate 		(void) strncpy(buf, argv[optind], IFNAMSIZ);
2350Sstevel@tonic-gate 		(void) strncat(buf, argv[optind + 1], IFNAMSIZ - strlen(buf));
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 		if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL) {
2380Sstevel@tonic-gate 			error("out of memory");
2390Sstevel@tonic-gate 		}
2400Sstevel@tonic-gate 
241*10616SSebastien.Roy@Sun.COM 		if (!ifparse_ifspec(buf, &ifsp))
2420Sstevel@tonic-gate 			error("invalid interface specification");
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 		if (ifsp.ifsp_lunvalid) {
2450Sstevel@tonic-gate 			(void) snprintf(ifdev->ldevice,
2460Sstevel@tonic-gate 			    sizeof (ifdev->ldevice), "%s%d:",
2470Sstevel@tonic-gate 			    ifsp.ifsp_devnm, ifsp.ifsp_ppa);
2480Sstevel@tonic-gate 			ifdev->lunit = ifsp.ifsp_lun;
2494456Sss150715 		} else {
2500Sstevel@tonic-gate 			ifdev->lunit = -1; /* no logical unit */
2514456Sss150715 		}
2520Sstevel@tonic-gate 		(void) strlcpy(rarpdev_head->device, ifsp.ifsp_devnm,
2530Sstevel@tonic-gate 		    sizeof (rarpdev_head->device));
2540Sstevel@tonic-gate 		rarpdev_head->unit = ifsp.ifsp_ppa;
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 		ifdev->next = rarpdev_head->ifdev;
2570Sstevel@tonic-gate 		rarpdev_head->ifdev = ifdev;
2580Sstevel@tonic-gate 	}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	/*
2614456Sss150715 	 * Initialize each rarpdev.
2620Sstevel@tonic-gate 	 */
2630Sstevel@tonic-gate 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
2640Sstevel@tonic-gate 		init_rarpdev(rdev);
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	(void) sema_init(&delay_sema, 0, USYNC_THREAD, NULL);
2680Sstevel@tonic-gate 	(void) mutex_init(&delay_mutex, USYNC_THREAD, NULL);
2690Sstevel@tonic-gate 	(void) mutex_init(&debug_mutex, USYNC_THREAD, NULL);
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	/*
2724456Sss150715 	 * Start delayed processing thread.
2730Sstevel@tonic-gate 	 */
2740Sstevel@tonic-gate 	(void) thr_create(NULL, NULL, (void *(*)(void *))do_delay_write, NULL,
2750Sstevel@tonic-gate 	    THR_NEW_LWP, NULL);
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	/*
2784456Sss150715 	 * Start RARP processing for each device.
2790Sstevel@tonic-gate 	 */
2800Sstevel@tonic-gate 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
2814456Sss150715 		if (rdev->dh_rarp != NULL) {
2820Sstevel@tonic-gate 			(void) thr_create(NULL, NULL,
2830Sstevel@tonic-gate 			    (void *(*)(void *))do_rarp, (void *)rdev,
2840Sstevel@tonic-gate 			    THR_NEW_LWP, NULL);
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	/*
2890Sstevel@tonic-gate 	 * Exit main() thread
2900Sstevel@tonic-gate 	 */
2910Sstevel@tonic-gate 	thr_exit(NULL);
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	return (0);
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate static void
getintf(void)2970Sstevel@tonic-gate getintf(void)
2980Sstevel@tonic-gate {
2990Sstevel@tonic-gate 	int		fd;
3000Sstevel@tonic-gate 	int		numifs;
3010Sstevel@tonic-gate 	unsigned	bufsize;
3020Sstevel@tonic-gate 	struct ifreq	*reqbuf;
3030Sstevel@tonic-gate 	struct ifconf	ifconf;
3040Sstevel@tonic-gate 	struct ifreq	*ifr;
3050Sstevel@tonic-gate 	struct rarpdev	*rdev;
3060Sstevel@tonic-gate 	struct ifdev	*ifdev;
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	/*
3090Sstevel@tonic-gate 	 * Open the IP provider.
3100Sstevel@tonic-gate 	 */
3110Sstevel@tonic-gate 	if ((fd = open(DEVIP, 0)) < 0)
3120Sstevel@tonic-gate 		syserr(DEVIP);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	/*
3150Sstevel@tonic-gate 	 * Ask IP for the list of configured interfaces.
3160Sstevel@tonic-gate 	 */
3170Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) {
3180Sstevel@tonic-gate 		numifs = MAXIFS;
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 	bufsize = numifs * sizeof (struct ifreq);
3210Sstevel@tonic-gate 	reqbuf = (struct ifreq *)malloc(bufsize);
3220Sstevel@tonic-gate 	if (reqbuf == NULL) {
3230Sstevel@tonic-gate 		error("out of memory");
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	ifconf.ifc_len = bufsize;
3270Sstevel@tonic-gate 	ifconf.ifc_buf = (caddr_t)reqbuf;
3280Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFCONF, (char *)&ifconf) < 0)
3290Sstevel@tonic-gate 		syserr("SIOCGIFCONF");
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	/*
3324456Sss150715 	 * Initialize a rarpdev for each interface.
3330Sstevel@tonic-gate 	 */
3340Sstevel@tonic-gate 	for (ifr = ifconf.ifc_req; ifconf.ifc_len > 0;
3350Sstevel@tonic-gate 	    ifr++, ifconf.ifc_len -= sizeof (struct ifreq)) {
3360Sstevel@tonic-gate 		ifspec_t	ifsp;
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 		if (ioctl(fd, SIOCGIFFLAGS, (char *)ifr) < 0) {
3390Sstevel@tonic-gate 			syserr("ioctl SIOCGIFFLAGS");
3400Sstevel@tonic-gate 			exit(1);
3410Sstevel@tonic-gate 		}
3420Sstevel@tonic-gate 		if ((ifr->ifr_flags & IFF_LOOPBACK) ||
3430Sstevel@tonic-gate 		    !(ifr->ifr_flags & IFF_UP) ||
3440Sstevel@tonic-gate 		    !(ifr->ifr_flags & IFF_BROADCAST) ||
3450Sstevel@tonic-gate 		    (ifr->ifr_flags & IFF_NOARP) ||
3460Sstevel@tonic-gate 		    (ifr->ifr_flags & IFF_POINTOPOINT))
3470Sstevel@tonic-gate 			continue;
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 		if (!ifparse_ifspec(ifr->ifr_name, &ifsp))
3500Sstevel@tonic-gate 			error("ifparse_ifspec failed");
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		/*
3534456Sss150715 		 * Look for an existing device for logical interfaces.
3540Sstevel@tonic-gate 		 */
3550Sstevel@tonic-gate 		if ((rdev = find_device(&ifsp)) == NULL) {
3560Sstevel@tonic-gate 			rdev = calloc(1, sizeof (struct rarpdev));
3570Sstevel@tonic-gate 			if (rdev == NULL)
3580Sstevel@tonic-gate 				error("out of memory");
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 			(void) strlcpy(rdev->device, ifsp.ifsp_devnm,
3610Sstevel@tonic-gate 			    sizeof (rdev->device));
3620Sstevel@tonic-gate 			rdev->unit = ifsp.ifsp_ppa;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 			rdev->next = rarpdev_head;
3650Sstevel@tonic-gate 			rarpdev_head = rdev;
3660Sstevel@tonic-gate 		}
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 		if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL)
3690Sstevel@tonic-gate 			error("out of memory");
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 		if (ifsp.ifsp_lunvalid) {
3720Sstevel@tonic-gate 			(void) snprintf(ifdev->ldevice,
3730Sstevel@tonic-gate 			    sizeof (ifdev->ldevice), "%s%d:",
3740Sstevel@tonic-gate 			    ifsp.ifsp_devnm, ifsp.ifsp_ppa);
3750Sstevel@tonic-gate 			ifdev->lunit = ifsp.ifsp_lun;
3760Sstevel@tonic-gate 		} else
3770Sstevel@tonic-gate 			ifdev->lunit = -1; /* no logical unit */
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 		ifdev->next = rdev->ifdev;
3800Sstevel@tonic-gate 		rdev->ifdev = ifdev;
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate 	(void) free((char *)reqbuf);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate static struct rarpdev *
find_device(ifspec_t * specp)3860Sstevel@tonic-gate find_device(ifspec_t *specp)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	struct rarpdev	*rdev;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
3910Sstevel@tonic-gate 		if (specp->ifsp_ppa == rdev->unit &&
3920Sstevel@tonic-gate 		    strcmp(specp->ifsp_devnm, rdev->device) == 0)
3930Sstevel@tonic-gate 			return (rdev);
3940Sstevel@tonic-gate 	}
3950Sstevel@tonic-gate 	return (NULL);
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate static void
init_rarpdev(struct rarpdev * rdev)3990Sstevel@tonic-gate init_rarpdev(struct rarpdev *rdev)
4000Sstevel@tonic-gate {
4014456Sss150715 	char 		*dev;
4024456Sss150715 	int 		unit;
4034456Sss150715 	struct ifdev 	*ifdev;
4044456Sss150715 	int		retval;
4054456Sss150715 	char		*str = NULL;
4064456Sss150715 	uint_t		physaddrlen = DLPI_PHYSADDR_MAX;
4074456Sss150715 	char		linkname[DLPI_LINKNAME_MAX];
4084456Sss150715 	dlpi_handle_t	dh;
4090Sstevel@tonic-gate 
4104456Sss150715 	(void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", rdev->device,
4114456Sss150715 	    rdev->unit);
4120Sstevel@tonic-gate 	/*
4130Sstevel@tonic-gate 	 * Open datalink provider and get our mac address.
4140Sstevel@tonic-gate 	 */
4154456Sss150715 	if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) {
4164456Sss150715 		error("cannot open link %s: %s", linkname,
4174456Sss150715 		    dlpi_strerror(retval));
4184456Sss150715 	}
4194456Sss150715 
4204456Sss150715 	if ((retval = dlpi_bind(dh, ETHERTYPE_REVARP, NULL)) != DLPI_SUCCESS) {
4214456Sss150715 		dlpi_close(dh);
4224456Sss150715 		error("dlpi_bind failed: %s", dlpi_strerror(retval));
4234456Sss150715 	}
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	/*
4264456Sss150715 	 * Save our mac address.
4270Sstevel@tonic-gate 	 */
4284456Sss150715 	if ((retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, rdev->physaddr,
4294456Sss150715 	    &physaddrlen)) != DLPI_SUCCESS) {
4304456Sss150715 		dlpi_close(dh);
4314456Sss150715 		error("dlpi_get_physaddr failed: %s", dlpi_strerror(retval));
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 
4344456Sss150715 	rdev->physaddrlen = physaddrlen;
4354456Sss150715 	rdev->ifrarplen = sizeof (struct arphdr) + (2 * sizeof (ipaddr_t)) +
4364456Sss150715 	    (2 * physaddrlen);
4374456Sss150715 
4384456Sss150715 	if (dflag) {
4394456Sss150715 		str = _link_ntoa(rdev->physaddr, str,
4404456Sss150715 		    rdev->physaddrlen, IFT_OTHER);
4414456Sss150715 		if (str != NULL) {
4424456Sss150715 			debug("device %s physical address %s", linkname, str);
4434456Sss150715 			free(str);
4444456Sss150715 		}
4454456Sss150715 	}
4464456Sss150715 
4474456Sss150715 	/*
4484456Sss150715 	 * Assign dlpi handle to rdev.
4494456Sss150715 	 */
4504456Sss150715 	rdev->dh_rarp = dh;
4514456Sss150715 
4520Sstevel@tonic-gate 	/*
4530Sstevel@tonic-gate 	 * Get the IP address and netmask from directory service for
4540Sstevel@tonic-gate 	 * each logical interface.
4550Sstevel@tonic-gate 	 */
4560Sstevel@tonic-gate 	for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
4570Sstevel@tonic-gate 		/*
4584456Sss150715 		 * If lunit == -1 then this is the primary interface name.
4590Sstevel@tonic-gate 		 */
4600Sstevel@tonic-gate 		if (ifdev->lunit == -1) {
4610Sstevel@tonic-gate 			dev = rdev->device;
4620Sstevel@tonic-gate 			unit = rdev->unit;
4630Sstevel@tonic-gate 		} else {
4640Sstevel@tonic-gate 			dev = ifdev->ldevice;
4650Sstevel@tonic-gate 			unit = ifdev->lunit;
4660Sstevel@tonic-gate 		}
4670Sstevel@tonic-gate 		get_ifdata(dev, unit, &ifdev->if_ipaddr, &ifdev->if_netmask);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 		/*
4700Sstevel@tonic-gate 		 * Use IP address of the interface.
4710Sstevel@tonic-gate 		 */
4720Sstevel@tonic-gate 		ifdev->if_netnum = ifdev->if_ipaddr & ifdev->if_netmask;
4730Sstevel@tonic-gate 		ifdev->ipaddr = (ipaddr_t)htonl(ifdev->if_ipaddr);
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate static void
do_rarp(void * buf)4780Sstevel@tonic-gate do_rarp(void *buf)
4790Sstevel@tonic-gate {
4804456Sss150715 	struct rarpdev *rdev = buf;
4810Sstevel@tonic-gate 	char	*cause;
4820Sstevel@tonic-gate 	struct arphdr *ans;
4834456Sss150715 	uchar_t *shost;
4844456Sss150715 	uint_t	saddrlen;
4854456Sss150715 	size_t	anslen = rdev->ifrarplen;
4860Sstevel@tonic-gate 	char	*str = NULL;
4874456Sss150715 	int	retval;
4880Sstevel@tonic-gate 
4894456Sss150715 	if (((shost = malloc(rdev->physaddrlen)) == NULL) ||
4904456Sss150715 	    ((ans = malloc(rdev->ifrarplen)) == NULL))
4910Sstevel@tonic-gate 		syserr("malloc");
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	if (dflag) {
4944456Sss150715 		str = _link_ntoa(rdev->physaddr, str, rdev->physaddrlen,
4954456Sss150715 		    IFT_OTHER);
4960Sstevel@tonic-gate 		if (str != NULL) {
4974456Sss150715 			debug("starting rarp service on device %s%d physical"
4984456Sss150715 			    " address %s", rdev->device, rdev->unit, str);
4990Sstevel@tonic-gate 			free(str);
5000Sstevel@tonic-gate 		}
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	/*
5044456Sss150715 	 * Read RARP packets and respond to them.
5050Sstevel@tonic-gate 	 */
5060Sstevel@tonic-gate 	for (;;) {
5074456Sss150715 		saddrlen = DLPI_PHYSADDR_MAX;
5084456Sss150715 		retval = dlpi_recv(rdev->dh_rarp, shost,
5094456Sss150715 		    &saddrlen, ans, &anslen, -1, NULL);
5104456Sss150715 		if (retval == DLPI_ETIMEDOUT) {
5114456Sss150715 			continue;
5124456Sss150715 		} else if (retval != DLPI_SUCCESS) {
5134456Sss150715 			error("error in dlpi_recv %s: %s", rdev->dh_rarp,
5144456Sss150715 			    dlpi_strerror(retval));
5154456Sss150715 		}
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		cause = NULL;
5184456Sss150715 
5194456Sss150715 		if (anslen < rdev->ifrarplen)
5204456Sss150715 			cause = "short packet";
5210Sstevel@tonic-gate 		else if (ans->ar_hrd != htons(ARPHRD_ETHER))
5224456Sss150715 			cause = "hardware type not Ethernet";
5230Sstevel@tonic-gate 		else if (ans->ar_pro != htons(ETHERTYPE_IP))
5244456Sss150715 			cause = "protocol type not IP";
5254456Sss150715 		else if (ans->ar_hln != rdev->physaddrlen)
5264456Sss150715 			cause = "unexpected hardware address length";
5270Sstevel@tonic-gate 		else if (ans->ar_pln != sizeof (ipaddr_t))
5284456Sss150715 			cause = "unexpected protocol address length";
5294456Sss150715 		if (cause != NULL) {
5300Sstevel@tonic-gate 			if (dflag)
5314456Sss150715 				debug("RARP packet received but "
5324456Sss150715 				    "discarded: %s", cause);
5330Sstevel@tonic-gate 			continue;
5340Sstevel@tonic-gate 		}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 		/*
5370Sstevel@tonic-gate 		 * Handle the request.
5380Sstevel@tonic-gate 		 */
5390Sstevel@tonic-gate 		switch (ntohs(ans->ar_op)) {
5400Sstevel@tonic-gate 		case REVARP_REQUEST:
5410Sstevel@tonic-gate 			rarp_request(rdev, ans, shost);
5420Sstevel@tonic-gate 			break;
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 		case ARPOP_REQUEST:
5450Sstevel@tonic-gate 			arp_request(rdev, ans, shost);
5460Sstevel@tonic-gate 			break;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 		case REVARP_REPLY:
5490Sstevel@tonic-gate 			if (dflag)
5500Sstevel@tonic-gate 				debug("REVARP_REPLY ignored");
5510Sstevel@tonic-gate 			break;
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 		case ARPOP_REPLY:
5540Sstevel@tonic-gate 			if (dflag)
5550Sstevel@tonic-gate 				debug("ARPOP_REPLY ignored");
5560Sstevel@tonic-gate 			break;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 		default:
5590Sstevel@tonic-gate 			if (dflag)
5600Sstevel@tonic-gate 				debug("unknown opcode 0x%x", ans->ar_op);
5610Sstevel@tonic-gate 			break;
5620Sstevel@tonic-gate 		}
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate  * Reverse address determination and allocation code.
5680Sstevel@tonic-gate  */
5690Sstevel@tonic-gate static void
rarp_request(struct rarpdev * rdev,struct arphdr * rp,uchar_t * shost)5700Sstevel@tonic-gate rarp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost)
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate 	ipaddr_t		tpa,  spa;
5730Sstevel@tonic-gate 	struct	rarpreply	*rrp;
5740Sstevel@tonic-gate 	uchar_t			*shap, *thap, *spap, *tpap;
5750Sstevel@tonic-gate 	char			*str = NULL;
5764456Sss150715 	int			retval;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	shap = (uchar_t *)rp + sizeof (struct arphdr);
5790Sstevel@tonic-gate 	spap = shap + rp->ar_hln;
5800Sstevel@tonic-gate 	thap = spap + rp->ar_pln;
5810Sstevel@tonic-gate 	tpap = thap + rp->ar_hln;
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	if (dflag) {
5844456Sss150715 		str = _link_ntoa(thap, str, rdev->physaddrlen, IFT_OTHER);
5850Sstevel@tonic-gate 		if (str != NULL) {
5860Sstevel@tonic-gate 			debug("RARP_REQUEST for %s", str);
5870Sstevel@tonic-gate 			free(str);
5880Sstevel@tonic-gate 		}
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	/*
5924456Sss150715 	 * Third party lookups are rare and wonderful.
5930Sstevel@tonic-gate 	 */
5944456Sss150715 	if ((memcmp(shap, thap, rdev->physaddrlen) != 0) ||
5954456Sss150715 	    (memcmp(shap, shost, rdev->physaddrlen) != 0)) {
5960Sstevel@tonic-gate 		if (dflag)
5970Sstevel@tonic-gate 			debug("weird (3rd party lookup)");
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	/*
6014456Sss150715 	 * Fill in given parts of reply packet.
6020Sstevel@tonic-gate 	 */
6034456Sss150715 	(void) memcpy(shap, rdev->physaddr, rdev->physaddrlen);
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	/*
6060Sstevel@tonic-gate 	 * If a good address is stored in our lookup tables, return it
6074456Sss150715 	 * immediately or after a delay.  Store it in our kernel's ARP cache.
6080Sstevel@tonic-gate 	 */
6090Sstevel@tonic-gate 	if (get_ipaddr(rdev, thap, tpap, &spa))
6100Sstevel@tonic-gate 		return;
6110Sstevel@tonic-gate 	(void) memcpy(spap, &spa, sizeof (spa));
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	add_arp(rdev, tpap, thap);
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	rp->ar_op = htons(REVARP_REPLY);
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	if (dflag) {
6180Sstevel@tonic-gate 		struct in_addr addr;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 		(void) memcpy(&addr, tpap, sizeof (ipaddr_t));
6210Sstevel@tonic-gate 		debug("good lookup, maps to %s", inet_ntoa(addr));
6220Sstevel@tonic-gate 	}
6230Sstevel@tonic-gate 
6244456Sss150715 	rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen +
6254456Sss150715 	    rdev->ifrarplen);
6260Sstevel@tonic-gate 	if (rrp == NULL)
6270Sstevel@tonic-gate 		error("out of memory");
6280Sstevel@tonic-gate 	rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply);
6294456Sss150715 	rrp->arprep = rrp->lldest + rdev->physaddrlen;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	/*
6320Sstevel@tonic-gate 	 * Create rarpreply structure.
6330Sstevel@tonic-gate 	 */
6340Sstevel@tonic-gate 	(void) gettimeofday(&rrp->tv, NULL);
6350Sstevel@tonic-gate 	rrp->tv.tv_sec += 3;	/* delay */
6360Sstevel@tonic-gate 	rrp->rdev = rdev;
6374456Sss150715 	(void) memcpy(rrp->lldest, shost, rdev->physaddrlen);
6380Sstevel@tonic-gate 	(void) memcpy(rrp->arprep, rp, rdev->ifrarplen);
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	/*
6410Sstevel@tonic-gate 	 * If this is diskless and we're not its bootserver, let the
6420Sstevel@tonic-gate 	 * bootserver reply first by delaying a while.
6430Sstevel@tonic-gate 	 */
6440Sstevel@tonic-gate 	(void) memcpy(&tpa, tpap, sizeof (ipaddr_t));
6450Sstevel@tonic-gate 	if (mightboot(ntohl(tpa))) {
6464456Sss150715 		retval = dlpi_send(rdev->dh_rarp, rrp->lldest,
6474456Sss150715 		    rdev->physaddrlen, rrp->arprep, rdev->ifrarplen, NULL);
6484456Sss150715 		if (retval != DLPI_SUCCESS) {
6494456Sss150715 			error("dlpi_send failed: %s", dlpi_strerror(retval));
6504456Sss150715 		} else if (dflag) {
6510Sstevel@tonic-gate 			debug("immediate reply sent");
6524456Sss150715 		}
6530Sstevel@tonic-gate 		(void) free(rrp);
6540Sstevel@tonic-gate 	} else {
6550Sstevel@tonic-gate 		delay_write(rdev, rrp);
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate /*
6600Sstevel@tonic-gate  * Download an ARP entry into our kernel.
6610Sstevel@tonic-gate  */
6620Sstevel@tonic-gate static void
add_arp(struct rarpdev * rdev,uchar_t * ip,uchar_t * laddr)6630Sstevel@tonic-gate add_arp(struct rarpdev *rdev, uchar_t *ip, uchar_t *laddr)
6640Sstevel@tonic-gate {
6650Sstevel@tonic-gate 	struct xarpreq ar;
6660Sstevel@tonic-gate 	struct sockaddr_in	*sin;
6670Sstevel@tonic-gate 	int	fd;
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	/*
6704456Sss150715 	 * Common part of query or set.
6710Sstevel@tonic-gate 	 */
6720Sstevel@tonic-gate 	(void) memset(&ar, 0, sizeof (ar));
6730Sstevel@tonic-gate 	ar.xarp_pa.ss_family = AF_INET;
6740Sstevel@tonic-gate 	sin = (struct sockaddr_in *)&ar.xarp_pa;
6750Sstevel@tonic-gate 	(void) memcpy(&sin->sin_addr, ip, sizeof (ipaddr_t));
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	/*
6780Sstevel@tonic-gate 	 * Open the IP provider.
6790Sstevel@tonic-gate 	 */
6800Sstevel@tonic-gate 	if ((fd = open(DEVARP, 0)) < 0)
6810Sstevel@tonic-gate 		syserr(DEVARP);
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	/*
6844456Sss150715 	 * Set the entry.
6850Sstevel@tonic-gate 	 */
6864456Sss150715 	(void) memcpy(LLADDR(&ar.xarp_ha), laddr, rdev->physaddrlen);
6874456Sss150715 	ar.xarp_ha.sdl_alen = rdev->physaddrlen;
6880Sstevel@tonic-gate 	ar.xarp_ha.sdl_family = AF_LINK;
6890Sstevel@tonic-gate 	(void) strioctl(fd, SIOCDXARP, -1, sizeof (struct xarpreq),
6900Sstevel@tonic-gate 	    (char *)&ar);
6910Sstevel@tonic-gate 	if (strioctl(fd, SIOCSXARP, -1, sizeof (struct xarpreq),
6920Sstevel@tonic-gate 	    (char *)&ar) < 0)
6930Sstevel@tonic-gate 		syserr("SIOCSXARP");
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	(void) close(fd);
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate /*
6990Sstevel@tonic-gate  * The RARP spec says we must be able to process ARP requests,
7000Sstevel@tonic-gate  * even through the packet type is RARP.  Let's hope this feature
7010Sstevel@tonic-gate  * is not heavily used.
7020Sstevel@tonic-gate  */
7030Sstevel@tonic-gate static void
arp_request(struct rarpdev * rdev,struct arphdr * rp,uchar_t * shost)7040Sstevel@tonic-gate arp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost)
7050Sstevel@tonic-gate {
7060Sstevel@tonic-gate 	struct	rarpreply	*rrp;
7070Sstevel@tonic-gate 	struct ifdev		*ifdev;
7080Sstevel@tonic-gate 	uchar_t			*shap, *thap, *spap, *tpap;
7094456Sss150715 	int			retval;
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	shap = (uchar_t *)rp + sizeof (struct arphdr);
7120Sstevel@tonic-gate 	spap = shap + rp->ar_hln;
7130Sstevel@tonic-gate 	thap = spap + rp->ar_pln;
7140Sstevel@tonic-gate 	tpap = thap + rp->ar_hln;
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	if (dflag)
7170Sstevel@tonic-gate 		debug("ARPOP_REQUEST");
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
7200Sstevel@tonic-gate 		if (memcmp(&ifdev->ipaddr, tpap, sizeof (ipaddr_t)) == 0)
7210Sstevel@tonic-gate 			break;
7220Sstevel@tonic-gate 	}
7230Sstevel@tonic-gate 	if (ifdev == NULL)
7240Sstevel@tonic-gate 		return;
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	rp->ar_op = ARPOP_REPLY;
7274456Sss150715 	(void) memcpy(shap, rdev->physaddr, rdev->physaddrlen);
7280Sstevel@tonic-gate 	(void) memcpy(spap, &ifdev->ipaddr, sizeof (ipaddr_t));
7294456Sss150715 	(void) memcpy(thap, rdev->physaddr, rdev->physaddrlen);
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	add_arp(rdev, tpap, thap);
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	/*
7340Sstevel@tonic-gate 	 * Create rarp reply structure.
7350Sstevel@tonic-gate 	 */
7364456Sss150715 	rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen +
7374456Sss150715 	    rdev->ifrarplen);
7380Sstevel@tonic-gate 	if (rrp == NULL)
7390Sstevel@tonic-gate 		error("out of memory");
7400Sstevel@tonic-gate 	rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply);
7414456Sss150715 	rrp->arprep = rrp->lldest + rdev->physaddrlen;
7420Sstevel@tonic-gate 	rrp->rdev = rdev;
7430Sstevel@tonic-gate 
7444456Sss150715 	(void) memcpy(rrp->lldest, shost, rdev->physaddrlen);
7450Sstevel@tonic-gate 	(void) memcpy(rrp->arprep, rp, rdev->ifrarplen);
7460Sstevel@tonic-gate 
7474456Sss150715 	retval = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen,
7484456Sss150715 	    rrp->arprep, rdev->ifrarplen, NULL);
7490Sstevel@tonic-gate 	free(rrp);
7504456Sss150715 	if (retval != DLPI_SUCCESS)
7514456Sss150715 		error("dlpi_send failed: %s", dlpi_strerror(retval));
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate /* ARGSUSED */
7550Sstevel@tonic-gate static void
do_delay_write(void * buf)7560Sstevel@tonic-gate do_delay_write(void *buf)
7570Sstevel@tonic-gate {
7580Sstevel@tonic-gate 	struct	timeval		tv;
7590Sstevel@tonic-gate 	struct	rarpreply	*rrp;
7604456Sss150715 	struct	rarpdev		*rdev;
7610Sstevel@tonic-gate 	int			err;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	for (;;) {
7640Sstevel@tonic-gate 		if ((err = sema_wait(&delay_sema)) != 0) {
7650Sstevel@tonic-gate 			if (err == EINTR)
7660Sstevel@tonic-gate 				continue;
7670Sstevel@tonic-gate 			error("do_delay_write: sema_wait failed");
7680Sstevel@tonic-gate 		}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 		(void) mutex_lock(&delay_mutex);
7710Sstevel@tonic-gate 		rrp = delay_list;
7724456Sss150715 		rdev = rrp->rdev;
7730Sstevel@tonic-gate 		delay_list = delay_list->next;
7740Sstevel@tonic-gate 		(void) mutex_unlock(&delay_mutex);
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 		(void) gettimeofday(&tv, NULL);
7770Sstevel@tonic-gate 		if (tv.tv_sec < rrp->tv.tv_sec)
7780Sstevel@tonic-gate 			(void) sleep(rrp->tv.tv_sec - tv.tv_sec);
7790Sstevel@tonic-gate 
7804456Sss150715 		err = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen,
7814456Sss150715 		    rrp->arprep, rdev->ifrarplen, NULL);
7824456Sss150715 		if (err != DLPI_SUCCESS)
7834456Sss150715 			error("dlpi_send failed: %s", dlpi_strerror(err));
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 		(void) free(rrp);
7860Sstevel@tonic-gate 	}
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate /* ARGSUSED */
7900Sstevel@tonic-gate static void
delay_write(struct rarpdev * rdev,struct rarpreply * rrp)7910Sstevel@tonic-gate delay_write(struct rarpdev *rdev, struct rarpreply *rrp)
7920Sstevel@tonic-gate {
7930Sstevel@tonic-gate 	struct	rarpreply	*trp;
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	(void) mutex_lock(&delay_mutex);
7960Sstevel@tonic-gate 	if (delay_list == NULL) {
7970Sstevel@tonic-gate 		delay_list = rrp;
7980Sstevel@tonic-gate 	} else {
7990Sstevel@tonic-gate 		trp = delay_list;
8000Sstevel@tonic-gate 		while (trp->next != NULL)
8010Sstevel@tonic-gate 			trp = trp->next;
8020Sstevel@tonic-gate 		trp->next = rrp;
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 	(void) mutex_unlock(&delay_mutex);
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	(void) sema_post(&delay_sema);
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate /*
8100Sstevel@tonic-gate  * See if we have a TFTP boot file for this guy. Filenames in TFTP
8110Sstevel@tonic-gate  * boot requests are of the form <ipaddr> for Sun-3's and of the form
8120Sstevel@tonic-gate  * <ipaddr>.<arch> for all other architectures.  Since we don't know
8130Sstevel@tonic-gate  * the client's architecture, either format will do.
8140Sstevel@tonic-gate  */
8150Sstevel@tonic-gate static int
mightboot(ipaddr_t ipa)8160Sstevel@tonic-gate mightboot(ipaddr_t ipa)
8170Sstevel@tonic-gate {
8180Sstevel@tonic-gate 	char path[MAXPATHL];
8190Sstevel@tonic-gate 	DIR *dirp;
8200Sstevel@tonic-gate 	struct dirent *dp;
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s/%08X", BOOTDIR, ipa);
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	/*
8250Sstevel@tonic-gate 	 * Try a quick access() first.
8260Sstevel@tonic-gate 	 */
8270Sstevel@tonic-gate 	if (access(path, 0) == 0)
8280Sstevel@tonic-gate 		return (1);
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	/*
8310Sstevel@tonic-gate 	 * Not there, do it the slow way by
8320Sstevel@tonic-gate 	 * reading through the directory.
8330Sstevel@tonic-gate 	 */
8340Sstevel@tonic-gate 	(void) sprintf(path, "%08X", ipa);
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	if (!(dirp = opendir(BOOTDIR)))
8370Sstevel@tonic-gate 		return (0);
8380Sstevel@tonic-gate 
839871Scasper 	while ((dp = readdir(dirp)) != NULL) {
8400Sstevel@tonic-gate 		if (strncmp(dp->d_name, path, 8) != 0)
8410Sstevel@tonic-gate 			continue;
8420Sstevel@tonic-gate 		if ((strlen(dp->d_name) != 8) && (dp->d_name[8] != '.'))
8430Sstevel@tonic-gate 			continue;
8440Sstevel@tonic-gate 		break;
8450Sstevel@tonic-gate 	}
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	(void) closedir(dirp);
8480Sstevel@tonic-gate 
8494456Sss150715 	return ((dp != NULL) ? 1 : 0);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate /*
8530Sstevel@tonic-gate  * Get our IP address and local netmask.
8540Sstevel@tonic-gate  */
8550Sstevel@tonic-gate static void
get_ifdata(char * dev,int unit,ipaddr_t * ipp,ipaddr_t * maskp)8560Sstevel@tonic-gate get_ifdata(char *dev, int unit, ipaddr_t *ipp, ipaddr_t *maskp)
8570Sstevel@tonic-gate {
8580Sstevel@tonic-gate 	int	fd;
8590Sstevel@tonic-gate 	struct	ifreq	ifr;
8600Sstevel@tonic-gate 	struct	sockaddr_in	*sin;
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	/* LINTED pointer */
8630Sstevel@tonic-gate 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	/*
8660Sstevel@tonic-gate 	 * Open the IP provider.
8670Sstevel@tonic-gate 	 */
8680Sstevel@tonic-gate 	if ((fd = open(DEVIP, 0)) < 0)
8690Sstevel@tonic-gate 		syserr(DEVIP);
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	/*
8720Sstevel@tonic-gate 	 * Ask IP for our IP address.
8730Sstevel@tonic-gate 	 */
8740Sstevel@tonic-gate 	(void) snprintf(ifr.ifr_name, sizeof (ifr.ifr_name), "%s%d", dev, unit);
8750Sstevel@tonic-gate 	if (strioctl(fd, SIOCGIFADDR, -1, sizeof (struct ifreq),
8764456Sss150715 	    (char *)&ifr) < 0)
8770Sstevel@tonic-gate 		syserr("SIOCGIFADDR");
8780Sstevel@tonic-gate 	*ipp = (ipaddr_t)ntohl(sin->sin_addr.s_addr);
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	if (dflag)
8814456Sss150715 		debug("device %s%d address %s", dev, unit,
8824456Sss150715 		    inet_ntoa(sin->sin_addr));
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	/*
8850Sstevel@tonic-gate 	 * Ask IP for our netmask.
8860Sstevel@tonic-gate 	 */
8870Sstevel@tonic-gate 	if (strioctl(fd, SIOCGIFNETMASK, -1, sizeof (struct ifreq),
8884456Sss150715 	    (char *)&ifr) < 0)
8890Sstevel@tonic-gate 		syserr("SIOCGIFNETMASK");
8900Sstevel@tonic-gate 	*maskp = (ipaddr_t)ntohl(sin->sin_addr.s_addr);
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	if (dflag)
8934456Sss150715 		debug("device %s%d subnet mask %s", dev, unit,
8944456Sss150715 		    inet_ntoa(sin->sin_addr));
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	/*
8970Sstevel@tonic-gate 	 * Thankyou ip.
8980Sstevel@tonic-gate 	 */
8990Sstevel@tonic-gate 	(void) close(fd);
9000Sstevel@tonic-gate }
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate /*
9030Sstevel@tonic-gate  * Translate mac address to IP address.
9040Sstevel@tonic-gate  * Return 0 on success, nonzero on failure.
9050Sstevel@tonic-gate  */
9060Sstevel@tonic-gate static int
get_ipaddr(struct rarpdev * rdev,uchar_t * laddr,uchar_t * ipp,ipaddr_t * ipaddr)9070Sstevel@tonic-gate get_ipaddr(struct rarpdev *rdev, uchar_t *laddr, uchar_t *ipp, ipaddr_t *ipaddr)
9080Sstevel@tonic-gate {
9090Sstevel@tonic-gate 	char host[MAXHOSTL];
9100Sstevel@tonic-gate 	char hbuffer[BUFSIZE];
9110Sstevel@tonic-gate 	struct hostent *hp, res;
9120Sstevel@tonic-gate 	int herror;
9130Sstevel@tonic-gate 	struct in_addr addr;
9140Sstevel@tonic-gate 	char	**p;
9150Sstevel@tonic-gate 	struct ifdev *ifdev;
9160Sstevel@tonic-gate 
9174456Sss150715 	if (rdev->physaddrlen != ETHERADDRL) {
9180Sstevel@tonic-gate 		if (dflag)
9194456Sss150715 			debug("%s %s", " cannot map non 6 byte hardware ",
9200Sstevel@tonic-gate 			    "address to IP address");
9210Sstevel@tonic-gate 		return (1);
9220Sstevel@tonic-gate 	}
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	/*
9254456Sss150715 	 * Translate mac address to hostname and IP address.
9260Sstevel@tonic-gate 	 */
9270Sstevel@tonic-gate 	if (ether_ntohost(host, (struct ether_addr *)laddr) != 0 ||
9280Sstevel@tonic-gate 	    !(hp = gethostbyname_r(host, &res, hbuffer, sizeof (hbuffer),
9290Sstevel@tonic-gate 	    &herror)) ||
9300Sstevel@tonic-gate 	    hp->h_addrtype != AF_INET || hp->h_length != sizeof (ipaddr_t)) {
9310Sstevel@tonic-gate 		if (dflag)
9320Sstevel@tonic-gate 			debug("could not map hardware address to IP address");
9330Sstevel@tonic-gate 		return (1);
9340Sstevel@tonic-gate 	}
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	/*
9370Sstevel@tonic-gate 	 * Find the IP address on the right net.
9380Sstevel@tonic-gate 	 */
9390Sstevel@tonic-gate 	for (p = hp->h_addr_list; *p; p++) {
9400Sstevel@tonic-gate 		(void) memcpy(&addr, *p, sizeof (ipaddr_t));
9410Sstevel@tonic-gate 		for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
9420Sstevel@tonic-gate 			if (dflag) {
9430Sstevel@tonic-gate 				struct in_addr daddr;
9440Sstevel@tonic-gate 				ipaddr_t netnum;
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 				netnum = htonl(ifdev->if_netnum);
9470Sstevel@tonic-gate 				(void) memcpy(&daddr, &netnum,
9480Sstevel@tonic-gate 				    sizeof (ipaddr_t));
9490Sstevel@tonic-gate 				if (ifdev->lunit == -1)
9504456Sss150715 					debug("trying physical netnum %s"
9514456Sss150715 					    " mask %x", inet_ntoa(daddr),
9524456Sss150715 					    ifdev->if_netmask);
9530Sstevel@tonic-gate 				else
9544456Sss150715 					debug("trying logical %d netnum %s"
9554456Sss150715 					    " mask %x", ifdev->lunit,
9564456Sss150715 					    inet_ntoa(daddr),
9574456Sss150715 					    ifdev->if_netmask);
9580Sstevel@tonic-gate 			}
9590Sstevel@tonic-gate 			if ((ntohl(addr.s_addr) & ifdev->if_netmask) ==
9604456Sss150715 			    ifdev->if_netnum) {
9610Sstevel@tonic-gate 				/*
9620Sstevel@tonic-gate 				 * Return the correct IP address.
9630Sstevel@tonic-gate 				 */
9640Sstevel@tonic-gate 				(void) memcpy(ipp, &addr, sizeof (ipaddr_t));
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 				/*
9670Sstevel@tonic-gate 				 * Return the interface's ipaddr
9680Sstevel@tonic-gate 				 */
9690Sstevel@tonic-gate 				(void) memcpy(ipaddr, &ifdev->ipaddr,
9700Sstevel@tonic-gate 				    sizeof (ipaddr_t));
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 				return (0);
9730Sstevel@tonic-gate 			}
9740Sstevel@tonic-gate 		}
9750Sstevel@tonic-gate 	}
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	if (dflag)
9780Sstevel@tonic-gate 		debug("got host entry but no IP address on this net");
9790Sstevel@tonic-gate 	return (1);
9800Sstevel@tonic-gate }
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate static int
strioctl(int fd,int cmd,int timout,int len,char * dp)9830Sstevel@tonic-gate strioctl(int fd, int cmd, int timout, int len, char *dp)
9840Sstevel@tonic-gate {
9850Sstevel@tonic-gate 	struct	strioctl	si;
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	si.ic_cmd = cmd;
9880Sstevel@tonic-gate 	si.ic_timout = timout;
9890Sstevel@tonic-gate 	si.ic_len = len;
9900Sstevel@tonic-gate 	si.ic_dp = dp;
9910Sstevel@tonic-gate 	return (ioctl(fd, I_STR, &si));
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate static void
usage(void)9954456Sss150715 usage(void)
9960Sstevel@tonic-gate {
9970Sstevel@tonic-gate 	error("Usage:  %s [ -ad ] device unit", cmdname);
9980Sstevel@tonic-gate }
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate static void
syserr(const char * s)10014456Sss150715 syserr(const char *s)
10020Sstevel@tonic-gate {
10030Sstevel@tonic-gate 	char buf[256];
10040Sstevel@tonic-gate 	int status = 1;
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s: %s", s, strerror(errno));
10070Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:  %s\n", cmdname, buf);
10080Sstevel@tonic-gate 	syslog(LOG_ERR, "%s", buf);
10090Sstevel@tonic-gate 	thr_exit(&status);
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate static void
error(const char * fmt,...)10134456Sss150715 error(const char *fmt, ...)
10140Sstevel@tonic-gate {
10150Sstevel@tonic-gate 	char buf[256];
10160Sstevel@tonic-gate 	va_list ap;
10170Sstevel@tonic-gate 	int status = 1;
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	va_start(ap, fmt);
10200Sstevel@tonic-gate 	(void) vsprintf(buf, fmt, ap);
10210Sstevel@tonic-gate 	va_end(ap);
10220Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:  %s\n", cmdname, buf);
10230Sstevel@tonic-gate 	syslog(LOG_ERR, buf);
10240Sstevel@tonic-gate 	thr_exit(&status);
10250Sstevel@tonic-gate }
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate /*PRINTFLIKE1*/
10280Sstevel@tonic-gate static void
debug(char * fmt,...)10290Sstevel@tonic-gate debug(char *fmt, ...)
10300Sstevel@tonic-gate {
10310Sstevel@tonic-gate 	va_list ap;
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	(void) mutex_lock(&debug_mutex);
10340Sstevel@tonic-gate 	va_start(ap, fmt);
10350Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:[%u]  ", cmdname, thr_self());
10360Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
10370Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
10380Sstevel@tonic-gate 	va_end(ap);
10390Sstevel@tonic-gate 	(void) mutex_unlock(&debug_mutex);
10400Sstevel@tonic-gate }
1041