17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5004388ebScasper * Common Development and Distribution License (the "License").
6004388ebScasper * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*2b24ab6bSSebastien Roy * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
267c478bd9Sstevel@tonic-gate /* All Rights Reserved */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD
307c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California.
317c478bd9Sstevel@tonic-gate */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate * rarpd.c Reverse-ARP server.
357c478bd9Sstevel@tonic-gate * Refer to RFC 903 "A Reverse Address Resolution Protocol".
367c478bd9Sstevel@tonic-gate */
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate #define _REENTRANT
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate #include <thread.h>
417c478bd9Sstevel@tonic-gate #include <synch.h>
427c478bd9Sstevel@tonic-gate #include <stdlib.h>
437c478bd9Sstevel@tonic-gate #include <unistd.h>
447c478bd9Sstevel@tonic-gate #include <sys/resource.h>
457c478bd9Sstevel@tonic-gate #include <stdio.h>
46004388ebScasper #include <stdio_ext.h>
477c478bd9Sstevel@tonic-gate #include <stdarg.h>
487c478bd9Sstevel@tonic-gate #include <string.h>
497c478bd9Sstevel@tonic-gate #include <fcntl.h>
507c478bd9Sstevel@tonic-gate #include <sys/types.h>
517c478bd9Sstevel@tonic-gate #include <dirent.h>
527c478bd9Sstevel@tonic-gate #include <syslog.h>
537c478bd9Sstevel@tonic-gate #include <netdb.h>
547c478bd9Sstevel@tonic-gate #include <errno.h>
557c478bd9Sstevel@tonic-gate #include <sys/socket.h>
567c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
577c478bd9Sstevel@tonic-gate #include <net/if.h>
587c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
597c478bd9Sstevel@tonic-gate #include <netinet/in.h>
607c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
617c478bd9Sstevel@tonic-gate #include <stropts.h>
627c478bd9Sstevel@tonic-gate #include <libinetutil.h>
63948f2876Sss150715 #include <libdlpi.h>
647c478bd9Sstevel@tonic-gate #include <net/if_types.h>
657c478bd9Sstevel@tonic-gate #include <net/if_dl.h>
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate #define BOOTDIR "/tftpboot" /* boot files directory */
687c478bd9Sstevel@tonic-gate #define DEVIP "/dev/ip" /* path to ip driver */
697c478bd9Sstevel@tonic-gate #define DEVARP "/dev/arp" /* path to arp driver */
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate #define BUFSIZE 2048 /* max receive frame length */
727c478bd9Sstevel@tonic-gate #define MAXPATHL 128 /* max path length */
737c478bd9Sstevel@tonic-gate #define MAXHOSTL 128 /* max host name length */
747c478bd9Sstevel@tonic-gate #define MAXIFS 256
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate * Logical network devices
787c478bd9Sstevel@tonic-gate */
797c478bd9Sstevel@tonic-gate struct ifdev {
807c478bd9Sstevel@tonic-gate char ldevice[IFNAMSIZ];
817c478bd9Sstevel@tonic-gate int lunit;
827c478bd9Sstevel@tonic-gate ipaddr_t ipaddr; /* network order */
837c478bd9Sstevel@tonic-gate ipaddr_t if_netmask; /* host order */
847c478bd9Sstevel@tonic-gate ipaddr_t if_ipaddr; /* host order */
857c478bd9Sstevel@tonic-gate ipaddr_t if_netnum; /* host order, with subnet */
867c478bd9Sstevel@tonic-gate struct ifdev *next;
877c478bd9Sstevel@tonic-gate };
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate * Physical network device
917c478bd9Sstevel@tonic-gate */
927c478bd9Sstevel@tonic-gate struct rarpdev {
93948f2876Sss150715 char device[DLPI_LINKNAME_MAX];
94948f2876Sss150715 uint_t unit;
95948f2876Sss150715 dlpi_handle_t dh_rarp;
96948f2876Sss150715 uchar_t physaddr[DLPI_PHYSADDR_MAX];
97948f2876Sss150715 /* mac address of interface */
98948f2876Sss150715 uint_t physaddrlen; /* mac address length */
997c478bd9Sstevel@tonic-gate int ifrarplen; /* size of rarp data packet */
1007c478bd9Sstevel@tonic-gate struct ifdev *ifdev; /* private interface info */
1017c478bd9Sstevel@tonic-gate struct rarpdev *next; /* list of managed devices */
1027c478bd9Sstevel@tonic-gate };
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate struct rarpreply {
1057c478bd9Sstevel@tonic-gate struct rarpdev *rdev; /* which device reply for */
1067c478bd9Sstevel@tonic-gate struct timeval tv; /* send RARP reply by when */
1077c478bd9Sstevel@tonic-gate uchar_t *lldest; /* target mac to send reply */
1087c478bd9Sstevel@tonic-gate uchar_t *arprep; /* [R]ARP response */
1097c478bd9Sstevel@tonic-gate struct rarpreply *next;
1107c478bd9Sstevel@tonic-gate };
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate static struct rarpreply *delay_list;
1137c478bd9Sstevel@tonic-gate static sema_t delay_sema;
1147c478bd9Sstevel@tonic-gate static mutex_t delay_mutex;
1157c478bd9Sstevel@tonic-gate static mutex_t debug_mutex;
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate static struct rarpdev *rarpdev_head;
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate /*
1207c478bd9Sstevel@tonic-gate * Globals initialized before multi-threading
1217c478bd9Sstevel@tonic-gate */
1227c478bd9Sstevel@tonic-gate static char *cmdname; /* command name from argv[0] */
1237c478bd9Sstevel@tonic-gate static int dflag = 0; /* enable diagnostics */
1247c478bd9Sstevel@tonic-gate static int aflag = 0; /* start rarpd on all interfaces */
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate static void getintf(void);
1277c478bd9Sstevel@tonic-gate static struct rarpdev *find_device(ifspec_t *);
1287c478bd9Sstevel@tonic-gate static void init_rarpdev(struct rarpdev *);
1297c478bd9Sstevel@tonic-gate static void do_rarp(void *);
1307c478bd9Sstevel@tonic-gate static void rarp_request(struct rarpdev *, struct arphdr *,
1317c478bd9Sstevel@tonic-gate uchar_t *);
1327c478bd9Sstevel@tonic-gate static void add_arp(struct rarpdev *, uchar_t *, uchar_t *);
1337c478bd9Sstevel@tonic-gate static void arp_request(struct rarpdev *, struct arphdr *, uchar_t *);
1347c478bd9Sstevel@tonic-gate static void do_delay_write(void *);
1357c478bd9Sstevel@tonic-gate static void delay_write(struct rarpdev *, struct rarpreply *);
1367c478bd9Sstevel@tonic-gate static int mightboot(ipaddr_t);
1377c478bd9Sstevel@tonic-gate static void get_ifdata(char *, int, ipaddr_t *, ipaddr_t *);
1387c478bd9Sstevel@tonic-gate static int get_ipaddr(struct rarpdev *, uchar_t *, uchar_t *, ipaddr_t *);
1397c478bd9Sstevel@tonic-gate static int strioctl(int, int, int, int, char *);
1407c478bd9Sstevel@tonic-gate static void usage();
141948f2876Sss150715 static void syserr(const char *);
142948f2876Sss150715 /*PRINTFLIKE1*/
143948f2876Sss150715 static void error(const char *, ...);
1447c478bd9Sstevel@tonic-gate static void debug(char *, ...);
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate extern int optind;
1477c478bd9Sstevel@tonic-gate extern char *optarg;
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])1507c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate int c;
1537c478bd9Sstevel@tonic-gate struct rlimit rl;
1547c478bd9Sstevel@tonic-gate struct rarpdev *rdev;
1557c478bd9Sstevel@tonic-gate int i;
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate cmdname = argv[0];
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "ad")) != -1) {
1607c478bd9Sstevel@tonic-gate switch (c) {
1617c478bd9Sstevel@tonic-gate case 'a':
1627c478bd9Sstevel@tonic-gate aflag = 1;
1637c478bd9Sstevel@tonic-gate break;
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate case 'd':
1667c478bd9Sstevel@tonic-gate dflag = 1;
1677c478bd9Sstevel@tonic-gate break;
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate default:
1707c478bd9Sstevel@tonic-gate usage();
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate if ((!aflag && (argc - optind) != 2) ||
1757c478bd9Sstevel@tonic-gate (aflag && (argc - optind) != 0)) {
1767c478bd9Sstevel@tonic-gate usage();
1777c478bd9Sstevel@tonic-gate /* NOTREACHED */
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate if (!dflag) {
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate * Background
1837c478bd9Sstevel@tonic-gate */
1847c478bd9Sstevel@tonic-gate switch (fork()) {
1857c478bd9Sstevel@tonic-gate case -1: /* error */
1867c478bd9Sstevel@tonic-gate syserr("fork");
1877c478bd9Sstevel@tonic-gate /*NOTREACHED*/
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate case 0: /* child */
1907c478bd9Sstevel@tonic-gate break;
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate default: /* parent */
1937c478bd9Sstevel@tonic-gate return (0);
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate for (i = 0; i < 3; i++) {
1967c478bd9Sstevel@tonic-gate (void) close(i);
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate (void) open("/", O_RDONLY, 0);
1997c478bd9Sstevel@tonic-gate (void) dup2(0, 1);
2007c478bd9Sstevel@tonic-gate (void) dup2(0, 2);
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate * Detach terminal
2037c478bd9Sstevel@tonic-gate */
2047c478bd9Sstevel@tonic-gate if (setsid() < 0)
2057c478bd9Sstevel@tonic-gate syserr("setsid");
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate rl.rlim_cur = RLIM_INFINITY;
2097c478bd9Sstevel@tonic-gate rl.rlim_max = RLIM_INFINITY;
2107c478bd9Sstevel@tonic-gate if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
2117c478bd9Sstevel@tonic-gate syserr("setrlimit");
212004388ebScasper (void) enable_extended_FILE_stdio(-1, -1);
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate (void) openlog(cmdname, LOG_PID, LOG_DAEMON);
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate if (aflag) {
2177c478bd9Sstevel@tonic-gate /*
218948f2876Sss150715 * Get each interface name and load rarpdev list.
2197c478bd9Sstevel@tonic-gate */
2207c478bd9Sstevel@tonic-gate getintf();
2217c478bd9Sstevel@tonic-gate } else {
2227c478bd9Sstevel@tonic-gate ifspec_t ifsp;
2237c478bd9Sstevel@tonic-gate struct ifdev *ifdev;
2247c478bd9Sstevel@tonic-gate char buf[IFNAMSIZ + 1];
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate /*
227948f2876Sss150715 * Load specified device as only element of the list.
2287c478bd9Sstevel@tonic-gate */
2297c478bd9Sstevel@tonic-gate rarpdev_head = (struct rarpdev *)calloc(1,
2307c478bd9Sstevel@tonic-gate sizeof (struct rarpdev));
2317c478bd9Sstevel@tonic-gate if (rarpdev_head == NULL) {
2327c478bd9Sstevel@tonic-gate error("out of memory");
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate (void) strncpy(buf, argv[optind], IFNAMSIZ);
2357c478bd9Sstevel@tonic-gate (void) strncat(buf, argv[optind + 1], IFNAMSIZ - strlen(buf));
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL) {
2387c478bd9Sstevel@tonic-gate error("out of memory");
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate
241*2b24ab6bSSebastien Roy if (!ifparse_ifspec(buf, &ifsp))
2427c478bd9Sstevel@tonic-gate error("invalid interface specification");
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate if (ifsp.ifsp_lunvalid) {
2457c478bd9Sstevel@tonic-gate (void) snprintf(ifdev->ldevice,
2467c478bd9Sstevel@tonic-gate sizeof (ifdev->ldevice), "%s%d:",
2477c478bd9Sstevel@tonic-gate ifsp.ifsp_devnm, ifsp.ifsp_ppa);
2487c478bd9Sstevel@tonic-gate ifdev->lunit = ifsp.ifsp_lun;
249948f2876Sss150715 } else {
2507c478bd9Sstevel@tonic-gate ifdev->lunit = -1; /* no logical unit */
251948f2876Sss150715 }
2527c478bd9Sstevel@tonic-gate (void) strlcpy(rarpdev_head->device, ifsp.ifsp_devnm,
2537c478bd9Sstevel@tonic-gate sizeof (rarpdev_head->device));
2547c478bd9Sstevel@tonic-gate rarpdev_head->unit = ifsp.ifsp_ppa;
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate ifdev->next = rarpdev_head->ifdev;
2577c478bd9Sstevel@tonic-gate rarpdev_head->ifdev = ifdev;
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate /*
261948f2876Sss150715 * Initialize each rarpdev.
2627c478bd9Sstevel@tonic-gate */
2637c478bd9Sstevel@tonic-gate for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
2647c478bd9Sstevel@tonic-gate init_rarpdev(rdev);
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate (void) sema_init(&delay_sema, 0, USYNC_THREAD, NULL);
2687c478bd9Sstevel@tonic-gate (void) mutex_init(&delay_mutex, USYNC_THREAD, NULL);
2697c478bd9Sstevel@tonic-gate (void) mutex_init(&debug_mutex, USYNC_THREAD, NULL);
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate /*
272948f2876Sss150715 * Start delayed processing thread.
2737c478bd9Sstevel@tonic-gate */
2747c478bd9Sstevel@tonic-gate (void) thr_create(NULL, NULL, (void *(*)(void *))do_delay_write, NULL,
2757c478bd9Sstevel@tonic-gate THR_NEW_LWP, NULL);
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate /*
278948f2876Sss150715 * Start RARP processing for each device.
2797c478bd9Sstevel@tonic-gate */
2807c478bd9Sstevel@tonic-gate for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
281948f2876Sss150715 if (rdev->dh_rarp != NULL) {
2827c478bd9Sstevel@tonic-gate (void) thr_create(NULL, NULL,
2837c478bd9Sstevel@tonic-gate (void *(*)(void *))do_rarp, (void *)rdev,
2847c478bd9Sstevel@tonic-gate THR_NEW_LWP, NULL);
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate * Exit main() thread
2907c478bd9Sstevel@tonic-gate */
2917c478bd9Sstevel@tonic-gate thr_exit(NULL);
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate return (0);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate static void
getintf(void)2977c478bd9Sstevel@tonic-gate getintf(void)
2987c478bd9Sstevel@tonic-gate {
2997c478bd9Sstevel@tonic-gate int fd;
3007c478bd9Sstevel@tonic-gate int numifs;
3017c478bd9Sstevel@tonic-gate unsigned bufsize;
3027c478bd9Sstevel@tonic-gate struct ifreq *reqbuf;
3037c478bd9Sstevel@tonic-gate struct ifconf ifconf;
3047c478bd9Sstevel@tonic-gate struct ifreq *ifr;
3057c478bd9Sstevel@tonic-gate struct rarpdev *rdev;
3067c478bd9Sstevel@tonic-gate struct ifdev *ifdev;
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate * Open the IP provider.
3107c478bd9Sstevel@tonic-gate */
3117c478bd9Sstevel@tonic-gate if ((fd = open(DEVIP, 0)) < 0)
3127c478bd9Sstevel@tonic-gate syserr(DEVIP);
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate /*
3157c478bd9Sstevel@tonic-gate * Ask IP for the list of configured interfaces.
3167c478bd9Sstevel@tonic-gate */
3177c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) {
3187c478bd9Sstevel@tonic-gate numifs = MAXIFS;
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate bufsize = numifs * sizeof (struct ifreq);
3217c478bd9Sstevel@tonic-gate reqbuf = (struct ifreq *)malloc(bufsize);
3227c478bd9Sstevel@tonic-gate if (reqbuf == NULL) {
3237c478bd9Sstevel@tonic-gate error("out of memory");
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate ifconf.ifc_len = bufsize;
3277c478bd9Sstevel@tonic-gate ifconf.ifc_buf = (caddr_t)reqbuf;
3287c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGIFCONF, (char *)&ifconf) < 0)
3297c478bd9Sstevel@tonic-gate syserr("SIOCGIFCONF");
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate /*
332948f2876Sss150715 * Initialize a rarpdev for each interface.
3337c478bd9Sstevel@tonic-gate */
3347c478bd9Sstevel@tonic-gate for (ifr = ifconf.ifc_req; ifconf.ifc_len > 0;
3357c478bd9Sstevel@tonic-gate ifr++, ifconf.ifc_len -= sizeof (struct ifreq)) {
3367c478bd9Sstevel@tonic-gate ifspec_t ifsp;
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGIFFLAGS, (char *)ifr) < 0) {
3397c478bd9Sstevel@tonic-gate syserr("ioctl SIOCGIFFLAGS");
3407c478bd9Sstevel@tonic-gate exit(1);
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate if ((ifr->ifr_flags & IFF_LOOPBACK) ||
3437c478bd9Sstevel@tonic-gate !(ifr->ifr_flags & IFF_UP) ||
3447c478bd9Sstevel@tonic-gate !(ifr->ifr_flags & IFF_BROADCAST) ||
3457c478bd9Sstevel@tonic-gate (ifr->ifr_flags & IFF_NOARP) ||
3467c478bd9Sstevel@tonic-gate (ifr->ifr_flags & IFF_POINTOPOINT))
3477c478bd9Sstevel@tonic-gate continue;
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate if (!ifparse_ifspec(ifr->ifr_name, &ifsp))
3507c478bd9Sstevel@tonic-gate error("ifparse_ifspec failed");
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate /*
353948f2876Sss150715 * Look for an existing device for logical interfaces.
3547c478bd9Sstevel@tonic-gate */
3557c478bd9Sstevel@tonic-gate if ((rdev = find_device(&ifsp)) == NULL) {
3567c478bd9Sstevel@tonic-gate rdev = calloc(1, sizeof (struct rarpdev));
3577c478bd9Sstevel@tonic-gate if (rdev == NULL)
3587c478bd9Sstevel@tonic-gate error("out of memory");
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate (void) strlcpy(rdev->device, ifsp.ifsp_devnm,
3617c478bd9Sstevel@tonic-gate sizeof (rdev->device));
3627c478bd9Sstevel@tonic-gate rdev->unit = ifsp.ifsp_ppa;
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate rdev->next = rarpdev_head;
3657c478bd9Sstevel@tonic-gate rarpdev_head = rdev;
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL)
3697c478bd9Sstevel@tonic-gate error("out of memory");
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate if (ifsp.ifsp_lunvalid) {
3727c478bd9Sstevel@tonic-gate (void) snprintf(ifdev->ldevice,
3737c478bd9Sstevel@tonic-gate sizeof (ifdev->ldevice), "%s%d:",
3747c478bd9Sstevel@tonic-gate ifsp.ifsp_devnm, ifsp.ifsp_ppa);
3757c478bd9Sstevel@tonic-gate ifdev->lunit = ifsp.ifsp_lun;
3767c478bd9Sstevel@tonic-gate } else
3777c478bd9Sstevel@tonic-gate ifdev->lunit = -1; /* no logical unit */
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate ifdev->next = rdev->ifdev;
3807c478bd9Sstevel@tonic-gate rdev->ifdev = ifdev;
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate (void) free((char *)reqbuf);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate static struct rarpdev *
find_device(ifspec_t * specp)3867c478bd9Sstevel@tonic-gate find_device(ifspec_t *specp)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate struct rarpdev *rdev;
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
3917c478bd9Sstevel@tonic-gate if (specp->ifsp_ppa == rdev->unit &&
3927c478bd9Sstevel@tonic-gate strcmp(specp->ifsp_devnm, rdev->device) == 0)
3937c478bd9Sstevel@tonic-gate return (rdev);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate return (NULL);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate static void
init_rarpdev(struct rarpdev * rdev)3997c478bd9Sstevel@tonic-gate init_rarpdev(struct rarpdev *rdev)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate char *dev;
4027c478bd9Sstevel@tonic-gate int unit;
4037c478bd9Sstevel@tonic-gate struct ifdev *ifdev;
404948f2876Sss150715 int retval;
405948f2876Sss150715 char *str = NULL;
406948f2876Sss150715 uint_t physaddrlen = DLPI_PHYSADDR_MAX;
407948f2876Sss150715 char linkname[DLPI_LINKNAME_MAX];
408948f2876Sss150715 dlpi_handle_t dh;
4097c478bd9Sstevel@tonic-gate
410948f2876Sss150715 (void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", rdev->device,
411948f2876Sss150715 rdev->unit);
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate * Open datalink provider and get our mac address.
4147c478bd9Sstevel@tonic-gate */
415948f2876Sss150715 if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) {
416948f2876Sss150715 error("cannot open link %s: %s", linkname,
417948f2876Sss150715 dlpi_strerror(retval));
418948f2876Sss150715 }
419948f2876Sss150715
420948f2876Sss150715 if ((retval = dlpi_bind(dh, ETHERTYPE_REVARP, NULL)) != DLPI_SUCCESS) {
421948f2876Sss150715 dlpi_close(dh);
422948f2876Sss150715 error("dlpi_bind failed: %s", dlpi_strerror(retval));
423948f2876Sss150715 }
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate /*
426948f2876Sss150715 * Save our mac address.
4277c478bd9Sstevel@tonic-gate */
428948f2876Sss150715 if ((retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, rdev->physaddr,
429948f2876Sss150715 &physaddrlen)) != DLPI_SUCCESS) {
430948f2876Sss150715 dlpi_close(dh);
431948f2876Sss150715 error("dlpi_get_physaddr failed: %s", dlpi_strerror(retval));
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
434948f2876Sss150715 rdev->physaddrlen = physaddrlen;
435948f2876Sss150715 rdev->ifrarplen = sizeof (struct arphdr) + (2 * sizeof (ipaddr_t)) +
436948f2876Sss150715 (2 * physaddrlen);
437948f2876Sss150715
438948f2876Sss150715 if (dflag) {
439948f2876Sss150715 str = _link_ntoa(rdev->physaddr, str,
440948f2876Sss150715 rdev->physaddrlen, IFT_OTHER);
441948f2876Sss150715 if (str != NULL) {
442948f2876Sss150715 debug("device %s physical address %s", linkname, str);
443948f2876Sss150715 free(str);
444948f2876Sss150715 }
445948f2876Sss150715 }
446948f2876Sss150715
447948f2876Sss150715 /*
448948f2876Sss150715 * Assign dlpi handle to rdev.
449948f2876Sss150715 */
450948f2876Sss150715 rdev->dh_rarp = dh;
451948f2876Sss150715
4527c478bd9Sstevel@tonic-gate /*
4537c478bd9Sstevel@tonic-gate * Get the IP address and netmask from directory service for
4547c478bd9Sstevel@tonic-gate * each logical interface.
4557c478bd9Sstevel@tonic-gate */
4567c478bd9Sstevel@tonic-gate for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
4577c478bd9Sstevel@tonic-gate /*
458948f2876Sss150715 * If lunit == -1 then this is the primary interface name.
4597c478bd9Sstevel@tonic-gate */
4607c478bd9Sstevel@tonic-gate if (ifdev->lunit == -1) {
4617c478bd9Sstevel@tonic-gate dev = rdev->device;
4627c478bd9Sstevel@tonic-gate unit = rdev->unit;
4637c478bd9Sstevel@tonic-gate } else {
4647c478bd9Sstevel@tonic-gate dev = ifdev->ldevice;
4657c478bd9Sstevel@tonic-gate unit = ifdev->lunit;
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate get_ifdata(dev, unit, &ifdev->if_ipaddr, &ifdev->if_netmask);
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate * Use IP address of the interface.
4717c478bd9Sstevel@tonic-gate */
4727c478bd9Sstevel@tonic-gate ifdev->if_netnum = ifdev->if_ipaddr & ifdev->if_netmask;
4737c478bd9Sstevel@tonic-gate ifdev->ipaddr = (ipaddr_t)htonl(ifdev->if_ipaddr);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate static void
do_rarp(void * buf)4787c478bd9Sstevel@tonic-gate do_rarp(void *buf)
4797c478bd9Sstevel@tonic-gate {
480948f2876Sss150715 struct rarpdev *rdev = buf;
4817c478bd9Sstevel@tonic-gate char *cause;
4827c478bd9Sstevel@tonic-gate struct arphdr *ans;
4837c478bd9Sstevel@tonic-gate uchar_t *shost;
484948f2876Sss150715 uint_t saddrlen;
485948f2876Sss150715 size_t anslen = rdev->ifrarplen;
4867c478bd9Sstevel@tonic-gate char *str = NULL;
487948f2876Sss150715 int retval;
4887c478bd9Sstevel@tonic-gate
489948f2876Sss150715 if (((shost = malloc(rdev->physaddrlen)) == NULL) ||
490948f2876Sss150715 ((ans = malloc(rdev->ifrarplen)) == NULL))
4917c478bd9Sstevel@tonic-gate syserr("malloc");
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate if (dflag) {
494948f2876Sss150715 str = _link_ntoa(rdev->physaddr, str, rdev->physaddrlen,
495948f2876Sss150715 IFT_OTHER);
4967c478bd9Sstevel@tonic-gate if (str != NULL) {
497948f2876Sss150715 debug("starting rarp service on device %s%d physical"
498948f2876Sss150715 " address %s", rdev->device, rdev->unit, str);
4997c478bd9Sstevel@tonic-gate free(str);
5007c478bd9Sstevel@tonic-gate }
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate
5037c478bd9Sstevel@tonic-gate /*
504948f2876Sss150715 * Read RARP packets and respond to them.
5057c478bd9Sstevel@tonic-gate */
5067c478bd9Sstevel@tonic-gate for (;;) {
507948f2876Sss150715 saddrlen = DLPI_PHYSADDR_MAX;
508948f2876Sss150715 retval = dlpi_recv(rdev->dh_rarp, shost,
509948f2876Sss150715 &saddrlen, ans, &anslen, -1, NULL);
510948f2876Sss150715 if (retval == DLPI_ETIMEDOUT) {
5117c478bd9Sstevel@tonic-gate continue;
512948f2876Sss150715 } else if (retval != DLPI_SUCCESS) {
513948f2876Sss150715 error("error in dlpi_recv %s: %s", rdev->dh_rarp,
514948f2876Sss150715 dlpi_strerror(retval));
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate
517948f2876Sss150715 cause = NULL;
518948f2876Sss150715
519948f2876Sss150715 if (anslen < rdev->ifrarplen)
520948f2876Sss150715 cause = "short packet";
521948f2876Sss150715 else if (ans->ar_hrd != htons(ARPHRD_ETHER))
522948f2876Sss150715 cause = "hardware type not Ethernet";
523948f2876Sss150715 else if (ans->ar_pro != htons(ETHERTYPE_IP))
524948f2876Sss150715 cause = "protocol type not IP";
525948f2876Sss150715 else if (ans->ar_hln != rdev->physaddrlen)
526948f2876Sss150715 cause = "unexpected hardware address length";
527948f2876Sss150715 else if (ans->ar_pln != sizeof (ipaddr_t))
528948f2876Sss150715 cause = "unexpected protocol address length";
529948f2876Sss150715 if (cause != NULL) {
530948f2876Sss150715 if (dflag)
531948f2876Sss150715 debug("RARP packet received but "
532948f2876Sss150715 "discarded: %s", cause);
533948f2876Sss150715 continue;
534948f2876Sss150715 }
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate /*
5377c478bd9Sstevel@tonic-gate * Handle the request.
5387c478bd9Sstevel@tonic-gate */
5397c478bd9Sstevel@tonic-gate switch (ntohs(ans->ar_op)) {
5407c478bd9Sstevel@tonic-gate case REVARP_REQUEST:
5417c478bd9Sstevel@tonic-gate rarp_request(rdev, ans, shost);
5427c478bd9Sstevel@tonic-gate break;
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate case ARPOP_REQUEST:
5457c478bd9Sstevel@tonic-gate arp_request(rdev, ans, shost);
5467c478bd9Sstevel@tonic-gate break;
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate case REVARP_REPLY:
5497c478bd9Sstevel@tonic-gate if (dflag)
5507c478bd9Sstevel@tonic-gate debug("REVARP_REPLY ignored");
5517c478bd9Sstevel@tonic-gate break;
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate case ARPOP_REPLY:
5547c478bd9Sstevel@tonic-gate if (dflag)
5557c478bd9Sstevel@tonic-gate debug("ARPOP_REPLY ignored");
5567c478bd9Sstevel@tonic-gate break;
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate default:
5597c478bd9Sstevel@tonic-gate if (dflag)
5607c478bd9Sstevel@tonic-gate debug("unknown opcode 0x%x", ans->ar_op);
5617c478bd9Sstevel@tonic-gate break;
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate /*
5677c478bd9Sstevel@tonic-gate * Reverse address determination and allocation code.
5687c478bd9Sstevel@tonic-gate */
5697c478bd9Sstevel@tonic-gate static void
rarp_request(struct rarpdev * rdev,struct arphdr * rp,uchar_t * shost)5707c478bd9Sstevel@tonic-gate rarp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost)
5717c478bd9Sstevel@tonic-gate {
5727c478bd9Sstevel@tonic-gate ipaddr_t tpa, spa;
5737c478bd9Sstevel@tonic-gate struct rarpreply *rrp;
5747c478bd9Sstevel@tonic-gate uchar_t *shap, *thap, *spap, *tpap;
5757c478bd9Sstevel@tonic-gate char *str = NULL;
576948f2876Sss150715 int retval;
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate shap = (uchar_t *)rp + sizeof (struct arphdr);
5797c478bd9Sstevel@tonic-gate spap = shap + rp->ar_hln;
5807c478bd9Sstevel@tonic-gate thap = spap + rp->ar_pln;
5817c478bd9Sstevel@tonic-gate tpap = thap + rp->ar_hln;
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate if (dflag) {
584948f2876Sss150715 str = _link_ntoa(thap, str, rdev->physaddrlen, IFT_OTHER);
5857c478bd9Sstevel@tonic-gate if (str != NULL) {
5867c478bd9Sstevel@tonic-gate debug("RARP_REQUEST for %s", str);
5877c478bd9Sstevel@tonic-gate free(str);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate }
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate /*
592948f2876Sss150715 * Third party lookups are rare and wonderful.
5937c478bd9Sstevel@tonic-gate */
594948f2876Sss150715 if ((memcmp(shap, thap, rdev->physaddrlen) != 0) ||
595948f2876Sss150715 (memcmp(shap, shost, rdev->physaddrlen) != 0)) {
5967c478bd9Sstevel@tonic-gate if (dflag)
5977c478bd9Sstevel@tonic-gate debug("weird (3rd party lookup)");
5987c478bd9Sstevel@tonic-gate }
5997c478bd9Sstevel@tonic-gate
6007c478bd9Sstevel@tonic-gate /*
601948f2876Sss150715 * Fill in given parts of reply packet.
6027c478bd9Sstevel@tonic-gate */
603948f2876Sss150715 (void) memcpy(shap, rdev->physaddr, rdev->physaddrlen);
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate /*
6067c478bd9Sstevel@tonic-gate * If a good address is stored in our lookup tables, return it
607948f2876Sss150715 * immediately or after a delay. Store it in our kernel's ARP cache.
6087c478bd9Sstevel@tonic-gate */
6097c478bd9Sstevel@tonic-gate if (get_ipaddr(rdev, thap, tpap, &spa))
6107c478bd9Sstevel@tonic-gate return;
6117c478bd9Sstevel@tonic-gate (void) memcpy(spap, &spa, sizeof (spa));
6127c478bd9Sstevel@tonic-gate
6137c478bd9Sstevel@tonic-gate add_arp(rdev, tpap, thap);
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate rp->ar_op = htons(REVARP_REPLY);
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate if (dflag) {
6187c478bd9Sstevel@tonic-gate struct in_addr addr;
6197c478bd9Sstevel@tonic-gate
6207c478bd9Sstevel@tonic-gate (void) memcpy(&addr, tpap, sizeof (ipaddr_t));
6217c478bd9Sstevel@tonic-gate debug("good lookup, maps to %s", inet_ntoa(addr));
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate
624948f2876Sss150715 rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen +
625948f2876Sss150715 rdev->ifrarplen);
6267c478bd9Sstevel@tonic-gate if (rrp == NULL)
6277c478bd9Sstevel@tonic-gate error("out of memory");
6287c478bd9Sstevel@tonic-gate rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply);
629948f2876Sss150715 rrp->arprep = rrp->lldest + rdev->physaddrlen;
6307c478bd9Sstevel@tonic-gate
6317c478bd9Sstevel@tonic-gate /*
6327c478bd9Sstevel@tonic-gate * Create rarpreply structure.
6337c478bd9Sstevel@tonic-gate */
6347c478bd9Sstevel@tonic-gate (void) gettimeofday(&rrp->tv, NULL);
6357c478bd9Sstevel@tonic-gate rrp->tv.tv_sec += 3; /* delay */
6367c478bd9Sstevel@tonic-gate rrp->rdev = rdev;
637948f2876Sss150715 (void) memcpy(rrp->lldest, shost, rdev->physaddrlen);
6387c478bd9Sstevel@tonic-gate (void) memcpy(rrp->arprep, rp, rdev->ifrarplen);
6397c478bd9Sstevel@tonic-gate
6407c478bd9Sstevel@tonic-gate /*
6417c478bd9Sstevel@tonic-gate * If this is diskless and we're not its bootserver, let the
6427c478bd9Sstevel@tonic-gate * bootserver reply first by delaying a while.
6437c478bd9Sstevel@tonic-gate */
6447c478bd9Sstevel@tonic-gate (void) memcpy(&tpa, tpap, sizeof (ipaddr_t));
6457c478bd9Sstevel@tonic-gate if (mightboot(ntohl(tpa))) {
646948f2876Sss150715 retval = dlpi_send(rdev->dh_rarp, rrp->lldest,
647948f2876Sss150715 rdev->physaddrlen, rrp->arprep, rdev->ifrarplen, NULL);
648948f2876Sss150715 if (retval != DLPI_SUCCESS) {
649948f2876Sss150715 error("dlpi_send failed: %s", dlpi_strerror(retval));
650948f2876Sss150715 } else if (dflag) {
6517c478bd9Sstevel@tonic-gate debug("immediate reply sent");
652948f2876Sss150715 }
6537c478bd9Sstevel@tonic-gate (void) free(rrp);
6547c478bd9Sstevel@tonic-gate } else {
6557c478bd9Sstevel@tonic-gate delay_write(rdev, rrp);
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate }
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate /*
6607c478bd9Sstevel@tonic-gate * Download an ARP entry into our kernel.
6617c478bd9Sstevel@tonic-gate */
6627c478bd9Sstevel@tonic-gate static void
add_arp(struct rarpdev * rdev,uchar_t * ip,uchar_t * laddr)6637c478bd9Sstevel@tonic-gate add_arp(struct rarpdev *rdev, uchar_t *ip, uchar_t *laddr)
6647c478bd9Sstevel@tonic-gate {
6657c478bd9Sstevel@tonic-gate struct xarpreq ar;
6667c478bd9Sstevel@tonic-gate struct sockaddr_in *sin;
6677c478bd9Sstevel@tonic-gate int fd;
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate /*
670948f2876Sss150715 * Common part of query or set.
6717c478bd9Sstevel@tonic-gate */
6727c478bd9Sstevel@tonic-gate (void) memset(&ar, 0, sizeof (ar));
6737c478bd9Sstevel@tonic-gate ar.xarp_pa.ss_family = AF_INET;
6747c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ar.xarp_pa;
6757c478bd9Sstevel@tonic-gate (void) memcpy(&sin->sin_addr, ip, sizeof (ipaddr_t));
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate /*
6787c478bd9Sstevel@tonic-gate * Open the IP provider.
6797c478bd9Sstevel@tonic-gate */
6807c478bd9Sstevel@tonic-gate if ((fd = open(DEVARP, 0)) < 0)
6817c478bd9Sstevel@tonic-gate syserr(DEVARP);
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate /*
684948f2876Sss150715 * Set the entry.
6857c478bd9Sstevel@tonic-gate */
686948f2876Sss150715 (void) memcpy(LLADDR(&ar.xarp_ha), laddr, rdev->physaddrlen);
687948f2876Sss150715 ar.xarp_ha.sdl_alen = rdev->physaddrlen;
6887c478bd9Sstevel@tonic-gate ar.xarp_ha.sdl_family = AF_LINK;
6897c478bd9Sstevel@tonic-gate (void) strioctl(fd, SIOCDXARP, -1, sizeof (struct xarpreq),
6907c478bd9Sstevel@tonic-gate (char *)&ar);
6917c478bd9Sstevel@tonic-gate if (strioctl(fd, SIOCSXARP, -1, sizeof (struct xarpreq),
6927c478bd9Sstevel@tonic-gate (char *)&ar) < 0)
6937c478bd9Sstevel@tonic-gate syserr("SIOCSXARP");
6947c478bd9Sstevel@tonic-gate
6957c478bd9Sstevel@tonic-gate (void) close(fd);
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate
6987c478bd9Sstevel@tonic-gate /*
6997c478bd9Sstevel@tonic-gate * The RARP spec says we must be able to process ARP requests,
7007c478bd9Sstevel@tonic-gate * even through the packet type is RARP. Let's hope this feature
7017c478bd9Sstevel@tonic-gate * is not heavily used.
7027c478bd9Sstevel@tonic-gate */
7037c478bd9Sstevel@tonic-gate static void
arp_request(struct rarpdev * rdev,struct arphdr * rp,uchar_t * shost)7047c478bd9Sstevel@tonic-gate arp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost)
7057c478bd9Sstevel@tonic-gate {
7067c478bd9Sstevel@tonic-gate struct rarpreply *rrp;
7077c478bd9Sstevel@tonic-gate struct ifdev *ifdev;
7087c478bd9Sstevel@tonic-gate uchar_t *shap, *thap, *spap, *tpap;
709948f2876Sss150715 int retval;
7107c478bd9Sstevel@tonic-gate
7117c478bd9Sstevel@tonic-gate shap = (uchar_t *)rp + sizeof (struct arphdr);
7127c478bd9Sstevel@tonic-gate spap = shap + rp->ar_hln;
7137c478bd9Sstevel@tonic-gate thap = spap + rp->ar_pln;
7147c478bd9Sstevel@tonic-gate tpap = thap + rp->ar_hln;
7157c478bd9Sstevel@tonic-gate
7167c478bd9Sstevel@tonic-gate if (dflag)
7177c478bd9Sstevel@tonic-gate debug("ARPOP_REQUEST");
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
7207c478bd9Sstevel@tonic-gate if (memcmp(&ifdev->ipaddr, tpap, sizeof (ipaddr_t)) == 0)
7217c478bd9Sstevel@tonic-gate break;
7227c478bd9Sstevel@tonic-gate }
7237c478bd9Sstevel@tonic-gate if (ifdev == NULL)
7247c478bd9Sstevel@tonic-gate return;
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate rp->ar_op = ARPOP_REPLY;
727948f2876Sss150715 (void) memcpy(shap, rdev->physaddr, rdev->physaddrlen);
7287c478bd9Sstevel@tonic-gate (void) memcpy(spap, &ifdev->ipaddr, sizeof (ipaddr_t));
729948f2876Sss150715 (void) memcpy(thap, rdev->physaddr, rdev->physaddrlen);
7307c478bd9Sstevel@tonic-gate
7317c478bd9Sstevel@tonic-gate add_arp(rdev, tpap, thap);
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate /*
7347c478bd9Sstevel@tonic-gate * Create rarp reply structure.
7357c478bd9Sstevel@tonic-gate */
736948f2876Sss150715 rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen +
737948f2876Sss150715 rdev->ifrarplen);
7387c478bd9Sstevel@tonic-gate if (rrp == NULL)
7397c478bd9Sstevel@tonic-gate error("out of memory");
7407c478bd9Sstevel@tonic-gate rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply);
741948f2876Sss150715 rrp->arprep = rrp->lldest + rdev->physaddrlen;
7427c478bd9Sstevel@tonic-gate rrp->rdev = rdev;
7437c478bd9Sstevel@tonic-gate
744948f2876Sss150715 (void) memcpy(rrp->lldest, shost, rdev->physaddrlen);
7457c478bd9Sstevel@tonic-gate (void) memcpy(rrp->arprep, rp, rdev->ifrarplen);
7467c478bd9Sstevel@tonic-gate
747948f2876Sss150715 retval = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen,
748948f2876Sss150715 rrp->arprep, rdev->ifrarplen, NULL);
7497c478bd9Sstevel@tonic-gate free(rrp);
750948f2876Sss150715 if (retval != DLPI_SUCCESS)
751948f2876Sss150715 error("dlpi_send failed: %s", dlpi_strerror(retval));
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate /* ARGSUSED */
7557c478bd9Sstevel@tonic-gate static void
do_delay_write(void * buf)7567c478bd9Sstevel@tonic-gate do_delay_write(void *buf)
7577c478bd9Sstevel@tonic-gate {
7587c478bd9Sstevel@tonic-gate struct timeval tv;
7597c478bd9Sstevel@tonic-gate struct rarpreply *rrp;
760948f2876Sss150715 struct rarpdev *rdev;
7617c478bd9Sstevel@tonic-gate int err;
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate for (;;) {
7647c478bd9Sstevel@tonic-gate if ((err = sema_wait(&delay_sema)) != 0) {
7657c478bd9Sstevel@tonic-gate if (err == EINTR)
7667c478bd9Sstevel@tonic-gate continue;
7677c478bd9Sstevel@tonic-gate error("do_delay_write: sema_wait failed");
7687c478bd9Sstevel@tonic-gate }
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate (void) mutex_lock(&delay_mutex);
7717c478bd9Sstevel@tonic-gate rrp = delay_list;
772948f2876Sss150715 rdev = rrp->rdev;
7737c478bd9Sstevel@tonic-gate delay_list = delay_list->next;
7747c478bd9Sstevel@tonic-gate (void) mutex_unlock(&delay_mutex);
7757c478bd9Sstevel@tonic-gate
7767c478bd9Sstevel@tonic-gate (void) gettimeofday(&tv, NULL);
7777c478bd9Sstevel@tonic-gate if (tv.tv_sec < rrp->tv.tv_sec)
7787c478bd9Sstevel@tonic-gate (void) sleep(rrp->tv.tv_sec - tv.tv_sec);
7797c478bd9Sstevel@tonic-gate
780948f2876Sss150715 err = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen,
781948f2876Sss150715 rrp->arprep, rdev->ifrarplen, NULL);
782948f2876Sss150715 if (err != DLPI_SUCCESS)
783948f2876Sss150715 error("dlpi_send failed: %s", dlpi_strerror(err));
7847c478bd9Sstevel@tonic-gate
7857c478bd9Sstevel@tonic-gate (void) free(rrp);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate
7897c478bd9Sstevel@tonic-gate /* ARGSUSED */
7907c478bd9Sstevel@tonic-gate static void
delay_write(struct rarpdev * rdev,struct rarpreply * rrp)7917c478bd9Sstevel@tonic-gate delay_write(struct rarpdev *rdev, struct rarpreply *rrp)
7927c478bd9Sstevel@tonic-gate {
7937c478bd9Sstevel@tonic-gate struct rarpreply *trp;
7947c478bd9Sstevel@tonic-gate
7957c478bd9Sstevel@tonic-gate (void) mutex_lock(&delay_mutex);
7967c478bd9Sstevel@tonic-gate if (delay_list == NULL) {
7977c478bd9Sstevel@tonic-gate delay_list = rrp;
7987c478bd9Sstevel@tonic-gate } else {
7997c478bd9Sstevel@tonic-gate trp = delay_list;
8007c478bd9Sstevel@tonic-gate while (trp->next != NULL)
8017c478bd9Sstevel@tonic-gate trp = trp->next;
8027c478bd9Sstevel@tonic-gate trp->next = rrp;
8037c478bd9Sstevel@tonic-gate }
8047c478bd9Sstevel@tonic-gate (void) mutex_unlock(&delay_mutex);
8057c478bd9Sstevel@tonic-gate
8067c478bd9Sstevel@tonic-gate (void) sema_post(&delay_sema);
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate /*
8107c478bd9Sstevel@tonic-gate * See if we have a TFTP boot file for this guy. Filenames in TFTP
8117c478bd9Sstevel@tonic-gate * boot requests are of the form <ipaddr> for Sun-3's and of the form
8127c478bd9Sstevel@tonic-gate * <ipaddr>.<arch> for all other architectures. Since we don't know
8137c478bd9Sstevel@tonic-gate * the client's architecture, either format will do.
8147c478bd9Sstevel@tonic-gate */
8157c478bd9Sstevel@tonic-gate static int
mightboot(ipaddr_t ipa)8167c478bd9Sstevel@tonic-gate mightboot(ipaddr_t ipa)
8177c478bd9Sstevel@tonic-gate {
8187c478bd9Sstevel@tonic-gate char path[MAXPATHL];
8197c478bd9Sstevel@tonic-gate DIR *dirp;
8207c478bd9Sstevel@tonic-gate struct dirent *dp;
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/%08X", BOOTDIR, ipa);
8237c478bd9Sstevel@tonic-gate
8247c478bd9Sstevel@tonic-gate /*
8257c478bd9Sstevel@tonic-gate * Try a quick access() first.
8267c478bd9Sstevel@tonic-gate */
8277c478bd9Sstevel@tonic-gate if (access(path, 0) == 0)
8287c478bd9Sstevel@tonic-gate return (1);
8297c478bd9Sstevel@tonic-gate
8307c478bd9Sstevel@tonic-gate /*
8317c478bd9Sstevel@tonic-gate * Not there, do it the slow way by
8327c478bd9Sstevel@tonic-gate * reading through the directory.
8337c478bd9Sstevel@tonic-gate */
8347c478bd9Sstevel@tonic-gate (void) sprintf(path, "%08X", ipa);
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate if (!(dirp = opendir(BOOTDIR)))
8377c478bd9Sstevel@tonic-gate return (0);
8387c478bd9Sstevel@tonic-gate
8394bc0a2efScasper while ((dp = readdir(dirp)) != NULL) {
8407c478bd9Sstevel@tonic-gate if (strncmp(dp->d_name, path, 8) != 0)
8417c478bd9Sstevel@tonic-gate continue;
8427c478bd9Sstevel@tonic-gate if ((strlen(dp->d_name) != 8) && (dp->d_name[8] != '.'))
8437c478bd9Sstevel@tonic-gate continue;
8447c478bd9Sstevel@tonic-gate break;
8457c478bd9Sstevel@tonic-gate }
8467c478bd9Sstevel@tonic-gate
8477c478bd9Sstevel@tonic-gate (void) closedir(dirp);
8487c478bd9Sstevel@tonic-gate
849948f2876Sss150715 return ((dp != NULL) ? 1 : 0);
8507c478bd9Sstevel@tonic-gate }
8517c478bd9Sstevel@tonic-gate
8527c478bd9Sstevel@tonic-gate /*
8537c478bd9Sstevel@tonic-gate * Get our IP address and local netmask.
8547c478bd9Sstevel@tonic-gate */
8557c478bd9Sstevel@tonic-gate static void
get_ifdata(char * dev,int unit,ipaddr_t * ipp,ipaddr_t * maskp)8567c478bd9Sstevel@tonic-gate get_ifdata(char *dev, int unit, ipaddr_t *ipp, ipaddr_t *maskp)
8577c478bd9Sstevel@tonic-gate {
8587c478bd9Sstevel@tonic-gate int fd;
8597c478bd9Sstevel@tonic-gate struct ifreq ifr;
8607c478bd9Sstevel@tonic-gate struct sockaddr_in *sin;
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate /* LINTED pointer */
8637c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr.ifr_addr;
8647c478bd9Sstevel@tonic-gate
8657c478bd9Sstevel@tonic-gate /*
8667c478bd9Sstevel@tonic-gate * Open the IP provider.
8677c478bd9Sstevel@tonic-gate */
8687c478bd9Sstevel@tonic-gate if ((fd = open(DEVIP, 0)) < 0)
8697c478bd9Sstevel@tonic-gate syserr(DEVIP);
8707c478bd9Sstevel@tonic-gate
8717c478bd9Sstevel@tonic-gate /*
8727c478bd9Sstevel@tonic-gate * Ask IP for our IP address.
8737c478bd9Sstevel@tonic-gate */
8747c478bd9Sstevel@tonic-gate (void) snprintf(ifr.ifr_name, sizeof (ifr.ifr_name), "%s%d", dev, unit);
8757c478bd9Sstevel@tonic-gate if (strioctl(fd, SIOCGIFADDR, -1, sizeof (struct ifreq),
8767c478bd9Sstevel@tonic-gate (char *)&ifr) < 0)
8777c478bd9Sstevel@tonic-gate syserr("SIOCGIFADDR");
8787c478bd9Sstevel@tonic-gate *ipp = (ipaddr_t)ntohl(sin->sin_addr.s_addr);
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate if (dflag)
881948f2876Sss150715 debug("device %s%d address %s", dev, unit,
882948f2876Sss150715 inet_ntoa(sin->sin_addr));
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate * Ask IP for our netmask.
8867c478bd9Sstevel@tonic-gate */
8877c478bd9Sstevel@tonic-gate if (strioctl(fd, SIOCGIFNETMASK, -1, sizeof (struct ifreq),
8887c478bd9Sstevel@tonic-gate (char *)&ifr) < 0)
8897c478bd9Sstevel@tonic-gate syserr("SIOCGIFNETMASK");
8907c478bd9Sstevel@tonic-gate *maskp = (ipaddr_t)ntohl(sin->sin_addr.s_addr);
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate if (dflag)
893948f2876Sss150715 debug("device %s%d subnet mask %s", dev, unit,
894948f2876Sss150715 inet_ntoa(sin->sin_addr));
8957c478bd9Sstevel@tonic-gate
8967c478bd9Sstevel@tonic-gate /*
8977c478bd9Sstevel@tonic-gate * Thankyou ip.
8987c478bd9Sstevel@tonic-gate */
8997c478bd9Sstevel@tonic-gate (void) close(fd);
9007c478bd9Sstevel@tonic-gate }
9017c478bd9Sstevel@tonic-gate
9027c478bd9Sstevel@tonic-gate /*
9037c478bd9Sstevel@tonic-gate * Translate mac address to IP address.
9047c478bd9Sstevel@tonic-gate * Return 0 on success, nonzero on failure.
9057c478bd9Sstevel@tonic-gate */
9067c478bd9Sstevel@tonic-gate static int
get_ipaddr(struct rarpdev * rdev,uchar_t * laddr,uchar_t * ipp,ipaddr_t * ipaddr)9077c478bd9Sstevel@tonic-gate get_ipaddr(struct rarpdev *rdev, uchar_t *laddr, uchar_t *ipp, ipaddr_t *ipaddr)
9087c478bd9Sstevel@tonic-gate {
9097c478bd9Sstevel@tonic-gate char host[MAXHOSTL];
9107c478bd9Sstevel@tonic-gate char hbuffer[BUFSIZE];
9117c478bd9Sstevel@tonic-gate struct hostent *hp, res;
9127c478bd9Sstevel@tonic-gate int herror;
9137c478bd9Sstevel@tonic-gate struct in_addr addr;
9147c478bd9Sstevel@tonic-gate char **p;
9157c478bd9Sstevel@tonic-gate struct ifdev *ifdev;
9167c478bd9Sstevel@tonic-gate
917948f2876Sss150715 if (rdev->physaddrlen != ETHERADDRL) {
9187c478bd9Sstevel@tonic-gate if (dflag)
9197c478bd9Sstevel@tonic-gate debug("%s %s", " cannot map non 6 byte hardware ",
9207c478bd9Sstevel@tonic-gate "address to IP address");
9217c478bd9Sstevel@tonic-gate return (1);
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate /*
925948f2876Sss150715 * Translate mac address to hostname and IP address.
9267c478bd9Sstevel@tonic-gate */
9277c478bd9Sstevel@tonic-gate if (ether_ntohost(host, (struct ether_addr *)laddr) != 0 ||
9287c478bd9Sstevel@tonic-gate !(hp = gethostbyname_r(host, &res, hbuffer, sizeof (hbuffer),
9297c478bd9Sstevel@tonic-gate &herror)) ||
9307c478bd9Sstevel@tonic-gate hp->h_addrtype != AF_INET || hp->h_length != sizeof (ipaddr_t)) {
9317c478bd9Sstevel@tonic-gate if (dflag)
9327c478bd9Sstevel@tonic-gate debug("could not map hardware address to IP address");
9337c478bd9Sstevel@tonic-gate return (1);
9347c478bd9Sstevel@tonic-gate }
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate /*
9377c478bd9Sstevel@tonic-gate * Find the IP address on the right net.
9387c478bd9Sstevel@tonic-gate */
9397c478bd9Sstevel@tonic-gate for (p = hp->h_addr_list; *p; p++) {
9407c478bd9Sstevel@tonic-gate (void) memcpy(&addr, *p, sizeof (ipaddr_t));
9417c478bd9Sstevel@tonic-gate for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
9427c478bd9Sstevel@tonic-gate if (dflag) {
9437c478bd9Sstevel@tonic-gate struct in_addr daddr;
9447c478bd9Sstevel@tonic-gate ipaddr_t netnum;
9457c478bd9Sstevel@tonic-gate
9467c478bd9Sstevel@tonic-gate netnum = htonl(ifdev->if_netnum);
9477c478bd9Sstevel@tonic-gate (void) memcpy(&daddr, &netnum,
9487c478bd9Sstevel@tonic-gate sizeof (ipaddr_t));
9497c478bd9Sstevel@tonic-gate if (ifdev->lunit == -1)
950948f2876Sss150715 debug("trying physical netnum %s"
951948f2876Sss150715 " mask %x", inet_ntoa(daddr),
9527c478bd9Sstevel@tonic-gate ifdev->if_netmask);
9537c478bd9Sstevel@tonic-gate else
954948f2876Sss150715 debug("trying logical %d netnum %s"
955948f2876Sss150715 " mask %x", ifdev->lunit,
9567c478bd9Sstevel@tonic-gate inet_ntoa(daddr),
9577c478bd9Sstevel@tonic-gate ifdev->if_netmask);
9587c478bd9Sstevel@tonic-gate }
9597c478bd9Sstevel@tonic-gate if ((ntohl(addr.s_addr) & ifdev->if_netmask) ==
9607c478bd9Sstevel@tonic-gate ifdev->if_netnum) {
9617c478bd9Sstevel@tonic-gate /*
9627c478bd9Sstevel@tonic-gate * Return the correct IP address.
9637c478bd9Sstevel@tonic-gate */
9647c478bd9Sstevel@tonic-gate (void) memcpy(ipp, &addr, sizeof (ipaddr_t));
9657c478bd9Sstevel@tonic-gate
9667c478bd9Sstevel@tonic-gate /*
9677c478bd9Sstevel@tonic-gate * Return the interface's ipaddr
9687c478bd9Sstevel@tonic-gate */
9697c478bd9Sstevel@tonic-gate (void) memcpy(ipaddr, &ifdev->ipaddr,
9707c478bd9Sstevel@tonic-gate sizeof (ipaddr_t));
9717c478bd9Sstevel@tonic-gate
9727c478bd9Sstevel@tonic-gate return (0);
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate }
9757c478bd9Sstevel@tonic-gate }
9767c478bd9Sstevel@tonic-gate
9777c478bd9Sstevel@tonic-gate if (dflag)
9787c478bd9Sstevel@tonic-gate debug("got host entry but no IP address on this net");
9797c478bd9Sstevel@tonic-gate return (1);
9807c478bd9Sstevel@tonic-gate }
9817c478bd9Sstevel@tonic-gate
9827c478bd9Sstevel@tonic-gate static int
strioctl(int fd,int cmd,int timout,int len,char * dp)9837c478bd9Sstevel@tonic-gate strioctl(int fd, int cmd, int timout, int len, char *dp)
9847c478bd9Sstevel@tonic-gate {
9857c478bd9Sstevel@tonic-gate struct strioctl si;
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate si.ic_cmd = cmd;
9887c478bd9Sstevel@tonic-gate si.ic_timout = timout;
9897c478bd9Sstevel@tonic-gate si.ic_len = len;
9907c478bd9Sstevel@tonic-gate si.ic_dp = dp;
9917c478bd9Sstevel@tonic-gate return (ioctl(fd, I_STR, &si));
9927c478bd9Sstevel@tonic-gate }
9937c478bd9Sstevel@tonic-gate
9947c478bd9Sstevel@tonic-gate static void
usage(void)995948f2876Sss150715 usage(void)
9967c478bd9Sstevel@tonic-gate {
9977c478bd9Sstevel@tonic-gate error("Usage: %s [ -ad ] device unit", cmdname);
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate
10007c478bd9Sstevel@tonic-gate static void
syserr(const char * s)1001948f2876Sss150715 syserr(const char *s)
10027c478bd9Sstevel@tonic-gate {
10037c478bd9Sstevel@tonic-gate char buf[256];
10047c478bd9Sstevel@tonic-gate int status = 1;
10057c478bd9Sstevel@tonic-gate
10067c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s: %s", s, strerror(errno));
10077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", cmdname, buf);
10087c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s", buf);
10097c478bd9Sstevel@tonic-gate thr_exit(&status);
10107c478bd9Sstevel@tonic-gate }
10117c478bd9Sstevel@tonic-gate
10127c478bd9Sstevel@tonic-gate static void
error(const char * fmt,...)1013948f2876Sss150715 error(const char *fmt, ...)
10147c478bd9Sstevel@tonic-gate {
10157c478bd9Sstevel@tonic-gate char buf[256];
10167c478bd9Sstevel@tonic-gate va_list ap;
10177c478bd9Sstevel@tonic-gate int status = 1;
10187c478bd9Sstevel@tonic-gate
10197c478bd9Sstevel@tonic-gate va_start(ap, fmt);
10207c478bd9Sstevel@tonic-gate (void) vsprintf(buf, fmt, ap);
10217c478bd9Sstevel@tonic-gate va_end(ap);
10227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", cmdname, buf);
10237c478bd9Sstevel@tonic-gate syslog(LOG_ERR, buf);
10247c478bd9Sstevel@tonic-gate thr_exit(&status);
10257c478bd9Sstevel@tonic-gate }
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
10287c478bd9Sstevel@tonic-gate static void
debug(char * fmt,...)10297c478bd9Sstevel@tonic-gate debug(char *fmt, ...)
10307c478bd9Sstevel@tonic-gate {
10317c478bd9Sstevel@tonic-gate va_list ap;
10327c478bd9Sstevel@tonic-gate
10337c478bd9Sstevel@tonic-gate (void) mutex_lock(&debug_mutex);
10347c478bd9Sstevel@tonic-gate va_start(ap, fmt);
10357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s:[%u] ", cmdname, thr_self());
10367c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap);
10377c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n");
10387c478bd9Sstevel@tonic-gate va_end(ap);
10397c478bd9Sstevel@tonic-gate (void) mutex_unlock(&debug_mutex);
10407c478bd9Sstevel@tonic-gate }
1041