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