xref: /titanic_44/usr/src/cmd/cmd-inet/usr.sbin/in.rarpd.c (revision b509e89b2befbaa42939abad9da1d7f5a8c6aaae)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
26 /*	  All Rights Reserved  	*/
27 
28 /*
29  * Portions of this source code were derived from Berkeley 4.3 BSD
30  * under license from the Regents of the University of California.
31  */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 /*
36  * rarpd.c  Reverse-ARP server.
37  * Refer to RFC 903 "A Reverse Address Resolution Protocol".
38  */
39 
40 #define	_REENTRANT
41 
42 #include	<thread.h>
43 #include	<synch.h>
44 #include	<stdlib.h>
45 #include	<unistd.h>
46 #include	<sys/resource.h>
47 #include	<stdio.h>
48 #include	<stdio_ext.h>
49 #include	<stdarg.h>
50 #include	<string.h>
51 #include	<fcntl.h>
52 #include	<sys/types.h>
53 #include	<dirent.h>
54 #include	<syslog.h>
55 #include	<netdb.h>
56 #include	<errno.h>
57 #include	<sys/socket.h>
58 #include	<sys/sockio.h>
59 #include	<net/if.h>
60 #include	<netinet/if_ether.h>
61 #include	<netinet/in.h>
62 #include	<arpa/inet.h>
63 #include	<stropts.h>
64 #include	<libinetutil.h>
65 #include	<libdlpi.h>
66 #include	<net/if_types.h>
67 #include	<net/if_dl.h>
68 
69 #define	BOOTDIR		"/tftpboot"	/* boot files directory */
70 #define	DEVIP		"/dev/ip"	/* path to ip driver */
71 #define	DEVARP		"/dev/arp"	/* path to arp driver */
72 
73 #define	BUFSIZE		2048		/* max receive frame length */
74 #define	MAXPATHL	128		/* max path length */
75 #define	MAXHOSTL	128		/* max host name length */
76 #define	MAXIFS		256
77 
78 /*
79  * Logical network devices
80  */
81 struct	ifdev {
82 	char		ldevice[IFNAMSIZ];
83 	int		lunit;
84 	ipaddr_t	ipaddr;			/* network order */
85 	ipaddr_t	if_netmask;		/* host order */
86 	ipaddr_t	if_ipaddr;		/* host order */
87 	ipaddr_t	if_netnum;		/* host order, with subnet */
88 	struct ifdev *next;
89 };
90 
91 /*
92  * Physical network device
93  */
94 struct	rarpdev {
95 	char		device[DLPI_LINKNAME_MAX];
96 	uint_t		unit;
97 	dlpi_handle_t	dh_rarp;
98 	uchar_t		physaddr[DLPI_PHYSADDR_MAX];
99 						/* mac address of interface */
100 	uint_t		physaddrlen;		/* mac address length */
101 	int		ifrarplen;		/* size of rarp data packet */
102 	struct ifdev	*ifdev;			/* private interface info */
103 	struct rarpdev	*next;			/* list of managed devices */
104 };
105 
106 struct	rarpreply {
107 	struct rarpdev		*rdev;		/* which device reply for */
108 	struct timeval		tv;		/* send RARP reply by when */
109 	uchar_t			*lldest;	/* target mac to send reply */
110 	uchar_t			*arprep;	/* [R]ARP response */
111 	struct rarpreply	*next;
112 };
113 
114 static struct rarpreply	*delay_list;
115 static sema_t		delay_sema;
116 static mutex_t		delay_mutex;
117 static mutex_t		debug_mutex;
118 
119 static struct rarpdev	*rarpdev_head;
120 
121 /*
122  * Globals initialized before multi-threading
123  */
124 static char	*cmdname;		/* command name from argv[0] */
125 static int	dflag = 0;		/* enable diagnostics */
126 static int	aflag = 0;		/* start rarpd on all interfaces */
127 
128 static void	getintf(void);
129 static struct rarpdev *find_device(ifspec_t *);
130 static void	init_rarpdev(struct rarpdev *);
131 static void	do_rarp(void *);
132 static void	rarp_request(struct rarpdev *, struct arphdr *,
133 		    uchar_t *);
134 static void	add_arp(struct rarpdev *, uchar_t *, uchar_t *);
135 static void	arp_request(struct rarpdev *, struct arphdr *, uchar_t *);
136 static void	do_delay_write(void *);
137 static void	delay_write(struct rarpdev *, struct rarpreply *);
138 static int	mightboot(ipaddr_t);
139 static void	get_ifdata(char *, int, ipaddr_t *, ipaddr_t *);
140 static int	get_ipaddr(struct rarpdev *, uchar_t *, uchar_t *, ipaddr_t *);
141 static int	strioctl(int, int, int, int, char *);
142 static void	usage();
143 static void	syserr(const char *);
144 /*PRINTFLIKE1*/
145 static void	error(const char *, ...);
146 static void	debug(char *, ...);
147 
148 extern	int	optind;
149 extern	char	*optarg;
150 
151 int
152 main(int argc, char *argv[])
153 {
154 	int		c;
155 	struct rlimit rl;
156 	struct rarpdev	*rdev;
157 	int		i;
158 
159 	cmdname = argv[0];
160 
161 	while ((c = getopt(argc, argv, "ad")) != -1) {
162 		switch (c) {
163 		case 'a':
164 			aflag = 1;
165 			break;
166 
167 		case 'd':
168 			dflag = 1;
169 			break;
170 
171 		default:
172 			usage();
173 		}
174 	}
175 
176 	if ((!aflag && (argc - optind) != 2) ||
177 	    (aflag && (argc - optind) != 0)) {
178 		usage();
179 		/* NOTREACHED */
180 	}
181 
182 	if (!dflag) {
183 		/*
184 		 * Background
185 		 */
186 		switch (fork()) {
187 			case -1:	/* error */
188 				syserr("fork");
189 				/*NOTREACHED*/
190 
191 			case 0:		/* child */
192 				break;
193 
194 			default:	/* parent */
195 				return (0);
196 		}
197 		for (i = 0; i < 3; i++) {
198 			(void) close(i);
199 		}
200 		(void) open("/", O_RDONLY, 0);
201 		(void) dup2(0, 1);
202 		(void) dup2(0, 2);
203 		/*
204 		 * Detach terminal
205 		 */
206 		if (setsid() < 0)
207 			syserr("setsid");
208 	}
209 
210 	rl.rlim_cur = RLIM_INFINITY;
211 	rl.rlim_max = RLIM_INFINITY;
212 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
213 		syserr("setrlimit");
214 	(void) enable_extended_FILE_stdio(-1, -1);
215 
216 	(void) openlog(cmdname, LOG_PID, LOG_DAEMON);
217 
218 	if (aflag) {
219 		/*
220 		 * Get each interface name and load rarpdev list.
221 		 */
222 		getintf();
223 	} else {
224 		ifspec_t	ifsp;
225 		struct ifdev	*ifdev;
226 		char		buf[IFNAMSIZ + 1];
227 
228 		/*
229 		 * Load specified device as only element of the list.
230 		 */
231 		rarpdev_head = (struct rarpdev *)calloc(1,
232 		    sizeof (struct rarpdev));
233 		if (rarpdev_head == NULL) {
234 			error("out of memory");
235 		}
236 		(void) strncpy(buf, argv[optind], IFNAMSIZ);
237 		(void) strncat(buf, argv[optind + 1], IFNAMSIZ - strlen(buf));
238 
239 		if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL) {
240 			error("out of memory");
241 		}
242 
243 		if (!ifparse_ifspec(buf, &ifsp) || ifsp.ifsp_modcnt != 0) {
244 			error("invalid interface specification");
245 		}
246 
247 		if (ifsp.ifsp_lunvalid) {
248 			(void) snprintf(ifdev->ldevice,
249 			    sizeof (ifdev->ldevice), "%s%d:",
250 			    ifsp.ifsp_devnm, ifsp.ifsp_ppa);
251 			ifdev->lunit = ifsp.ifsp_lun;
252 		} else {
253 			ifdev->lunit = -1; /* no logical unit */
254 		}
255 		(void) strlcpy(rarpdev_head->device, ifsp.ifsp_devnm,
256 		    sizeof (rarpdev_head->device));
257 		rarpdev_head->unit = ifsp.ifsp_ppa;
258 
259 		ifdev->next = rarpdev_head->ifdev;
260 		rarpdev_head->ifdev = ifdev;
261 	}
262 
263 	/*
264 	 * Initialize each rarpdev.
265 	 */
266 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
267 		init_rarpdev(rdev);
268 	}
269 
270 	(void) sema_init(&delay_sema, 0, USYNC_THREAD, NULL);
271 	(void) mutex_init(&delay_mutex, USYNC_THREAD, NULL);
272 	(void) mutex_init(&debug_mutex, USYNC_THREAD, NULL);
273 
274 	/*
275 	 * Start delayed processing thread.
276 	 */
277 	(void) thr_create(NULL, NULL, (void *(*)(void *))do_delay_write, NULL,
278 	    THR_NEW_LWP, NULL);
279 
280 	/*
281 	 * Start RARP processing for each device.
282 	 */
283 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
284 		if (rdev->dh_rarp != NULL) {
285 			(void) thr_create(NULL, NULL,
286 			    (void *(*)(void *))do_rarp, (void *)rdev,
287 			    THR_NEW_LWP, NULL);
288 		}
289 	}
290 
291 	/*
292 	 * Exit main() thread
293 	 */
294 	thr_exit(NULL);
295 
296 	return (0);
297 }
298 
299 static void
300 getintf(void)
301 {
302 	int		fd;
303 	int		numifs;
304 	unsigned	bufsize;
305 	struct ifreq	*reqbuf;
306 	struct ifconf	ifconf;
307 	struct ifreq	*ifr;
308 	struct rarpdev	*rdev;
309 	struct ifdev	*ifdev;
310 
311 	/*
312 	 * Open the IP provider.
313 	 */
314 	if ((fd = open(DEVIP, 0)) < 0)
315 		syserr(DEVIP);
316 
317 	/*
318 	 * Ask IP for the list of configured interfaces.
319 	 */
320 	if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) {
321 		numifs = MAXIFS;
322 	}
323 	bufsize = numifs * sizeof (struct ifreq);
324 	reqbuf = (struct ifreq *)malloc(bufsize);
325 	if (reqbuf == NULL) {
326 		error("out of memory");
327 	}
328 
329 	ifconf.ifc_len = bufsize;
330 	ifconf.ifc_buf = (caddr_t)reqbuf;
331 	if (ioctl(fd, SIOCGIFCONF, (char *)&ifconf) < 0)
332 		syserr("SIOCGIFCONF");
333 
334 	/*
335 	 * Initialize a rarpdev for each interface.
336 	 */
337 	for (ifr = ifconf.ifc_req; ifconf.ifc_len > 0;
338 	    ifr++, ifconf.ifc_len -= sizeof (struct ifreq)) {
339 		ifspec_t	ifsp;
340 
341 		if (ioctl(fd, SIOCGIFFLAGS, (char *)ifr) < 0) {
342 			syserr("ioctl SIOCGIFFLAGS");
343 			exit(1);
344 		}
345 		if ((ifr->ifr_flags & IFF_LOOPBACK) ||
346 		    !(ifr->ifr_flags & IFF_UP) ||
347 		    !(ifr->ifr_flags & IFF_BROADCAST) ||
348 		    (ifr->ifr_flags & IFF_NOARP) ||
349 		    (ifr->ifr_flags & IFF_POINTOPOINT))
350 			continue;
351 
352 		if (!ifparse_ifspec(ifr->ifr_name, &ifsp))
353 			error("ifparse_ifspec failed");
354 
355 		/*
356 		 * Look for an existing device for logical interfaces.
357 		 */
358 		if ((rdev = find_device(&ifsp)) == NULL) {
359 			rdev = calloc(1, sizeof (struct rarpdev));
360 			if (rdev == NULL)
361 				error("out of memory");
362 
363 			(void) strlcpy(rdev->device, ifsp.ifsp_devnm,
364 			    sizeof (rdev->device));
365 			rdev->unit = ifsp.ifsp_ppa;
366 
367 			rdev->next = rarpdev_head;
368 			rarpdev_head = rdev;
369 		}
370 
371 		if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL)
372 			error("out of memory");
373 
374 		if (ifsp.ifsp_lunvalid) {
375 			(void) snprintf(ifdev->ldevice,
376 			    sizeof (ifdev->ldevice), "%s%d:",
377 			    ifsp.ifsp_devnm, ifsp.ifsp_ppa);
378 			ifdev->lunit = ifsp.ifsp_lun;
379 		} else
380 			ifdev->lunit = -1; /* no logical unit */
381 
382 		ifdev->next = rdev->ifdev;
383 		rdev->ifdev = ifdev;
384 	}
385 	(void) free((char *)reqbuf);
386 }
387 
388 static struct rarpdev *
389 find_device(ifspec_t *specp)
390 {
391 	struct rarpdev	*rdev;
392 
393 	for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) {
394 		if (specp->ifsp_ppa == rdev->unit &&
395 		    strcmp(specp->ifsp_devnm, rdev->device) == 0)
396 			return (rdev);
397 	}
398 	return (NULL);
399 }
400 
401 static void
402 init_rarpdev(struct rarpdev *rdev)
403 {
404 	char 		*dev;
405 	int 		unit;
406 	struct ifdev 	*ifdev;
407 	int		retval;
408 	char		*str = NULL;
409 	uint_t		physaddrlen = DLPI_PHYSADDR_MAX;
410 	char		linkname[DLPI_LINKNAME_MAX];
411 	dlpi_handle_t	dh;
412 
413 	(void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", rdev->device,
414 	    rdev->unit);
415 	/*
416 	 * Open datalink provider and get our mac address.
417 	 */
418 	if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) {
419 		error("cannot open link %s: %s", linkname,
420 		    dlpi_strerror(retval));
421 	}
422 
423 	if ((retval = dlpi_bind(dh, ETHERTYPE_REVARP, NULL)) != DLPI_SUCCESS) {
424 		dlpi_close(dh);
425 		error("dlpi_bind failed: %s", dlpi_strerror(retval));
426 	}
427 
428 	/*
429 	 * Save our mac address.
430 	 */
431 	if ((retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, rdev->physaddr,
432 	    &physaddrlen)) != DLPI_SUCCESS) {
433 		dlpi_close(dh);
434 		error("dlpi_get_physaddr failed: %s", dlpi_strerror(retval));
435 	}
436 
437 	rdev->physaddrlen = physaddrlen;
438 	rdev->ifrarplen = sizeof (struct arphdr) + (2 * sizeof (ipaddr_t)) +
439 	    (2 * physaddrlen);
440 
441 	if (dflag) {
442 		str = _link_ntoa(rdev->physaddr, str,
443 		    rdev->physaddrlen, IFT_OTHER);
444 		if (str != NULL) {
445 			debug("device %s physical address %s", linkname, str);
446 			free(str);
447 		}
448 	}
449 
450 	/*
451 	 * Assign dlpi handle to rdev.
452 	 */
453 	rdev->dh_rarp = dh;
454 
455 	/*
456 	 * Get the IP address and netmask from directory service for
457 	 * each logical interface.
458 	 */
459 	for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
460 		/*
461 		 * If lunit == -1 then this is the primary interface name.
462 		 */
463 		if (ifdev->lunit == -1) {
464 			dev = rdev->device;
465 			unit = rdev->unit;
466 		} else {
467 			dev = ifdev->ldevice;
468 			unit = ifdev->lunit;
469 		}
470 		get_ifdata(dev, unit, &ifdev->if_ipaddr, &ifdev->if_netmask);
471 
472 		/*
473 		 * Use IP address of the interface.
474 		 */
475 		ifdev->if_netnum = ifdev->if_ipaddr & ifdev->if_netmask;
476 		ifdev->ipaddr = (ipaddr_t)htonl(ifdev->if_ipaddr);
477 	}
478 }
479 
480 static void
481 do_rarp(void *buf)
482 {
483 	struct rarpdev *rdev = buf;
484 	char	*cause;
485 	struct arphdr *ans;
486 	uchar_t *shost;
487 	uint_t	saddrlen;
488 	size_t	anslen = rdev->ifrarplen;
489 	char	*str = NULL;
490 	int	retval;
491 
492 	if (((shost = malloc(rdev->physaddrlen)) == NULL) ||
493 	    ((ans = malloc(rdev->ifrarplen)) == NULL))
494 		syserr("malloc");
495 
496 	if (dflag) {
497 		str = _link_ntoa(rdev->physaddr, str, rdev->physaddrlen,
498 		    IFT_OTHER);
499 		if (str != NULL) {
500 			debug("starting rarp service on device %s%d physical"
501 			    " address %s", rdev->device, rdev->unit, str);
502 			free(str);
503 		}
504 	}
505 
506 	/*
507 	 * Read RARP packets and respond to them.
508 	 */
509 	for (;;) {
510 		saddrlen = DLPI_PHYSADDR_MAX;
511 		retval = dlpi_recv(rdev->dh_rarp, shost,
512 		    &saddrlen, ans, &anslen, -1, NULL);
513 		if (retval == DLPI_ETIMEDOUT) {
514 			continue;
515 		} else if (retval != DLPI_SUCCESS) {
516 			error("error in dlpi_recv %s: %s", rdev->dh_rarp,
517 			    dlpi_strerror(retval));
518 		}
519 
520 		cause = NULL;
521 
522 		if (anslen < rdev->ifrarplen)
523 			cause = "short packet";
524 		else if (ans->ar_hrd != htons(ARPHRD_ETHER))
525 			cause = "hardware type not Ethernet";
526 		else if (ans->ar_pro != htons(ETHERTYPE_IP))
527 			cause = "protocol type not IP";
528 		else if (ans->ar_hln != rdev->physaddrlen)
529 			cause = "unexpected hardware address length";
530 		else if (ans->ar_pln != sizeof (ipaddr_t))
531 			cause = "unexpected protocol address length";
532 		if (cause != NULL) {
533 			if (dflag)
534 				debug("RARP packet received but "
535 				    "discarded: %s", cause);
536 			continue;
537 		}
538 
539 		/*
540 		 * Handle the request.
541 		 */
542 		switch (ntohs(ans->ar_op)) {
543 		case REVARP_REQUEST:
544 			rarp_request(rdev, ans, shost);
545 			break;
546 
547 		case ARPOP_REQUEST:
548 			arp_request(rdev, ans, shost);
549 			break;
550 
551 		case REVARP_REPLY:
552 			if (dflag)
553 				debug("REVARP_REPLY ignored");
554 			break;
555 
556 		case ARPOP_REPLY:
557 			if (dflag)
558 				debug("ARPOP_REPLY ignored");
559 			break;
560 
561 		default:
562 			if (dflag)
563 				debug("unknown opcode 0x%x", ans->ar_op);
564 			break;
565 		}
566 	}
567 }
568 
569 /*
570  * Reverse address determination and allocation code.
571  */
572 static void
573 rarp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost)
574 {
575 	ipaddr_t		tpa,  spa;
576 	struct	rarpreply	*rrp;
577 	uchar_t			*shap, *thap, *spap, *tpap;
578 	char			*str = NULL;
579 	int			retval;
580 
581 	shap = (uchar_t *)rp + sizeof (struct arphdr);
582 	spap = shap + rp->ar_hln;
583 	thap = spap + rp->ar_pln;
584 	tpap = thap + rp->ar_hln;
585 
586 	if (dflag) {
587 		str = _link_ntoa(thap, str, rdev->physaddrlen, IFT_OTHER);
588 		if (str != NULL) {
589 			debug("RARP_REQUEST for %s", str);
590 			free(str);
591 		}
592 	}
593 
594 	/*
595 	 * Third party lookups are rare and wonderful.
596 	 */
597 	if ((memcmp(shap, thap, rdev->physaddrlen) != 0) ||
598 	    (memcmp(shap, shost, rdev->physaddrlen) != 0)) {
599 		if (dflag)
600 			debug("weird (3rd party lookup)");
601 	}
602 
603 	/*
604 	 * Fill in given parts of reply packet.
605 	 */
606 	(void) memcpy(shap, rdev->physaddr, rdev->physaddrlen);
607 
608 	/*
609 	 * If a good address is stored in our lookup tables, return it
610 	 * immediately or after a delay.  Store it in our kernel's ARP cache.
611 	 */
612 	if (get_ipaddr(rdev, thap, tpap, &spa))
613 		return;
614 	(void) memcpy(spap, &spa, sizeof (spa));
615 
616 	add_arp(rdev, tpap, thap);
617 
618 	rp->ar_op = htons(REVARP_REPLY);
619 
620 	if (dflag) {
621 		struct in_addr addr;
622 
623 		(void) memcpy(&addr, tpap, sizeof (ipaddr_t));
624 		debug("good lookup, maps to %s", inet_ntoa(addr));
625 	}
626 
627 	rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen +
628 	    rdev->ifrarplen);
629 	if (rrp == NULL)
630 		error("out of memory");
631 	rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply);
632 	rrp->arprep = rrp->lldest + rdev->physaddrlen;
633 
634 	/*
635 	 * Create rarpreply structure.
636 	 */
637 	(void) gettimeofday(&rrp->tv, NULL);
638 	rrp->tv.tv_sec += 3;	/* delay */
639 	rrp->rdev = rdev;
640 	(void) memcpy(rrp->lldest, shost, rdev->physaddrlen);
641 	(void) memcpy(rrp->arprep, rp, rdev->ifrarplen);
642 
643 	/*
644 	 * If this is diskless and we're not its bootserver, let the
645 	 * bootserver reply first by delaying a while.
646 	 */
647 	(void) memcpy(&tpa, tpap, sizeof (ipaddr_t));
648 	if (mightboot(ntohl(tpa))) {
649 		retval = dlpi_send(rdev->dh_rarp, rrp->lldest,
650 		    rdev->physaddrlen, rrp->arprep, rdev->ifrarplen, NULL);
651 		if (retval != DLPI_SUCCESS) {
652 			error("dlpi_send failed: %s", dlpi_strerror(retval));
653 		} else if (dflag) {
654 			debug("immediate reply sent");
655 		}
656 		(void) free(rrp);
657 	} else {
658 		delay_write(rdev, rrp);
659 	}
660 }
661 
662 /*
663  * Download an ARP entry into our kernel.
664  */
665 static void
666 add_arp(struct rarpdev *rdev, uchar_t *ip, uchar_t *laddr)
667 {
668 	struct xarpreq ar;
669 	struct sockaddr_in	*sin;
670 	int	fd;
671 
672 	/*
673 	 * Common part of query or set.
674 	 */
675 	(void) memset(&ar, 0, sizeof (ar));
676 	ar.xarp_pa.ss_family = AF_INET;
677 	sin = (struct sockaddr_in *)&ar.xarp_pa;
678 	(void) memcpy(&sin->sin_addr, ip, sizeof (ipaddr_t));
679 
680 	/*
681 	 * Open the IP provider.
682 	 */
683 	if ((fd = open(DEVARP, 0)) < 0)
684 		syserr(DEVARP);
685 
686 	/*
687 	 * Set the entry.
688 	 */
689 	(void) memcpy(LLADDR(&ar.xarp_ha), laddr, rdev->physaddrlen);
690 	ar.xarp_ha.sdl_alen = rdev->physaddrlen;
691 	ar.xarp_ha.sdl_family = AF_LINK;
692 	(void) strioctl(fd, SIOCDXARP, -1, sizeof (struct xarpreq),
693 	    (char *)&ar);
694 	if (strioctl(fd, SIOCSXARP, -1, sizeof (struct xarpreq),
695 	    (char *)&ar) < 0)
696 		syserr("SIOCSXARP");
697 
698 	(void) close(fd);
699 }
700 
701 /*
702  * The RARP spec says we must be able to process ARP requests,
703  * even through the packet type is RARP.  Let's hope this feature
704  * is not heavily used.
705  */
706 static void
707 arp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost)
708 {
709 	struct	rarpreply	*rrp;
710 	struct ifdev		*ifdev;
711 	uchar_t			*shap, *thap, *spap, *tpap;
712 	int			retval;
713 
714 	shap = (uchar_t *)rp + sizeof (struct arphdr);
715 	spap = shap + rp->ar_hln;
716 	thap = spap + rp->ar_pln;
717 	tpap = thap + rp->ar_hln;
718 
719 	if (dflag)
720 		debug("ARPOP_REQUEST");
721 
722 	for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
723 		if (memcmp(&ifdev->ipaddr, tpap, sizeof (ipaddr_t)) == 0)
724 			break;
725 	}
726 	if (ifdev == NULL)
727 		return;
728 
729 	rp->ar_op = ARPOP_REPLY;
730 	(void) memcpy(shap, rdev->physaddr, rdev->physaddrlen);
731 	(void) memcpy(spap, &ifdev->ipaddr, sizeof (ipaddr_t));
732 	(void) memcpy(thap, rdev->physaddr, rdev->physaddrlen);
733 
734 	add_arp(rdev, tpap, thap);
735 
736 	/*
737 	 * Create rarp reply structure.
738 	 */
739 	rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen +
740 	    rdev->ifrarplen);
741 	if (rrp == NULL)
742 		error("out of memory");
743 	rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply);
744 	rrp->arprep = rrp->lldest + rdev->physaddrlen;
745 	rrp->rdev = rdev;
746 
747 	(void) memcpy(rrp->lldest, shost, rdev->physaddrlen);
748 	(void) memcpy(rrp->arprep, rp, rdev->ifrarplen);
749 
750 	retval = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen,
751 	    rrp->arprep, rdev->ifrarplen, NULL);
752 	free(rrp);
753 	if (retval != DLPI_SUCCESS)
754 		error("dlpi_send failed: %s", dlpi_strerror(retval));
755 }
756 
757 /* ARGSUSED */
758 static void
759 do_delay_write(void *buf)
760 {
761 	struct	timeval		tv;
762 	struct	rarpreply	*rrp;
763 	struct	rarpdev		*rdev;
764 	int			err;
765 
766 	for (;;) {
767 		if ((err = sema_wait(&delay_sema)) != 0) {
768 			if (err == EINTR)
769 				continue;
770 			error("do_delay_write: sema_wait failed");
771 		}
772 
773 		(void) mutex_lock(&delay_mutex);
774 		rrp = delay_list;
775 		rdev = rrp->rdev;
776 		delay_list = delay_list->next;
777 		(void) mutex_unlock(&delay_mutex);
778 
779 		(void) gettimeofday(&tv, NULL);
780 		if (tv.tv_sec < rrp->tv.tv_sec)
781 			(void) sleep(rrp->tv.tv_sec - tv.tv_sec);
782 
783 		err = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen,
784 		    rrp->arprep, rdev->ifrarplen, NULL);
785 		if (err != DLPI_SUCCESS)
786 			error("dlpi_send failed: %s", dlpi_strerror(err));
787 
788 		(void) free(rrp);
789 	}
790 }
791 
792 /* ARGSUSED */
793 static void
794 delay_write(struct rarpdev *rdev, struct rarpreply *rrp)
795 {
796 	struct	rarpreply	*trp;
797 
798 	(void) mutex_lock(&delay_mutex);
799 	if (delay_list == NULL) {
800 		delay_list = rrp;
801 	} else {
802 		trp = delay_list;
803 		while (trp->next != NULL)
804 			trp = trp->next;
805 		trp->next = rrp;
806 	}
807 	(void) mutex_unlock(&delay_mutex);
808 
809 	(void) sema_post(&delay_sema);
810 }
811 
812 /*
813  * See if we have a TFTP boot file for this guy. Filenames in TFTP
814  * boot requests are of the form <ipaddr> for Sun-3's and of the form
815  * <ipaddr>.<arch> for all other architectures.  Since we don't know
816  * the client's architecture, either format will do.
817  */
818 static int
819 mightboot(ipaddr_t ipa)
820 {
821 	char path[MAXPATHL];
822 	DIR *dirp;
823 	struct dirent *dp;
824 
825 	(void) snprintf(path, sizeof (path), "%s/%08X", BOOTDIR, ipa);
826 
827 	/*
828 	 * Try a quick access() first.
829 	 */
830 	if (access(path, 0) == 0)
831 		return (1);
832 
833 	/*
834 	 * Not there, do it the slow way by
835 	 * reading through the directory.
836 	 */
837 	(void) sprintf(path, "%08X", ipa);
838 
839 	if (!(dirp = opendir(BOOTDIR)))
840 		return (0);
841 
842 	while ((dp = readdir(dirp)) != NULL) {
843 		if (strncmp(dp->d_name, path, 8) != 0)
844 			continue;
845 		if ((strlen(dp->d_name) != 8) && (dp->d_name[8] != '.'))
846 			continue;
847 		break;
848 	}
849 
850 	(void) closedir(dirp);
851 
852 	return ((dp != NULL) ? 1 : 0);
853 }
854 
855 /*
856  * Get our IP address and local netmask.
857  */
858 static void
859 get_ifdata(char *dev, int unit, ipaddr_t *ipp, ipaddr_t *maskp)
860 {
861 	int	fd;
862 	struct	ifreq	ifr;
863 	struct	sockaddr_in	*sin;
864 
865 	/* LINTED pointer */
866 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
867 
868 	/*
869 	 * Open the IP provider.
870 	 */
871 	if ((fd = open(DEVIP, 0)) < 0)
872 		syserr(DEVIP);
873 
874 	/*
875 	 * Ask IP for our IP address.
876 	 */
877 	(void) snprintf(ifr.ifr_name, sizeof (ifr.ifr_name), "%s%d", dev, unit);
878 	if (strioctl(fd, SIOCGIFADDR, -1, sizeof (struct ifreq),
879 	    (char *)&ifr) < 0)
880 		syserr("SIOCGIFADDR");
881 	*ipp = (ipaddr_t)ntohl(sin->sin_addr.s_addr);
882 
883 	if (dflag)
884 		debug("device %s%d address %s", dev, unit,
885 		    inet_ntoa(sin->sin_addr));
886 
887 	/*
888 	 * Ask IP for our netmask.
889 	 */
890 	if (strioctl(fd, SIOCGIFNETMASK, -1, sizeof (struct ifreq),
891 	    (char *)&ifr) < 0)
892 		syserr("SIOCGIFNETMASK");
893 	*maskp = (ipaddr_t)ntohl(sin->sin_addr.s_addr);
894 
895 	if (dflag)
896 		debug("device %s%d subnet mask %s", dev, unit,
897 		    inet_ntoa(sin->sin_addr));
898 
899 	/*
900 	 * Thankyou ip.
901 	 */
902 	(void) close(fd);
903 }
904 
905 /*
906  * Translate mac address to IP address.
907  * Return 0 on success, nonzero on failure.
908  */
909 static int
910 get_ipaddr(struct rarpdev *rdev, uchar_t *laddr, uchar_t *ipp, ipaddr_t *ipaddr)
911 {
912 	char host[MAXHOSTL];
913 	char hbuffer[BUFSIZE];
914 	struct hostent *hp, res;
915 	int herror;
916 	struct in_addr addr;
917 	char	**p;
918 	struct ifdev *ifdev;
919 
920 	if (rdev->physaddrlen != ETHERADDRL) {
921 		if (dflag)
922 			debug("%s %s", " cannot map non 6 byte hardware ",
923 			    "address to IP address");
924 		return (1);
925 	}
926 
927 	/*
928 	 * Translate mac address to hostname and IP address.
929 	 */
930 	if (ether_ntohost(host, (struct ether_addr *)laddr) != 0 ||
931 	    !(hp = gethostbyname_r(host, &res, hbuffer, sizeof (hbuffer),
932 	    &herror)) ||
933 	    hp->h_addrtype != AF_INET || hp->h_length != sizeof (ipaddr_t)) {
934 		if (dflag)
935 			debug("could not map hardware address to IP address");
936 		return (1);
937 	}
938 
939 	/*
940 	 * Find the IP address on the right net.
941 	 */
942 	for (p = hp->h_addr_list; *p; p++) {
943 		(void) memcpy(&addr, *p, sizeof (ipaddr_t));
944 		for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) {
945 			if (dflag) {
946 				struct in_addr daddr;
947 				ipaddr_t netnum;
948 
949 				netnum = htonl(ifdev->if_netnum);
950 				(void) memcpy(&daddr, &netnum,
951 				    sizeof (ipaddr_t));
952 				if (ifdev->lunit == -1)
953 					debug("trying physical netnum %s"
954 					    " mask %x", inet_ntoa(daddr),
955 					    ifdev->if_netmask);
956 				else
957 					debug("trying logical %d netnum %s"
958 					    " mask %x", ifdev->lunit,
959 					    inet_ntoa(daddr),
960 					    ifdev->if_netmask);
961 			}
962 			if ((ntohl(addr.s_addr) & ifdev->if_netmask) ==
963 			    ifdev->if_netnum) {
964 				/*
965 				 * Return the correct IP address.
966 				 */
967 				(void) memcpy(ipp, &addr, sizeof (ipaddr_t));
968 
969 				/*
970 				 * Return the interface's ipaddr
971 				 */
972 				(void) memcpy(ipaddr, &ifdev->ipaddr,
973 				    sizeof (ipaddr_t));
974 
975 				return (0);
976 			}
977 		}
978 	}
979 
980 	if (dflag)
981 		debug("got host entry but no IP address on this net");
982 	return (1);
983 }
984 
985 static int
986 strioctl(int fd, int cmd, int timout, int len, char *dp)
987 {
988 	struct	strioctl	si;
989 
990 	si.ic_cmd = cmd;
991 	si.ic_timout = timout;
992 	si.ic_len = len;
993 	si.ic_dp = dp;
994 	return (ioctl(fd, I_STR, &si));
995 }
996 
997 static void
998 usage(void)
999 {
1000 	error("Usage:  %s [ -ad ] device unit", cmdname);
1001 }
1002 
1003 static void
1004 syserr(const char *s)
1005 {
1006 	char buf[256];
1007 	int status = 1;
1008 
1009 	(void) snprintf(buf, sizeof (buf), "%s: %s", s, strerror(errno));
1010 	(void) fprintf(stderr, "%s:  %s\n", cmdname, buf);
1011 	syslog(LOG_ERR, "%s", buf);
1012 	thr_exit(&status);
1013 }
1014 
1015 static void
1016 error(const char *fmt, ...)
1017 {
1018 	char buf[256];
1019 	va_list ap;
1020 	int status = 1;
1021 
1022 	va_start(ap, fmt);
1023 	(void) vsprintf(buf, fmt, ap);
1024 	va_end(ap);
1025 	(void) fprintf(stderr, "%s:  %s\n", cmdname, buf);
1026 	syslog(LOG_ERR, buf);
1027 	thr_exit(&status);
1028 }
1029 
1030 /*PRINTFLIKE1*/
1031 static void
1032 debug(char *fmt, ...)
1033 {
1034 	va_list ap;
1035 
1036 	(void) mutex_lock(&debug_mutex);
1037 	va_start(ap, fmt);
1038 	(void) fprintf(stderr, "%s:[%u]  ", cmdname, thr_self());
1039 	(void) vfprintf(stderr, fmt, ap);
1040 	(void) fprintf(stderr, "\n");
1041 	va_end(ap);
1042 	(void) mutex_unlock(&debug_mutex);
1043 }
1044