17c478bd9Sstevel@tonic-gate /*
2aee32e3dScarlsonj  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * Copyright (c) 1987 Regents of the University of California.
87c478bd9Sstevel@tonic-gate  * All rights reserved.
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
117c478bd9Sstevel@tonic-gate  * provided that the above copyright notice and this paragraph are
127c478bd9Sstevel@tonic-gate  * duplicated in all such forms and that any documentation,
137c478bd9Sstevel@tonic-gate  * advertising materials, and other materials related to such
147c478bd9Sstevel@tonic-gate  * distribution and use acknowledge that the software was developed
157c478bd9Sstevel@tonic-gate  * by the University of California, Berkeley. The name of the
167c478bd9Sstevel@tonic-gate  * University may not be used to endorse or promote products derived
177c478bd9Sstevel@tonic-gate  * from this software without specific prior written permission.
187c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
197c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
207c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <stdio.h>
267c478bd9Sstevel@tonic-gate #include <errno.h>
277c478bd9Sstevel@tonic-gate #include <signal.h>
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <sys/time.h>
307c478bd9Sstevel@tonic-gate #include <sys/stat.h>
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/socket.h>
347c478bd9Sstevel@tonic-gate #include <sys/file.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
377c478bd9Sstevel@tonic-gate #include <net/if.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
407c478bd9Sstevel@tonic-gate #include <netinet/in.h>
417c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
427c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h>
437c478bd9Sstevel@tonic-gate #include <netdb.h>
447c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <fcntl.h>
477c478bd9Sstevel@tonic-gate #include <strings.h>
487c478bd9Sstevel@tonic-gate #include <stdlib.h>
497c478bd9Sstevel@tonic-gate #include <unistd.h>
507c478bd9Sstevel@tonic-gate #include <assert.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #ifdef lint
537c478bd9Sstevel@tonic-gate #define	ALIGN(ptr)	(ptr ? 0 : 0)
547c478bd9Sstevel@tonic-gate #else
557c478bd9Sstevel@tonic-gate #define	ALIGN(ptr)	(ptr)
567c478bd9Sstevel@tonic-gate #endif
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #ifdef SYSV
597c478bd9Sstevel@tonic-gate #define	signal(s, f)	sigset(s, (void (*)(int))f)
607c478bd9Sstevel@tonic-gate #define	random()	rand()
617c478bd9Sstevel@tonic-gate #endif
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate #define	ALL_HOSTS_ADDRESS		"224.0.0.1"
647c478bd9Sstevel@tonic-gate #define	ALL_ROUTERS_ADDRESS		"224.0.0.2"
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #define	MAXIFS 256
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /* For router advertisement */
697c478bd9Sstevel@tonic-gate struct icmp_ra {
707c478bd9Sstevel@tonic-gate 	uchar_t		icmp_type;	/* type of message, see below */
717c478bd9Sstevel@tonic-gate 	uchar_t		icmp_code;	/* type sub code */
727c478bd9Sstevel@tonic-gate 	ushort_t	icmp_cksum;	/* ones complement cksum of struct */
737c478bd9Sstevel@tonic-gate 	uchar_t		icmp_num_addrs;
747c478bd9Sstevel@tonic-gate 	uchar_t		icmp_wpa;	/* Words per address */
757c478bd9Sstevel@tonic-gate 	short		icmp_lifetime;
767c478bd9Sstevel@tonic-gate };
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate struct icmp_ra_addr {
797c478bd9Sstevel@tonic-gate 	ulong_t	addr;
807c478bd9Sstevel@tonic-gate 	ulong_t preference;
817c478bd9Sstevel@tonic-gate };
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /* Router constants */
847c478bd9Sstevel@tonic-gate #define	MAX_INITIAL_ADVERT_INTERVAL	16
857c478bd9Sstevel@tonic-gate #define	MAX_INITIAL_ADVERTISEMENTS 	3
867c478bd9Sstevel@tonic-gate #define	MAX_RESPONSE_DELAY		2	/* Not used */
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate /* Host constants */
897c478bd9Sstevel@tonic-gate #define	MAX_SOLICITATIONS		3
907c478bd9Sstevel@tonic-gate #define	SOLICITATION_INTERVAL		3
917c478bd9Sstevel@tonic-gate #define	MAX_SOLICITATION_DELAY		1	/* Not used */
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #define	IGNORE_PREFERENCE	0x80000000	/* Maximum negative */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate #define	MAX_ADV_INT 600
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * A doubly linked list of all physical interfaces that each contain a
1007c478bd9Sstevel@tonic-gate  * doubly linked list of logical interfaces aka IP addresses.
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate struct phyint {
1037c478bd9Sstevel@tonic-gate 	char		pi_name[IFNAMSIZ];	/* Used to identify it */
1047c478bd9Sstevel@tonic-gate 	int		pi_state;		/* See below */
1057c478bd9Sstevel@tonic-gate 	struct logint	*pi_logical_first;
1067c478bd9Sstevel@tonic-gate 	struct logint	*pi_logical_last;
1077c478bd9Sstevel@tonic-gate 	struct phyint	*pi_next;
1087c478bd9Sstevel@tonic-gate 	struct phyint	*pi_prev;
1097c478bd9Sstevel@tonic-gate };
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate struct logint {
1127c478bd9Sstevel@tonic-gate 	char		li_name[IFNAMSIZ];	/* Used to identify it */
1137c478bd9Sstevel@tonic-gate 	int		li_state;		/* See below */
1147c478bd9Sstevel@tonic-gate 	struct in_addr	li_address;	/* Used to identify the interface */
1157c478bd9Sstevel@tonic-gate 	struct in_addr	li_localaddr;	/* Actual address of the interface */
1167c478bd9Sstevel@tonic-gate 	int		li_preference;
1177c478bd9Sstevel@tonic-gate 	int		li_index;	/* interface index (SIOCGLIFINDEX) */
1187c478bd9Sstevel@tonic-gate 	uint64_t	li_flags;
1197c478bd9Sstevel@tonic-gate 	struct in_addr	li_bcastaddr;
1207c478bd9Sstevel@tonic-gate 	struct in_addr	li_remoteaddr;
1217c478bd9Sstevel@tonic-gate 	struct in_addr	li_netmask;
1227c478bd9Sstevel@tonic-gate 	struct logint	*li_next;	/* Next logical for this physical */
1237c478bd9Sstevel@tonic-gate 	struct logint	*li_prev;	/* Prev logical for this physical */
1247c478bd9Sstevel@tonic-gate 	struct phyint	*li_physical;	/* Back pointer */
1257c478bd9Sstevel@tonic-gate };
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate struct phyint *phyint;
1287c478bd9Sstevel@tonic-gate int num_usable_interfaces;		/* Num used for sending/receiving */
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate  * State bits
1327c478bd9Sstevel@tonic-gate  */
1337c478bd9Sstevel@tonic-gate #define	ST_MARKED	0x01		/* To determine removed interfaces */
1347c478bd9Sstevel@tonic-gate #define	ST_JOINED	0x02		/* Joined multicast group */
1357c478bd9Sstevel@tonic-gate #define	ST_DELETED	0x04		/* Interface should be ignored */
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /* Function prototypes */
1387c478bd9Sstevel@tonic-gate static void	solicitor(struct sockaddr_in *sin);
1397c478bd9Sstevel@tonic-gate static void	advertise(struct sockaddr_in *sin);
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate static void	age_table(int time);
1427c478bd9Sstevel@tonic-gate static void	flush_unreachable_routers(void);
1437c478bd9Sstevel@tonic-gate static void	record_router(struct in_addr router, long preference, int ttl);
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate static void	add_route(struct in_addr addr);
1467c478bd9Sstevel@tonic-gate static void	del_route(struct in_addr addr);
1477c478bd9Sstevel@tonic-gate static void	rtioctl(struct in_addr addr, int op);
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate static int	support_multicast(void);
1507c478bd9Sstevel@tonic-gate static int	sendbcast(int s, char *packet, int packetlen);
1517c478bd9Sstevel@tonic-gate static int	sendbcastif(int s, char *packet, int packetlen,
1527c478bd9Sstevel@tonic-gate 		    struct logint *li);
1537c478bd9Sstevel@tonic-gate static int	sendmcast(int s, char *packet, int packetlen,
1547c478bd9Sstevel@tonic-gate 		    struct sockaddr_in *sin);
1557c478bd9Sstevel@tonic-gate static int	sendmcastif(int s, char *packet, int packetlen,
1567c478bd9Sstevel@tonic-gate 		    struct sockaddr_in *sin, struct logint *li);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate static int	ismulticast(struct sockaddr_in *sin);
1597c478bd9Sstevel@tonic-gate static int	isbroadcast(struct sockaddr_in *sin);
1607c478bd9Sstevel@tonic-gate int		in_cksum(ushort_t *addr, int len);
1617c478bd9Sstevel@tonic-gate static struct logint *find_directly_connected_logint(struct in_addr in,
1627c478bd9Sstevel@tonic-gate     struct phyint *pi);
1637c478bd9Sstevel@tonic-gate static void	force_preference(int preference);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static void	timer(void);
1667c478bd9Sstevel@tonic-gate static void	finish(void);
1677c478bd9Sstevel@tonic-gate static void	report(void);
1687c478bd9Sstevel@tonic-gate static void	report_interfaces(void);
1697c478bd9Sstevel@tonic-gate static void	report_routes(void);
1707c478bd9Sstevel@tonic-gate static void	reinitifs(void);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate static struct phyint *find_phyint(char *name);
1737c478bd9Sstevel@tonic-gate static struct phyint *add_phyint(char *name);
1747c478bd9Sstevel@tonic-gate static void	free_phyint(struct phyint *pi);
1757c478bd9Sstevel@tonic-gate static struct logint *find_logint(struct phyint *pi, char *name);
1767c478bd9Sstevel@tonic-gate static struct logint *add_logint(struct phyint *pi, char *name);
1777c478bd9Sstevel@tonic-gate static void	free_logint(struct logint *li);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate static void	deleted_phyint(struct phyint *pi, int s,
1807c478bd9Sstevel@tonic-gate 		    struct sockaddr_in *joinaddr);
1817c478bd9Sstevel@tonic-gate static void	added_logint(struct logint *li, int s,
1827c478bd9Sstevel@tonic-gate 		    struct sockaddr_in *joinaddr);
1837c478bd9Sstevel@tonic-gate static void	deleted_logint(struct logint *li, struct logint *newli, int s,
1847c478bd9Sstevel@tonic-gate 		    struct sockaddr_in *joinaddr);
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate static int	initifs(int s, struct sockaddr_in *joinaddr, int preference);
1877c478bd9Sstevel@tonic-gate static boolean_t getconfig(int sock, uint64_t if_flags, struct sockaddr *addr,
1887c478bd9Sstevel@tonic-gate 		    struct ifreq *ifr, struct logint *li);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate static void	pr_pack(char *buf, int cc, struct sockaddr_in *from);
1917c478bd9Sstevel@tonic-gate char		*pr_name(struct in_addr addr);
1927c478bd9Sstevel@tonic-gate char		*pr_type(int t);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate static void	initlog(void);
1957c478bd9Sstevel@tonic-gate void		logerr(), logtrace(), logdebug(), logperror();
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /* Local variables */
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate #define	MAXPACKET	4096	/* max packet size */
2007c478bd9Sstevel@tonic-gate uchar_t	packet[MAXPACKET];
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate char usage[] =
2037c478bd9Sstevel@tonic-gate "Usage:	rdisc [-s] [-v] [-f] [-a] [send_address] [receive_address]\n"
2047c478bd9Sstevel@tonic-gate "	rdisc -r [-v] [-p <preference>] [-T <secs>] \n"
2057c478bd9Sstevel@tonic-gate "		[send_address] [receive_address]\n";
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate int s;				/* Socket file descriptor */
2097c478bd9Sstevel@tonic-gate struct sockaddr_in whereto;	/* Address to send to */
2107c478bd9Sstevel@tonic-gate struct sockaddr_in g_joinaddr;	/* Address to receive on */
2117c478bd9Sstevel@tonic-gate char    *sendaddress, *recvaddress;	/* For logging purposes only */
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate /* Common variables */
2147c478bd9Sstevel@tonic-gate int verbose = 0;
2157c478bd9Sstevel@tonic-gate int debug = 0;
2167c478bd9Sstevel@tonic-gate int trace = 0;
2177c478bd9Sstevel@tonic-gate int start_solicit = 0;	/* -s parameter set */
2187c478bd9Sstevel@tonic-gate int solicit = 0;	/* Are we currently sending solicitations? */
2197c478bd9Sstevel@tonic-gate int responder;
2207c478bd9Sstevel@tonic-gate int ntransmitted = 0;
2217c478bd9Sstevel@tonic-gate int nreceived = 0;
2227c478bd9Sstevel@tonic-gate int forever = 0;	/* Never give up on host. If 0 defer fork until */
2237c478bd9Sstevel@tonic-gate 			/* first response.				*/
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate /* Router variables */
2267c478bd9Sstevel@tonic-gate int max_adv_int = MAX_ADV_INT;
2277c478bd9Sstevel@tonic-gate int min_adv_int;
2287c478bd9Sstevel@tonic-gate int lifetime;
2297c478bd9Sstevel@tonic-gate int initial_advert_interval = MAX_INITIAL_ADVERT_INTERVAL;
2307c478bd9Sstevel@tonic-gate int initial_advertisements = MAX_INITIAL_ADVERTISEMENTS;
2317c478bd9Sstevel@tonic-gate ulong_t g_preference = 0;	/* Setable with -p option */
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate /* Host variables */
2347c478bd9Sstevel@tonic-gate int max_solicitations = MAX_SOLICITATIONS;
2357c478bd9Sstevel@tonic-gate unsigned int solicitation_interval = SOLICITATION_INTERVAL;
2367c478bd9Sstevel@tonic-gate int best_preference = 1; 	/* Set to record only the router(s) with the */
2377c478bd9Sstevel@tonic-gate 				/* best preference in the kernel. Not set   */
2387c478bd9Sstevel@tonic-gate 				/* puts all routes in the kernel.	    */
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate static void
2427c478bd9Sstevel@tonic-gate prusage()
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, usage);
2457c478bd9Sstevel@tonic-gate 	exit(1);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate static int	sock = -1;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate static void
2517c478bd9Sstevel@tonic-gate do_fork()
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	int t;
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	if (trace)
2567c478bd9Sstevel@tonic-gate 		return;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if (fork())
2597c478bd9Sstevel@tonic-gate 		exit(0);
2607c478bd9Sstevel@tonic-gate 	for (t = 0; t < 20; t++)
2617c478bd9Sstevel@tonic-gate 		if (t != s)
2627c478bd9Sstevel@tonic-gate 			(void) close(t);
2637c478bd9Sstevel@tonic-gate 	sock = -1;
2647c478bd9Sstevel@tonic-gate 	(void) open("/", 0);
2657c478bd9Sstevel@tonic-gate 	(void) dup2(0, 1);
2667c478bd9Sstevel@tonic-gate 	(void) dup2(0, 2);
2677c478bd9Sstevel@tonic-gate #ifndef SYSV
2687c478bd9Sstevel@tonic-gate 	t = open("/dev/tty", 2);
2697c478bd9Sstevel@tonic-gate 	if (t >= 0) {
2707c478bd9Sstevel@tonic-gate 		(void) ioctl(t, TIOCNOTTY, (char *)0);
2717c478bd9Sstevel@tonic-gate 		(void) close(t);
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate #else
2747c478bd9Sstevel@tonic-gate 	(void) setpgrp();
2757c478bd9Sstevel@tonic-gate #endif
2767c478bd9Sstevel@tonic-gate 	initlog();
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  *			M A I N
2817c478bd9Sstevel@tonic-gate  */
2827c478bd9Sstevel@tonic-gate int
2837c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate #ifndef SYSV
2867c478bd9Sstevel@tonic-gate 	struct sigvec sv;
2877c478bd9Sstevel@tonic-gate #endif
2887c478bd9Sstevel@tonic-gate 	struct sockaddr_in from;
2897c478bd9Sstevel@tonic-gate 	char **av = argv;
2907c478bd9Sstevel@tonic-gate 	struct sockaddr_in *to = &whereto;
2917c478bd9Sstevel@tonic-gate 	ulong_t val;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	min_adv_int = (max_adv_int * 3 / 4);
2947c478bd9Sstevel@tonic-gate 	lifetime = (3*max_adv_int);
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	argc--, av++;
2977c478bd9Sstevel@tonic-gate 	while (argc > 0 && *av[0] == '-') {
2987c478bd9Sstevel@tonic-gate 	    while (*++av[0])
2997c478bd9Sstevel@tonic-gate 		switch (*av[0]) {
3007c478bd9Sstevel@tonic-gate 		case 'd':
3017c478bd9Sstevel@tonic-gate 			debug = 1;
3027c478bd9Sstevel@tonic-gate 			break;
3037c478bd9Sstevel@tonic-gate 		case 't':
3047c478bd9Sstevel@tonic-gate 			trace = 1;
3057c478bd9Sstevel@tonic-gate 			break;
3067c478bd9Sstevel@tonic-gate 		case 'v':
3077c478bd9Sstevel@tonic-gate 			verbose++;
3087c478bd9Sstevel@tonic-gate 			break;
3097c478bd9Sstevel@tonic-gate 		case 's':
3107c478bd9Sstevel@tonic-gate 			start_solicit = solicit = 1;
3117c478bd9Sstevel@tonic-gate 			break;
3127c478bd9Sstevel@tonic-gate 		case 'r':
3137c478bd9Sstevel@tonic-gate 			responder = 1;
3147c478bd9Sstevel@tonic-gate 			break;
3157c478bd9Sstevel@tonic-gate 		case 'a':
3167c478bd9Sstevel@tonic-gate 			best_preference = 0;
3177c478bd9Sstevel@tonic-gate 			break;
3187c478bd9Sstevel@tonic-gate 		case 'b':
3197c478bd9Sstevel@tonic-gate 			best_preference = 1;
3207c478bd9Sstevel@tonic-gate 			break;
3217c478bd9Sstevel@tonic-gate 		case 'f':
3227c478bd9Sstevel@tonic-gate 			forever = 1;
3237c478bd9Sstevel@tonic-gate 			break;
3247c478bd9Sstevel@tonic-gate 		case 'T':
3257c478bd9Sstevel@tonic-gate 			argc--, av++;
3267c478bd9Sstevel@tonic-gate 			if (argc != 0) {
3277c478bd9Sstevel@tonic-gate 				val = strtol(av[0], (char **)NULL, 0);
3287c478bd9Sstevel@tonic-gate 				if (val < 4 || val > 1800) {
3297c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
3307c478bd9Sstevel@tonic-gate 					    "Bad Max Advertisement Interval\n");
3317c478bd9Sstevel@tonic-gate 					exit(1);
3327c478bd9Sstevel@tonic-gate 				}
3337c478bd9Sstevel@tonic-gate 				max_adv_int = val;
3347c478bd9Sstevel@tonic-gate 				min_adv_int = (max_adv_int * 3 / 4);
3357c478bd9Sstevel@tonic-gate 				lifetime = (3*max_adv_int);
3367c478bd9Sstevel@tonic-gate 			} else {
3377c478bd9Sstevel@tonic-gate 				prusage();
3387c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
3397c478bd9Sstevel@tonic-gate 			}
3407c478bd9Sstevel@tonic-gate 			goto next;
3417c478bd9Sstevel@tonic-gate 		case 'p':
3427c478bd9Sstevel@tonic-gate 			argc--, av++;
3437c478bd9Sstevel@tonic-gate 			if (argc != 0) {
3447c478bd9Sstevel@tonic-gate 				val = strtoul(av[0], (char **)NULL, 0);
3457c478bd9Sstevel@tonic-gate 				g_preference = val;
3467c478bd9Sstevel@tonic-gate 			} else {
3477c478bd9Sstevel@tonic-gate 				prusage();
3487c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
3497c478bd9Sstevel@tonic-gate 			}
3507c478bd9Sstevel@tonic-gate 			goto next;
3517c478bd9Sstevel@tonic-gate 		default:
3527c478bd9Sstevel@tonic-gate 			prusage();
3537c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
3547c478bd9Sstevel@tonic-gate 		}
3557c478bd9Sstevel@tonic-gate 	next:
3567c478bd9Sstevel@tonic-gate 		argc--, av++;
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	if (argc < 1)  {
3597c478bd9Sstevel@tonic-gate 		if (support_multicast()) {
3607c478bd9Sstevel@tonic-gate 			if (responder)
3617c478bd9Sstevel@tonic-gate 				sendaddress = ALL_HOSTS_ADDRESS;
3627c478bd9Sstevel@tonic-gate 			else
3637c478bd9Sstevel@tonic-gate 				sendaddress = ALL_ROUTERS_ADDRESS;
3647c478bd9Sstevel@tonic-gate 		} else
3657c478bd9Sstevel@tonic-gate 			sendaddress = "255.255.255.255";
3667c478bd9Sstevel@tonic-gate 	} else {
3677c478bd9Sstevel@tonic-gate 		sendaddress = av[0];
3687c478bd9Sstevel@tonic-gate 		argc--;
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 	if (argc < 1) {
3717c478bd9Sstevel@tonic-gate 		if (support_multicast()) {
3727c478bd9Sstevel@tonic-gate 			if (responder)
3737c478bd9Sstevel@tonic-gate 				recvaddress = ALL_ROUTERS_ADDRESS;
3747c478bd9Sstevel@tonic-gate 			else
3757c478bd9Sstevel@tonic-gate 				recvaddress = ALL_HOSTS_ADDRESS;
3767c478bd9Sstevel@tonic-gate 		} else
3777c478bd9Sstevel@tonic-gate 			recvaddress = "255.255.255.255";
3787c478bd9Sstevel@tonic-gate 	} else {
3797c478bd9Sstevel@tonic-gate 		recvaddress = av[0];
3807c478bd9Sstevel@tonic-gate 		argc--;
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 	if (argc != 0) {
3837c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Extra paramaters\n");
3847c478bd9Sstevel@tonic-gate 		prusage();
3857c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	if (solicit && responder) {
3897c478bd9Sstevel@tonic-gate 		prusage();
3907c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	if (!(solicit && !forever)) {
3947c478bd9Sstevel@tonic-gate 		do_fork();
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	bzero((char *)&whereto, sizeof (struct sockaddr_in));
3987c478bd9Sstevel@tonic-gate 	to->sin_family = AF_INET;
3997c478bd9Sstevel@tonic-gate 	to->sin_addr.s_addr = inet_addr(sendaddress);
4007c478bd9Sstevel@tonic-gate 	if (to->sin_addr.s_addr == (unsigned long)-1) {
4017c478bd9Sstevel@tonic-gate 		logerr("in.rdisc: bad address %s\n", sendaddress);
4027c478bd9Sstevel@tonic-gate 		exit(1);
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	bzero((char *)&g_joinaddr, sizeof (struct sockaddr_in));
4067c478bd9Sstevel@tonic-gate 	g_joinaddr.sin_family = AF_INET;
4077c478bd9Sstevel@tonic-gate 	g_joinaddr.sin_addr.s_addr = inet_addr(recvaddress);
4087c478bd9Sstevel@tonic-gate 	if (g_joinaddr.sin_addr.s_addr == (unsigned long)-1) {
4097c478bd9Sstevel@tonic-gate 		logerr("in.rdisc: bad address %s\n", recvaddress);
4107c478bd9Sstevel@tonic-gate 		exit(1);
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	if (responder) {
4147c478bd9Sstevel@tonic-gate #ifdef SYSV
4157c478bd9Sstevel@tonic-gate 		srand((int)gethostid());
4167c478bd9Sstevel@tonic-gate #else
4177c478bd9Sstevel@tonic-gate 		srandom((int)gethostid());
4187c478bd9Sstevel@tonic-gate #endif
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
4227c478bd9Sstevel@tonic-gate 		logperror("socket");
4237c478bd9Sstevel@tonic-gate 		exit(5);
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate #ifdef SYSV
4277c478bd9Sstevel@tonic-gate 	setvbuf(stdout, NULL, _IOLBF, 0);
4287c478bd9Sstevel@tonic-gate #else
4297c478bd9Sstevel@tonic-gate 	setlinebuf(stdout);
4307c478bd9Sstevel@tonic-gate #endif
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	(void) signal(SIGINT, finish);
4337c478bd9Sstevel@tonic-gate 	(void) signal(SIGTERM, finish);
4347c478bd9Sstevel@tonic-gate 	(void) signal(SIGHUP, reinitifs);
4357c478bd9Sstevel@tonic-gate 	(void) signal(SIGUSR1, report);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	if (initifs(s, &g_joinaddr, g_preference) < 0) {
4387c478bd9Sstevel@tonic-gate 		logerr("Failed initializing interfaces\n");
4397c478bd9Sstevel@tonic-gate 		exit(2);
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	/*
4437c478bd9Sstevel@tonic-gate 	 * If there are no usable interfaces and we are soliciting
4447c478bd9Sstevel@tonic-gate 	 * waiting for to return an exit code (i.e. forever isn't set)
4457c478bd9Sstevel@tonic-gate 	 * give up immediately.
4467c478bd9Sstevel@tonic-gate 	 */
4477c478bd9Sstevel@tonic-gate 	if (num_usable_interfaces == 0 && solicit && !forever) {
4487c478bd9Sstevel@tonic-gate 		logerr("in.rdisc: No interfaces up\n");
4497c478bd9Sstevel@tonic-gate 		exit(5);
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate #ifdef SYSV
4537c478bd9Sstevel@tonic-gate 	(void) signal(SIGALRM, timer);
4547c478bd9Sstevel@tonic-gate #else
4557c478bd9Sstevel@tonic-gate 	/*
4567c478bd9Sstevel@tonic-gate 	 * Make sure that this signal actually interrupts (rather than
4577c478bd9Sstevel@tonic-gate 	 * restarts) the recvfrom call below.
4587c478bd9Sstevel@tonic-gate 	 */
4597c478bd9Sstevel@tonic-gate 	sv.sv_handler = timer;
4607c478bd9Sstevel@tonic-gate 	sv.sv_mask = 0;
4617c478bd9Sstevel@tonic-gate 	sv.sv_flags = SV_INTERRUPT;
4627c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGALRM, &sv, (struct sigvec *)NULL);
4637c478bd9Sstevel@tonic-gate #endif
4647c478bd9Sstevel@tonic-gate 	timer();	/* start things going */
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	for (;;) {
4677c478bd9Sstevel@tonic-gate 		int len = sizeof (packet);
4687c478bd9Sstevel@tonic-gate 		socklen_t fromlen = (socklen_t)sizeof (from);
4697c478bd9Sstevel@tonic-gate 		int cc;
4707c478bd9Sstevel@tonic-gate 		sigset_t newmask, oldmask;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		if ((cc = recvfrom(s, (char *)packet, len, 0,
4737c478bd9Sstevel@tonic-gate 		    (struct sockaddr *)&from,
4747c478bd9Sstevel@tonic-gate 		    &fromlen)) < 0) {
4757c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
4767c478bd9Sstevel@tonic-gate 				continue;
4777c478bd9Sstevel@tonic-gate 			logperror("recvfrom");
4787c478bd9Sstevel@tonic-gate 			continue;
4797c478bd9Sstevel@tonic-gate 		}
4807c478bd9Sstevel@tonic-gate 		/* Block all signals while processing */
4817c478bd9Sstevel@tonic-gate 		(void) sigfillset(&newmask);
4827c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_SETMASK, &newmask, &oldmask);
4837c478bd9Sstevel@tonic-gate 		pr_pack((char *)packet, cc, &from);
4847c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_SETMASK, &oldmask, NULL);
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate static void
4907c478bd9Sstevel@tonic-gate report(void)
4917c478bd9Sstevel@tonic-gate {
4927c478bd9Sstevel@tonic-gate 	report_interfaces();
4937c478bd9Sstevel@tonic-gate 	report_routes();
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate #define	TIMER_INTERVAL	6
4977c478bd9Sstevel@tonic-gate #define	GETIFCONF_TIMER	30
4987c478bd9Sstevel@tonic-gate 
499aee32e3dScarlsonj static int left_until_advertise;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate /* Called every TIMER_INTERVAL */
5027c478bd9Sstevel@tonic-gate static void
5037c478bd9Sstevel@tonic-gate timer(void)
5047c478bd9Sstevel@tonic-gate {
505aee32e3dScarlsonj 	static int time;
506aee32e3dScarlsonj 	static int left_until_getifconf;
507aee32e3dScarlsonj 	static int left_until_solicit;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	time += TIMER_INTERVAL;
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	left_until_getifconf -= TIMER_INTERVAL;
5127c478bd9Sstevel@tonic-gate 	left_until_advertise -= TIMER_INTERVAL;
5137c478bd9Sstevel@tonic-gate 	left_until_solicit -= TIMER_INTERVAL;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	if (left_until_getifconf < 0) {
5167c478bd9Sstevel@tonic-gate 		(void) initifs(s, &g_joinaddr, g_preference);
5177c478bd9Sstevel@tonic-gate 		left_until_getifconf = GETIFCONF_TIMER;
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 	if (responder && left_until_advertise <= 0) {
5207c478bd9Sstevel@tonic-gate 		ntransmitted++;
5217c478bd9Sstevel@tonic-gate 		advertise(&whereto);
5227c478bd9Sstevel@tonic-gate 		if (ntransmitted < initial_advertisements)
5237c478bd9Sstevel@tonic-gate 			left_until_advertise = initial_advert_interval;
5247c478bd9Sstevel@tonic-gate 		else
5257c478bd9Sstevel@tonic-gate 			left_until_advertise = min_adv_int +
5267c478bd9Sstevel@tonic-gate 				((max_adv_int - min_adv_int) *
5277c478bd9Sstevel@tonic-gate 				(random() % 1000)/1000);
5287c478bd9Sstevel@tonic-gate 	} else if (solicit && left_until_solicit <= 0) {
5297c478bd9Sstevel@tonic-gate 		if (ntransmitted < max_solicitations) {
5307c478bd9Sstevel@tonic-gate 			ntransmitted++;
5317c478bd9Sstevel@tonic-gate 			solicitor(&whereto);
5327c478bd9Sstevel@tonic-gate 			left_until_solicit = solicitation_interval;
5337c478bd9Sstevel@tonic-gate 		} else {
5347c478bd9Sstevel@tonic-gate 			solicit = 0;
5357c478bd9Sstevel@tonic-gate 			if (!forever && nreceived == 0)
5367c478bd9Sstevel@tonic-gate 				exit(5);
5377c478bd9Sstevel@tonic-gate 		}
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 	age_table(TIMER_INTERVAL);
5407c478bd9Sstevel@tonic-gate 	(void) alarm(TIMER_INTERVAL);
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate /*
5447c478bd9Sstevel@tonic-gate  *			S O L I C I T O R
5457c478bd9Sstevel@tonic-gate  *
5467c478bd9Sstevel@tonic-gate  * Compose and transmit an ICMP ROUTER SOLICITATION REQUEST packet.
5477c478bd9Sstevel@tonic-gate  * The IP packet will be added on by the kernel.
5487c478bd9Sstevel@tonic-gate  */
5497c478bd9Sstevel@tonic-gate static void
5507c478bd9Sstevel@tonic-gate solicitor(struct sockaddr_in *sin)
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate 	static uchar_t outpack[MAXPACKET];
5537c478bd9Sstevel@tonic-gate 	register struct icmp *icp = (struct icmp *)ALIGN(outpack);
5547c478bd9Sstevel@tonic-gate 	int packetlen, i;
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	if (verbose) {
5577c478bd9Sstevel@tonic-gate 		logtrace("Sending solicitation to %s\n",
5587c478bd9Sstevel@tonic-gate 			pr_name(sin->sin_addr));
5597c478bd9Sstevel@tonic-gate 	}
5607c478bd9Sstevel@tonic-gate 	icp->icmp_type = ICMP_ROUTERSOLICIT;
5617c478bd9Sstevel@tonic-gate 	icp->icmp_code = 0;
5627c478bd9Sstevel@tonic-gate 	icp->icmp_cksum = 0;
5637c478bd9Sstevel@tonic-gate 	icp->icmp_void = 0; /* Reserved */
5647c478bd9Sstevel@tonic-gate 	packetlen = 8;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	/* Compute ICMP checksum here */
5677c478bd9Sstevel@tonic-gate 	icp->icmp_cksum = in_cksum((ushort_t *)icp, packetlen);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	if (isbroadcast(sin))
5707c478bd9Sstevel@tonic-gate 		i = sendbcast(s, (char *)outpack, packetlen);
5717c478bd9Sstevel@tonic-gate 	else if (ismulticast(sin))
5727c478bd9Sstevel@tonic-gate 		i = sendmcast(s, (char *)outpack, packetlen, sin);
5737c478bd9Sstevel@tonic-gate 	else {
5747c478bd9Sstevel@tonic-gate 		struct logint *li;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 		li = find_directly_connected_logint(sin->sin_addr, NULL);
5777c478bd9Sstevel@tonic-gate 		if (li != NULL && (li->li_flags & IFF_NORTEXCH)) {
5787c478bd9Sstevel@tonic-gate 			if (verbose) {
5797c478bd9Sstevel@tonic-gate 				logtrace("Suppressing sending %s on %s "
5807c478bd9Sstevel@tonic-gate 				    "(no route exchange on interface)\n",
5817c478bd9Sstevel@tonic-gate 				    pr_type((int)icp->icmp_type), li->li_name);
5827c478bd9Sstevel@tonic-gate 			}
5837c478bd9Sstevel@tonic-gate 			return;
5847c478bd9Sstevel@tonic-gate 		} else {
5857c478bd9Sstevel@tonic-gate 			i = sendto(s, (char *)outpack, packetlen, 0,
5867c478bd9Sstevel@tonic-gate 			    (struct sockaddr *)sin, sizeof (struct sockaddr));
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	if (i < 0 || i != packetlen)  {
5917c478bd9Sstevel@tonic-gate 		if (i < 0) {
5927c478bd9Sstevel@tonic-gate 		    logperror("sendto");
5937c478bd9Sstevel@tonic-gate 		}
5947c478bd9Sstevel@tonic-gate 		logerr("wrote %s %d chars, ret=%d\n",
5957c478bd9Sstevel@tonic-gate 			sendaddress, packetlen, i);
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate /*
6007c478bd9Sstevel@tonic-gate  *			A D V E R T I S E
6017c478bd9Sstevel@tonic-gate  *
6027c478bd9Sstevel@tonic-gate  * Compose and transmit an ICMP ROUTER ADVERTISEMENT packet.
6037c478bd9Sstevel@tonic-gate  * The IP packet will be added on by the kernel.
6047c478bd9Sstevel@tonic-gate  */
6057c478bd9Sstevel@tonic-gate static void
6067c478bd9Sstevel@tonic-gate advertise(struct sockaddr_in *sin)
6077c478bd9Sstevel@tonic-gate {
6087c478bd9Sstevel@tonic-gate 	struct phyint *pi;
6097c478bd9Sstevel@tonic-gate 	struct logint *li, *li_tmp;
6107c478bd9Sstevel@tonic-gate 	static uchar_t outpack[MAXPACKET];
6117c478bd9Sstevel@tonic-gate 	register struct icmp_ra *rap = (struct icmp_ra *)ALIGN(outpack);
6127c478bd9Sstevel@tonic-gate 	struct icmp_ra_addr *ap;
6137c478bd9Sstevel@tonic-gate 	int packetlen, cc;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	if (verbose) {
6167c478bd9Sstevel@tonic-gate 		logtrace("Sending advertisement to %s\n",
6177c478bd9Sstevel@tonic-gate 			pr_name(sin->sin_addr));
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
6217c478bd9Sstevel@tonic-gate 		rap->icmp_type = ICMP_ROUTERADVERT;
6227c478bd9Sstevel@tonic-gate 		rap->icmp_code = 0;
6237c478bd9Sstevel@tonic-gate 		rap->icmp_cksum = 0;
6247c478bd9Sstevel@tonic-gate 		rap->icmp_num_addrs = 0;
6257c478bd9Sstevel@tonic-gate 		rap->icmp_wpa = 2;
6267c478bd9Sstevel@tonic-gate 		rap->icmp_lifetime = htons(lifetime);
6277c478bd9Sstevel@tonic-gate 		packetlen = ICMP_MINLEN;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
6307c478bd9Sstevel@tonic-gate 			if (li->li_state & ST_DELETED)
6317c478bd9Sstevel@tonic-gate 				continue;
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 			/*
6347c478bd9Sstevel@tonic-gate 			 * XXX Just truncate the list of addresses.
6357c478bd9Sstevel@tonic-gate 			 * Should probably send multiple packets.
6367c478bd9Sstevel@tonic-gate 			 */
6377c478bd9Sstevel@tonic-gate 			if (packetlen + rap->icmp_wpa * 4 > sizeof (outpack)) {
6387c478bd9Sstevel@tonic-gate 				if (debug)
6397c478bd9Sstevel@tonic-gate 					logdebug("full packet: %d addresses\n",
6407c478bd9Sstevel@tonic-gate 						rap->icmp_num_addrs);
6417c478bd9Sstevel@tonic-gate 				break;
6427c478bd9Sstevel@tonic-gate 			}
6437c478bd9Sstevel@tonic-gate 			ap = (struct icmp_ra_addr *)ALIGN(outpack + packetlen);
6447c478bd9Sstevel@tonic-gate 			ap->addr = li->li_localaddr.s_addr;
6457c478bd9Sstevel@tonic-gate 			ap->preference = htonl(li->li_preference);
6467c478bd9Sstevel@tonic-gate 			packetlen += rap->icmp_wpa * 4;
6477c478bd9Sstevel@tonic-gate 			rap->icmp_num_addrs++;
6487c478bd9Sstevel@tonic-gate 		}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		if (rap->icmp_num_addrs == 0)
6517c478bd9Sstevel@tonic-gate 			continue;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 		/* Compute ICMP checksum here */
6547c478bd9Sstevel@tonic-gate 		rap->icmp_cksum = in_cksum((ushort_t *)rap, packetlen);
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 		if (isbroadcast(sin))
6577c478bd9Sstevel@tonic-gate 			cc = sendbcastif(s, (char *)outpack, packetlen,
6587c478bd9Sstevel@tonic-gate 			    pi->pi_logical_first);
6597c478bd9Sstevel@tonic-gate 		else if (ismulticast(sin))
6607c478bd9Sstevel@tonic-gate 			cc = sendmcastif(s, (char *)outpack, packetlen, sin,
6617c478bd9Sstevel@tonic-gate 			    pi->pi_logical_first);
6627c478bd9Sstevel@tonic-gate 		else {
6637c478bd9Sstevel@tonic-gate 			/*
6647c478bd9Sstevel@tonic-gate 			 * Verify that the physical interface matches the
6657c478bd9Sstevel@tonic-gate 			 * destination address.
6667c478bd9Sstevel@tonic-gate 			 */
6677c478bd9Sstevel@tonic-gate 			li_tmp = find_directly_connected_logint(sin->sin_addr,
6687c478bd9Sstevel@tonic-gate 			    pi);
6697c478bd9Sstevel@tonic-gate 			if (li_tmp == NULL)
6707c478bd9Sstevel@tonic-gate 				continue;
6717c478bd9Sstevel@tonic-gate 			if (li_tmp->li_flags & IFF_NORTEXCH) {
6727c478bd9Sstevel@tonic-gate 				if (verbose) {
6737c478bd9Sstevel@tonic-gate 					logtrace("Suppressing sending %s on %s "
6747c478bd9Sstevel@tonic-gate 					    "(no route exchange on "
6757c478bd9Sstevel@tonic-gate 					    "interface)\n",
6767c478bd9Sstevel@tonic-gate 					    pr_type((int)rap->icmp_type),
6777c478bd9Sstevel@tonic-gate 					    li_tmp->li_name);
6787c478bd9Sstevel@tonic-gate 				}
6797c478bd9Sstevel@tonic-gate 				continue;
6807c478bd9Sstevel@tonic-gate 			}
6817c478bd9Sstevel@tonic-gate 			if (debug) {
6827c478bd9Sstevel@tonic-gate 				logdebug("Unicast to %s ",
6837c478bd9Sstevel@tonic-gate 				    pr_name(sin->sin_addr));
6847c478bd9Sstevel@tonic-gate 				logdebug("on interface %s\n", pi->pi_name);
6857c478bd9Sstevel@tonic-gate 			}
6867c478bd9Sstevel@tonic-gate 			cc = sendto(s, (char *)outpack, packetlen, 0,
6877c478bd9Sstevel@tonic-gate 			    (struct sockaddr *)sin, sizeof (struct sockaddr));
6887c478bd9Sstevel@tonic-gate 		}
6897c478bd9Sstevel@tonic-gate 		if (cc < 0 || cc != packetlen)  {
6907c478bd9Sstevel@tonic-gate 			if (cc < 0) {
6917c478bd9Sstevel@tonic-gate 				logperror("sendto");
6927c478bd9Sstevel@tonic-gate 			} else {
6937c478bd9Sstevel@tonic-gate 				logerr("wrote %s %d chars, ret=%d\n",
6947c478bd9Sstevel@tonic-gate 					sendaddress, packetlen, cc);
6957c478bd9Sstevel@tonic-gate 			}
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate }
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate /*
7017c478bd9Sstevel@tonic-gate  *			P R _ T Y P E
7027c478bd9Sstevel@tonic-gate  *
7037c478bd9Sstevel@tonic-gate  * Convert an ICMP "type" field to a printable string.
7047c478bd9Sstevel@tonic-gate  */
7057c478bd9Sstevel@tonic-gate char *
7067c478bd9Sstevel@tonic-gate pr_type(int t)
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate 	static char *ttab[] = {
7097c478bd9Sstevel@tonic-gate 		"Echo Reply",
7107c478bd9Sstevel@tonic-gate 		"ICMP 1",
7117c478bd9Sstevel@tonic-gate 		"ICMP 2",
7127c478bd9Sstevel@tonic-gate 		"Dest Unreachable",
7137c478bd9Sstevel@tonic-gate 		"Source Quench",
7147c478bd9Sstevel@tonic-gate 		"Redirect",
7157c478bd9Sstevel@tonic-gate 		"ICMP 6",
7167c478bd9Sstevel@tonic-gate 		"ICMP 7",
7177c478bd9Sstevel@tonic-gate 		"Echo",
7187c478bd9Sstevel@tonic-gate 		"Router Advertise",
7197c478bd9Sstevel@tonic-gate 		"Router Solicitation",
7207c478bd9Sstevel@tonic-gate 		"Time Exceeded",
7217c478bd9Sstevel@tonic-gate 		"Parameter Problem",
7227c478bd9Sstevel@tonic-gate 		"Timestamp",
7237c478bd9Sstevel@tonic-gate 		"Timestamp Reply",
7247c478bd9Sstevel@tonic-gate 		"Info Request",
7257c478bd9Sstevel@tonic-gate 		"Info Reply",
7267c478bd9Sstevel@tonic-gate 		"Netmask Request",
7277c478bd9Sstevel@tonic-gate 		"Netmask Reply"
7287c478bd9Sstevel@tonic-gate 	};
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	if (t < 0 || t > 16)
7317c478bd9Sstevel@tonic-gate 		return ("OUT-OF-RANGE");
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	return (ttab[t]);
7347c478bd9Sstevel@tonic-gate }
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate /*
7377c478bd9Sstevel@tonic-gate  *			P R _ N A M E
7387c478bd9Sstevel@tonic-gate  *
7397c478bd9Sstevel@tonic-gate  * Return a string name for the given IP address.
7407c478bd9Sstevel@tonic-gate  */
7417c478bd9Sstevel@tonic-gate char *
7427c478bd9Sstevel@tonic-gate pr_name(struct in_addr addr)
7437c478bd9Sstevel@tonic-gate {
7447c478bd9Sstevel@tonic-gate 	struct hostent *phe;
7457c478bd9Sstevel@tonic-gate 	static char buf[256];
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	phe = gethostbyaddr((char *)&addr.s_addr, 4, AF_INET);
7487c478bd9Sstevel@tonic-gate 	if (phe == NULL)
7497c478bd9Sstevel@tonic-gate 		return (inet_ntoa(addr));
7507c478bd9Sstevel@tonic-gate 	(void) sprintf(buf, "%s (%s)", phe->h_name, inet_ntoa(addr));
7517c478bd9Sstevel@tonic-gate 	return (buf);
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate /*
7557c478bd9Sstevel@tonic-gate  *			P R _ P A C K
7567c478bd9Sstevel@tonic-gate  *
7577c478bd9Sstevel@tonic-gate  * Print out the packet, if it came from us.  This logic is necessary
7587c478bd9Sstevel@tonic-gate  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
7597c478bd9Sstevel@tonic-gate  * which arrive ('tis only fair).  This permits multiple copies of this
7607c478bd9Sstevel@tonic-gate  * program to be run without having intermingled output (or statistics!).
7617c478bd9Sstevel@tonic-gate  */
7627c478bd9Sstevel@tonic-gate static void
7637c478bd9Sstevel@tonic-gate pr_pack(char *buf, int cc, struct sockaddr_in *from)
7647c478bd9Sstevel@tonic-gate {
7657c478bd9Sstevel@tonic-gate 	struct ip *ip;
7667c478bd9Sstevel@tonic-gate 	register struct icmp *icp;
7677c478bd9Sstevel@tonic-gate 	register int i;
7687c478bd9Sstevel@tonic-gate 	int hlen;
7697c478bd9Sstevel@tonic-gate 	struct logint *li;
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	ip = (struct ip *)ALIGN(buf);
7727c478bd9Sstevel@tonic-gate 	hlen = ip->ip_hl << 2;
7737c478bd9Sstevel@tonic-gate 	if (cc < hlen + ICMP_MINLEN) {
7747c478bd9Sstevel@tonic-gate 		if (verbose)
7757c478bd9Sstevel@tonic-gate 			logtrace("packet too short (%d bytes) from %s\n", cc,
7767c478bd9Sstevel@tonic-gate 				pr_name(from->sin_addr));
7777c478bd9Sstevel@tonic-gate 		return;
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	cc -= hlen;
7817c478bd9Sstevel@tonic-gate 	icp = (struct icmp *)ALIGN(buf + hlen);
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	/*
7847c478bd9Sstevel@tonic-gate 	 * Let's check if IFF_NORTEXCH flag is set on the interface which
7857c478bd9Sstevel@tonic-gate 	 * recevied this packet.
7867c478bd9Sstevel@tonic-gate 	 * TODO: this code can be re-written using one socket per interface
7877c478bd9Sstevel@tonic-gate 	 * to determine which interface the packet is recevied.
7887c478bd9Sstevel@tonic-gate 	 */
7897c478bd9Sstevel@tonic-gate 	li = find_directly_connected_logint(ip->ip_src, NULL);
7907c478bd9Sstevel@tonic-gate 	if (li != NULL && (li->li_flags & IFF_NORTEXCH)) {
7917c478bd9Sstevel@tonic-gate 		if (verbose) {
7927c478bd9Sstevel@tonic-gate 			logtrace("Ignoring received %s on %s "
7937c478bd9Sstevel@tonic-gate 			    "(no route exchange on interface)",
7947c478bd9Sstevel@tonic-gate 			    pr_type((int)icp->icmp_type), li->li_name);
7957c478bd9Sstevel@tonic-gate 		}
7967c478bd9Sstevel@tonic-gate 		return;
7977c478bd9Sstevel@tonic-gate 	}
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	if (ip->ip_p == 0) {
8007c478bd9Sstevel@tonic-gate 		/*
8017c478bd9Sstevel@tonic-gate 		 * Assume that we are running on a pre-4.3BSD system
8027c478bd9Sstevel@tonic-gate 		 * such as SunOS before 4.0
8037c478bd9Sstevel@tonic-gate 		 */
8047c478bd9Sstevel@tonic-gate 		icp = (struct icmp *)ALIGN(buf);
8057c478bd9Sstevel@tonic-gate 	}
8067c478bd9Sstevel@tonic-gate 	switch (icp->icmp_type) {
8077c478bd9Sstevel@tonic-gate 	case ICMP_ROUTERADVERT: {
8087c478bd9Sstevel@tonic-gate 		struct icmp_ra *rap = (struct icmp_ra *)ALIGN(icp);
8097c478bd9Sstevel@tonic-gate 		struct icmp_ra_addr *ap;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 		if (responder)
8127c478bd9Sstevel@tonic-gate 			break;
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 		/* TBD verify that the link is multicast or broadcast */
8157c478bd9Sstevel@tonic-gate 		/* XXX Find out the link it came in over? */
8167c478bd9Sstevel@tonic-gate #ifdef notdef
8177c478bd9Sstevel@tonic-gate 		if (debug) {
8187c478bd9Sstevel@tonic-gate 			logdebug("ROUTER_ADVERTISEMENT: \n");
8197c478bd9Sstevel@tonic-gate 			pr_hex(buf+hlen, cc);
8207c478bd9Sstevel@tonic-gate 		}
8217c478bd9Sstevel@tonic-gate #endif /* notdef */
8227c478bd9Sstevel@tonic-gate 		if (in_cksum((ushort_t *)ALIGN(buf+hlen), cc)) {
8237c478bd9Sstevel@tonic-gate 			if (verbose)
8247c478bd9Sstevel@tonic-gate 				logtrace("ICMP %s from %s: Bad checksum\n",
8257c478bd9Sstevel@tonic-gate 					pr_type((int)rap->icmp_type),
8267c478bd9Sstevel@tonic-gate 					pr_name(from->sin_addr));
8277c478bd9Sstevel@tonic-gate 			return;
8287c478bd9Sstevel@tonic-gate 		}
8297c478bd9Sstevel@tonic-gate 		if (rap->icmp_code != 0) {
8307c478bd9Sstevel@tonic-gate 			if (verbose)
8317c478bd9Sstevel@tonic-gate 				logtrace("ICMP %s from %s: Code = %d\n",
8327c478bd9Sstevel@tonic-gate 					pr_type((int)rap->icmp_type),
8337c478bd9Sstevel@tonic-gate 					pr_name(from->sin_addr),
8347c478bd9Sstevel@tonic-gate 					rap->icmp_code);
8357c478bd9Sstevel@tonic-gate 			return;
8367c478bd9Sstevel@tonic-gate 		}
8377c478bd9Sstevel@tonic-gate 		if (rap->icmp_num_addrs < 1) {
8387c478bd9Sstevel@tonic-gate 			if (verbose)
8397c478bd9Sstevel@tonic-gate 				logtrace("ICMP %s from %s: No addresses\n",
8407c478bd9Sstevel@tonic-gate 					pr_type((int)rap->icmp_type),
8417c478bd9Sstevel@tonic-gate 					pr_name(from->sin_addr));
8427c478bd9Sstevel@tonic-gate 			return;
8437c478bd9Sstevel@tonic-gate 		}
8447c478bd9Sstevel@tonic-gate 		if (rap->icmp_wpa < 2) {
8457c478bd9Sstevel@tonic-gate 			if (verbose)
8467c478bd9Sstevel@tonic-gate 				logtrace("ICMP %s from %s: Words/addr = %d\n",
8477c478bd9Sstevel@tonic-gate 					pr_type((int)rap->icmp_type),
8487c478bd9Sstevel@tonic-gate 					pr_name(from->sin_addr),
8497c478bd9Sstevel@tonic-gate 					rap->icmp_wpa);
8507c478bd9Sstevel@tonic-gate 			return;
8517c478bd9Sstevel@tonic-gate 		}
8527c478bd9Sstevel@tonic-gate 		if ((unsigned)cc <
8537c478bd9Sstevel@tonic-gate 		    ICMP_MINLEN + rap->icmp_num_addrs * rap->icmp_wpa * 4) {
8547c478bd9Sstevel@tonic-gate 			if (verbose)
8557c478bd9Sstevel@tonic-gate 				logtrace("ICMP %s from %s: Too short %d, %d\n",
8567c478bd9Sstevel@tonic-gate 					pr_type((int)rap->icmp_type),
8577c478bd9Sstevel@tonic-gate 					pr_name(from->sin_addr),
8587c478bd9Sstevel@tonic-gate 					cc,
8597c478bd9Sstevel@tonic-gate 					ICMP_MINLEN +
8607c478bd9Sstevel@tonic-gate 					rap->icmp_num_addrs *
8617c478bd9Sstevel@tonic-gate 					rap->icmp_wpa * 4);
8627c478bd9Sstevel@tonic-gate 			return;
8637c478bd9Sstevel@tonic-gate 		}
8647c478bd9Sstevel@tonic-gate 		rap->icmp_lifetime = ntohs(rap->icmp_lifetime);
8657c478bd9Sstevel@tonic-gate 		if ((rap->icmp_lifetime < 4 && rap->icmp_lifetime != 0) ||
8667c478bd9Sstevel@tonic-gate 		    rap->icmp_lifetime > 9000) {
8677c478bd9Sstevel@tonic-gate 			if (verbose)
8687c478bd9Sstevel@tonic-gate 			    logtrace("ICMP %s from %s: Invalid lifetime %d\n",
8697c478bd9Sstevel@tonic-gate 					pr_type((int)rap->icmp_type),
8707c478bd9Sstevel@tonic-gate 					pr_name(from->sin_addr),
8717c478bd9Sstevel@tonic-gate 					rap->icmp_lifetime);
8727c478bd9Sstevel@tonic-gate 			return;
8737c478bd9Sstevel@tonic-gate 		}
8747c478bd9Sstevel@tonic-gate 		if (verbose)
8757c478bd9Sstevel@tonic-gate 			logtrace("ICMP %s from %s, lifetime %d\n",
8767c478bd9Sstevel@tonic-gate 				pr_type((int)rap->icmp_type),
8777c478bd9Sstevel@tonic-gate 				pr_name(from->sin_addr),
8787c478bd9Sstevel@tonic-gate 				rap->icmp_lifetime);
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 		/*
8817c478bd9Sstevel@tonic-gate 		 * Check that at least one router address is a neighbor
8827c478bd9Sstevel@tonic-gate 		 * on the arriving link.
8837c478bd9Sstevel@tonic-gate 		 */
8847c478bd9Sstevel@tonic-gate 		for (i = 0; (unsigned)i < rap->icmp_num_addrs; i++) {
8857c478bd9Sstevel@tonic-gate 			struct in_addr ina;
8867c478bd9Sstevel@tonic-gate 			ap = (struct icmp_ra_addr *)
8877c478bd9Sstevel@tonic-gate 				ALIGN(buf + hlen + ICMP_MINLEN +
8887c478bd9Sstevel@tonic-gate 					i * rap->icmp_wpa * 4);
8897c478bd9Sstevel@tonic-gate 			ap->preference = ntohl(ap->preference);
8907c478bd9Sstevel@tonic-gate 			ina.s_addr = ap->addr;
8917c478bd9Sstevel@tonic-gate 			if (verbose)
8927c478bd9Sstevel@tonic-gate 				logtrace("\taddress %s, preference 0x%x\n",
8937c478bd9Sstevel@tonic-gate 					pr_name(ina),
8947c478bd9Sstevel@tonic-gate 					ap->preference);
8957c478bd9Sstevel@tonic-gate 			if (!responder) {
8967c478bd9Sstevel@tonic-gate 				if (find_directly_connected_logint(ina, NULL) !=
8977c478bd9Sstevel@tonic-gate 				    NULL) {
8987c478bd9Sstevel@tonic-gate 					record_router(ina,
8997c478bd9Sstevel@tonic-gate 					    (long)ap->preference,
9007c478bd9Sstevel@tonic-gate 					    rap->icmp_lifetime);
9017c478bd9Sstevel@tonic-gate 				}
9027c478bd9Sstevel@tonic-gate 			}
9037c478bd9Sstevel@tonic-gate 		}
9047c478bd9Sstevel@tonic-gate 		nreceived++;
9057c478bd9Sstevel@tonic-gate 		if (!forever) {
9067c478bd9Sstevel@tonic-gate 			(void) alarm(0);
9077c478bd9Sstevel@tonic-gate 			do_fork();
9087c478bd9Sstevel@tonic-gate 			forever = 1;
9097c478bd9Sstevel@tonic-gate 			(void) alarm(TIMER_INTERVAL);
9107c478bd9Sstevel@tonic-gate 		}
9117c478bd9Sstevel@tonic-gate 		break;
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	case ICMP_ROUTERSOLICIT: {
9157c478bd9Sstevel@tonic-gate 		struct sockaddr_in sin;
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 		if (!responder)
9187c478bd9Sstevel@tonic-gate 			break;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 		/* TBD verify that the link is multicast or broadcast */
9217c478bd9Sstevel@tonic-gate 		/* XXX Find out the link it came in over? */
9227c478bd9Sstevel@tonic-gate #ifdef notdef
9237c478bd9Sstevel@tonic-gate 		if (debug) {
9247c478bd9Sstevel@tonic-gate 			logdebug("ROUTER_SOLICITATION: \n");
9257c478bd9Sstevel@tonic-gate 			pr_hex(buf+hlen, cc);
9267c478bd9Sstevel@tonic-gate 		}
9277c478bd9Sstevel@tonic-gate #endif /* notdef */
9287c478bd9Sstevel@tonic-gate 		if (in_cksum((ushort_t *)ALIGN(buf+hlen), cc)) {
9297c478bd9Sstevel@tonic-gate 			if (verbose)
9307c478bd9Sstevel@tonic-gate 				logtrace("ICMP %s from %s: Bad checksum\n",
9317c478bd9Sstevel@tonic-gate 					pr_type((int)icp->icmp_type),
9327c478bd9Sstevel@tonic-gate 					pr_name(from->sin_addr));
9337c478bd9Sstevel@tonic-gate 			return;
9347c478bd9Sstevel@tonic-gate 		}
9357c478bd9Sstevel@tonic-gate 		if (icp->icmp_code != 0) {
9367c478bd9Sstevel@tonic-gate 			if (verbose)
9377c478bd9Sstevel@tonic-gate 				logtrace("ICMP %s from %s: Code = %d\n",
9387c478bd9Sstevel@tonic-gate 					pr_type((int)icp->icmp_type),
9397c478bd9Sstevel@tonic-gate 					pr_name(from->sin_addr),
9407c478bd9Sstevel@tonic-gate 					icp->icmp_code);
9417c478bd9Sstevel@tonic-gate 			return;
9427c478bd9Sstevel@tonic-gate 		}
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 		if (cc < ICMP_MINLEN) {
9457c478bd9Sstevel@tonic-gate 			if (verbose)
9467c478bd9Sstevel@tonic-gate 				logtrace("ICMP %s from %s: Too short %d, %d\n",
9477c478bd9Sstevel@tonic-gate 					pr_type((int)icp->icmp_type),
9487c478bd9Sstevel@tonic-gate 					pr_name(from->sin_addr),
9497c478bd9Sstevel@tonic-gate 					cc,
9507c478bd9Sstevel@tonic-gate 					ICMP_MINLEN);
9517c478bd9Sstevel@tonic-gate 			return;
9527c478bd9Sstevel@tonic-gate 		}
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 		if (verbose)
9557c478bd9Sstevel@tonic-gate 			logtrace("ICMP %s from %s\n",
9567c478bd9Sstevel@tonic-gate 				pr_type((int)icp->icmp_type),
9577c478bd9Sstevel@tonic-gate 				pr_name(from->sin_addr));
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 		if (!responder)
9607c478bd9Sstevel@tonic-gate 			break;
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 		/*
9637c478bd9Sstevel@tonic-gate 		 * Check that ip_src is either a neighbor
9647c478bd9Sstevel@tonic-gate 		 * on the arriving link or 0.
9657c478bd9Sstevel@tonic-gate 		 */
9667c478bd9Sstevel@tonic-gate 		sin.sin_family = AF_INET;
9677c478bd9Sstevel@tonic-gate 		if (ip->ip_src.s_addr == 0) {
9687c478bd9Sstevel@tonic-gate 			/*
9697c478bd9Sstevel@tonic-gate 			 * If it was sent to the broadcast address we respond
9707c478bd9Sstevel@tonic-gate 			 * to the broadcast address.
9717c478bd9Sstevel@tonic-gate 			 */
9727c478bd9Sstevel@tonic-gate 			if (IN_CLASSD(ntohl(ip->ip_dst.s_addr))) {
9737c478bd9Sstevel@tonic-gate 				sin.sin_addr.s_addr =
9747c478bd9Sstevel@tonic-gate 				    htonl(INADDR_ALLHOSTS_GROUP);
9757c478bd9Sstevel@tonic-gate 			} else
9767c478bd9Sstevel@tonic-gate 				sin.sin_addr.s_addr = htonl(INADDR_BROADCAST);
9777c478bd9Sstevel@tonic-gate 			/* Restart the timer when we broadcast */
9787c478bd9Sstevel@tonic-gate 			left_until_advertise = min_adv_int +
9797c478bd9Sstevel@tonic-gate 				((max_adv_int - min_adv_int)
9807c478bd9Sstevel@tonic-gate 				 * (random() % 1000)/1000);
9817c478bd9Sstevel@tonic-gate 		} else {
9827c478bd9Sstevel@tonic-gate 			if (li == NULL) {
9837c478bd9Sstevel@tonic-gate 				if (verbose)
9847c478bd9Sstevel@tonic-gate 					logtrace("ICMP %s from %s: %s\n",
9857c478bd9Sstevel@tonic-gate 						pr_type((int)icp->icmp_type),
9867c478bd9Sstevel@tonic-gate 						pr_name(from->sin_addr),
9877c478bd9Sstevel@tonic-gate 					"source not directly connected");
9887c478bd9Sstevel@tonic-gate 				break;
9897c478bd9Sstevel@tonic-gate 			}
9907c478bd9Sstevel@tonic-gate 			sin.sin_addr.s_addr = ip->ip_src.s_addr;
9917c478bd9Sstevel@tonic-gate 		}
9927c478bd9Sstevel@tonic-gate 		nreceived++;
9937c478bd9Sstevel@tonic-gate 		ntransmitted++;
9947c478bd9Sstevel@tonic-gate 		advertise(&sin);
9957c478bd9Sstevel@tonic-gate 		break;
9967c478bd9Sstevel@tonic-gate 	}
9977c478bd9Sstevel@tonic-gate 	}
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate /*
10027c478bd9Sstevel@tonic-gate  *			I N _ C K S U M
10037c478bd9Sstevel@tonic-gate  *
10047c478bd9Sstevel@tonic-gate  * Checksum routine for Internet Protocol family headers (C Version)
10057c478bd9Sstevel@tonic-gate  *
10067c478bd9Sstevel@tonic-gate  */
10077c478bd9Sstevel@tonic-gate int
10087c478bd9Sstevel@tonic-gate in_cksum(ushort_t *addr, int len)
10097c478bd9Sstevel@tonic-gate {
10107c478bd9Sstevel@tonic-gate 	register int nleft = len;
10117c478bd9Sstevel@tonic-gate 	register ushort_t *w = addr;
10127c478bd9Sstevel@tonic-gate 	register ushort_t answer;
10137c478bd9Sstevel@tonic-gate 	ushort_t odd_byte = 0;
10147c478bd9Sstevel@tonic-gate 	register int sum = 0;
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	/*
10177c478bd9Sstevel@tonic-gate 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
10187c478bd9Sstevel@tonic-gate 	 *  we add sequential 16 bit words to it, and at the end, fold
10197c478bd9Sstevel@tonic-gate 	 *  back all the carry bits from the top 16 bits into the lower
10207c478bd9Sstevel@tonic-gate 	 *  16 bits.
10217c478bd9Sstevel@tonic-gate 	 */
10227c478bd9Sstevel@tonic-gate 	while (nleft > 1)  {
10237c478bd9Sstevel@tonic-gate 		sum += *w++;
10247c478bd9Sstevel@tonic-gate 		nleft -= 2;
10257c478bd9Sstevel@tonic-gate 	}
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	/* mop up an odd byte, if necessary */
10287c478bd9Sstevel@tonic-gate 	if (nleft == 1) {
10297c478bd9Sstevel@tonic-gate 		*(uchar_t *)(&odd_byte) = *(uchar_t *)w;
10307c478bd9Sstevel@tonic-gate 		sum += odd_byte;
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	/*
10347c478bd9Sstevel@tonic-gate 	 * add back carry outs from top 16 bits to low 16 bits
10357c478bd9Sstevel@tonic-gate 	 */
10367c478bd9Sstevel@tonic-gate 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
10377c478bd9Sstevel@tonic-gate 	sum += (sum >> 16);			/* add carry */
10387c478bd9Sstevel@tonic-gate 	answer = ~sum;				/* truncate to 16 bits */
10397c478bd9Sstevel@tonic-gate 	return (answer);
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate /*
10437c478bd9Sstevel@tonic-gate  *			F I N I S H
10447c478bd9Sstevel@tonic-gate  *
10457c478bd9Sstevel@tonic-gate  * Print out statistics, and give up.
10467c478bd9Sstevel@tonic-gate  * Heavily buffered stdio is used here, so that all the statistics
10477c478bd9Sstevel@tonic-gate  * will be written with 1 sys-write call.  This is nice when more
10487c478bd9Sstevel@tonic-gate  * than one copy of the program is running on a terminal;  it prevents
10497c478bd9Sstevel@tonic-gate  * the statistics output from becoming intermingled.
10507c478bd9Sstevel@tonic-gate  */
10517c478bd9Sstevel@tonic-gate static void
10527c478bd9Sstevel@tonic-gate finish(void)
10537c478bd9Sstevel@tonic-gate {
10547c478bd9Sstevel@tonic-gate 	if (responder) {
10557c478bd9Sstevel@tonic-gate 		/*
10567c478bd9Sstevel@tonic-gate 		 * Send out a packet with a preference so that all
10577c478bd9Sstevel@tonic-gate 		 * hosts will know that we are dead.
10587c478bd9Sstevel@tonic-gate 		 */
10597c478bd9Sstevel@tonic-gate 		logerr("terminated\n");
10607c478bd9Sstevel@tonic-gate 		force_preference(IGNORE_PREFERENCE);
10617c478bd9Sstevel@tonic-gate 		ntransmitted++;
10627c478bd9Sstevel@tonic-gate 		advertise(&whereto);
10637c478bd9Sstevel@tonic-gate 	}
10647c478bd9Sstevel@tonic-gate 	if (verbose) {
10657c478bd9Sstevel@tonic-gate 		logtrace("\n----%s rdisc Statistics----\n", sendaddress);
10667c478bd9Sstevel@tonic-gate 		logtrace("%d packets transmitted, ", ntransmitted);
10677c478bd9Sstevel@tonic-gate 		logtrace("%d packets received, ", nreceived);
10687c478bd9Sstevel@tonic-gate 		logtrace("\n");
10697c478bd9Sstevel@tonic-gate 	}
10707c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
10717c478bd9Sstevel@tonic-gate 	exit(0);
10727c478bd9Sstevel@tonic-gate }
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate #include <ctype.h>
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate #ifdef notdef
10777c478bd9Sstevel@tonic-gate int
10787c478bd9Sstevel@tonic-gate pr_hex(unsigned char *data, int len)
10797c478bd9Sstevel@tonic-gate {
10807c478bd9Sstevel@tonic-gate 	FILE *out;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	out = stdout;
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	while (len) {
10857c478bd9Sstevel@tonic-gate 		register int i;
10867c478bd9Sstevel@tonic-gate 		char charstring[17];
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 		(void) strcpy(charstring, "                "); /* 16 spaces */
10897c478bd9Sstevel@tonic-gate 		for (i = 0; i < 16; i++) {
10907c478bd9Sstevel@tonic-gate 			/*
10917c478bd9Sstevel@tonic-gate 			 * output the bytes one at a time,
10927c478bd9Sstevel@tonic-gate 			 * not going past "len" bytes
10937c478bd9Sstevel@tonic-gate 			 */
10947c478bd9Sstevel@tonic-gate 			if (len) {
10957c478bd9Sstevel@tonic-gate 				char ch = *data & 0x7f; /* strip parity */
10967c478bd9Sstevel@tonic-gate 				if (!isprint((uchar_t)ch))
10977c478bd9Sstevel@tonic-gate 					ch = ' '; /* ensure printable */
10987c478bd9Sstevel@tonic-gate 				charstring[i] = ch;
10997c478bd9Sstevel@tonic-gate 				(void) fprintf(out, "%02x ", *data++);
11007c478bd9Sstevel@tonic-gate 				len--;
11017c478bd9Sstevel@tonic-gate 			} else
11027c478bd9Sstevel@tonic-gate 				(void) fprintf(out, "   ");
11037c478bd9Sstevel@tonic-gate 			if (i == 7)
11047c478bd9Sstevel@tonic-gate 				(void) fprintf(out, "   ");
11057c478bd9Sstevel@tonic-gate 		}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 		(void) fprintf(out, "    *%s*\n", charstring);
11087c478bd9Sstevel@tonic-gate 	}
11097c478bd9Sstevel@tonic-gate }
11107c478bd9Sstevel@tonic-gate #endif /* notdef */
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate static int
11137c478bd9Sstevel@tonic-gate isbroadcast(struct sockaddr_in *sin)
11147c478bd9Sstevel@tonic-gate {
11157c478bd9Sstevel@tonic-gate 	return (sin->sin_addr.s_addr == htonl(INADDR_BROADCAST));
11167c478bd9Sstevel@tonic-gate }
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate static int
11197c478bd9Sstevel@tonic-gate ismulticast(struct sockaddr_in *sin)
11207c478bd9Sstevel@tonic-gate {
11217c478bd9Sstevel@tonic-gate 	return (IN_CLASSD(ntohl(sin->sin_addr.s_addr)));
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate /* From libc/rpc/pmap_rmt.c */
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate /* Only send once per physical interface */
11287c478bd9Sstevel@tonic-gate static int
11297c478bd9Sstevel@tonic-gate sendbcast(int s, char *packet, int packetlen)
11307c478bd9Sstevel@tonic-gate {
11317c478bd9Sstevel@tonic-gate 	struct phyint *pi;
11327c478bd9Sstevel@tonic-gate 	struct logint *li;
11337c478bd9Sstevel@tonic-gate 	boolean_t bcast;
11347c478bd9Sstevel@tonic-gate 	int cc;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
11377c478bd9Sstevel@tonic-gate 		bcast = B_FALSE;
11387c478bd9Sstevel@tonic-gate 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
11397c478bd9Sstevel@tonic-gate 			if (li->li_state & ST_DELETED)
11407c478bd9Sstevel@tonic-gate 				continue;
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 			if (li->li_flags & IFF_BROADCAST) {
11437c478bd9Sstevel@tonic-gate 				bcast = B_TRUE;
11447c478bd9Sstevel@tonic-gate 				break;
11457c478bd9Sstevel@tonic-gate 			}
11467c478bd9Sstevel@tonic-gate 		}
11477c478bd9Sstevel@tonic-gate 		if (!bcast)
11487c478bd9Sstevel@tonic-gate 			continue;
11497c478bd9Sstevel@tonic-gate 		cc = sendbcastif(s, packet, packetlen, li);
11507c478bd9Sstevel@tonic-gate 		if (cc != packetlen) {
11517c478bd9Sstevel@tonic-gate 			return (cc);
11527c478bd9Sstevel@tonic-gate 		}
11537c478bd9Sstevel@tonic-gate 	}
11547c478bd9Sstevel@tonic-gate 	return (packetlen);
11557c478bd9Sstevel@tonic-gate }
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate static int
11587c478bd9Sstevel@tonic-gate sendbcastif(int s, char *packet, int packetlen, struct logint *li)
11597c478bd9Sstevel@tonic-gate {
11607c478bd9Sstevel@tonic-gate 	int cc;
11617c478bd9Sstevel@tonic-gate 	struct sockaddr_in baddr;
11627c478bd9Sstevel@tonic-gate 	struct icmp *icp = (struct icmp *)ALIGN(packet);
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	baddr.sin_family = AF_INET;
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	if ((li->li_flags & IFF_BROADCAST) == 0) {
11677c478bd9Sstevel@tonic-gate 		if (verbose) {
11687c478bd9Sstevel@tonic-gate 			logtrace("Suppressing sending %s on %s "
11697c478bd9Sstevel@tonic-gate 			    "(interface is not broadcast capable)\n",
11707c478bd9Sstevel@tonic-gate 			    pr_type((int)icp->icmp_type), li->li_name);
11717c478bd9Sstevel@tonic-gate 		}
11727c478bd9Sstevel@tonic-gate 		return (packetlen);
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate 	if (li->li_flags & IFF_NORTEXCH) {
11757c478bd9Sstevel@tonic-gate 		if (verbose) {
11767c478bd9Sstevel@tonic-gate 			logtrace("Suppressing sending %s on %s "
11777c478bd9Sstevel@tonic-gate 			    "(no route exchange on interface)\n",
11787c478bd9Sstevel@tonic-gate 			    pr_type((int)icp->icmp_type), li->li_name);
11797c478bd9Sstevel@tonic-gate 		}
11807c478bd9Sstevel@tonic-gate 		return (packetlen);
11817c478bd9Sstevel@tonic-gate 	}
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	baddr.sin_addr = li->li_bcastaddr;
11847c478bd9Sstevel@tonic-gate 	if (debug)
11857c478bd9Sstevel@tonic-gate 		logdebug("Broadcast to %s\n",
11867c478bd9Sstevel@tonic-gate 			pr_name(baddr.sin_addr));
11877c478bd9Sstevel@tonic-gate 	cc = sendto(s, packet, packetlen, 0,
11887c478bd9Sstevel@tonic-gate 	    (struct sockaddr *)&baddr, sizeof (struct sockaddr));
11897c478bd9Sstevel@tonic-gate 	if (cc != packetlen) {
11907c478bd9Sstevel@tonic-gate 		logperror("sendbcast: sendto");
11917c478bd9Sstevel@tonic-gate 		logerr("Cannot send broadcast packet to %s\n",
11927c478bd9Sstevel@tonic-gate 			pr_name(baddr.sin_addr));
11937c478bd9Sstevel@tonic-gate 	}
11947c478bd9Sstevel@tonic-gate 	return (cc);
11957c478bd9Sstevel@tonic-gate }
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate static int
11987c478bd9Sstevel@tonic-gate sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *sin)
11997c478bd9Sstevel@tonic-gate {
12007c478bd9Sstevel@tonic-gate 	struct phyint *pi;
12017c478bd9Sstevel@tonic-gate 	struct logint *li;
12027c478bd9Sstevel@tonic-gate 	boolean_t mcast;
12037c478bd9Sstevel@tonic-gate 	int cc;
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
12067c478bd9Sstevel@tonic-gate 		mcast = B_FALSE;
12077c478bd9Sstevel@tonic-gate 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
12087c478bd9Sstevel@tonic-gate 			if (li->li_state & ST_DELETED)
12097c478bd9Sstevel@tonic-gate 				continue;
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 			if (li->li_flags & IFF_MULTICAST) {
12127c478bd9Sstevel@tonic-gate 				mcast = B_TRUE;
12137c478bd9Sstevel@tonic-gate 				break;
12147c478bd9Sstevel@tonic-gate 			}
12157c478bd9Sstevel@tonic-gate 		}
12167c478bd9Sstevel@tonic-gate 		if (!mcast)
12177c478bd9Sstevel@tonic-gate 			continue;
12187c478bd9Sstevel@tonic-gate 		cc = sendmcastif(s, packet, packetlen, sin, li);
12197c478bd9Sstevel@tonic-gate 		if (cc != packetlen) {
12207c478bd9Sstevel@tonic-gate 			return (cc);
12217c478bd9Sstevel@tonic-gate 		}
12227c478bd9Sstevel@tonic-gate 	}
12237c478bd9Sstevel@tonic-gate 	return (packetlen);
12247c478bd9Sstevel@tonic-gate }
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate static int
12277c478bd9Sstevel@tonic-gate sendmcastif(int s, char *packet, int packetlen, struct sockaddr_in *sin,
12287c478bd9Sstevel@tonic-gate     struct logint *li)
12297c478bd9Sstevel@tonic-gate {
12307c478bd9Sstevel@tonic-gate 	int cc;
12317c478bd9Sstevel@tonic-gate 	struct sockaddr_in ifaddr;
12327c478bd9Sstevel@tonic-gate 	struct icmp *icp = (struct icmp *)ALIGN(packet);
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	ifaddr.sin_family = AF_INET;
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	if ((li->li_flags & IFF_MULTICAST) == 0) {
12377c478bd9Sstevel@tonic-gate 		if (verbose) {
12387c478bd9Sstevel@tonic-gate 			logtrace("Suppressing sending %s on %s "
12397c478bd9Sstevel@tonic-gate 			    "(interface is not multicast capable)\n",
12407c478bd9Sstevel@tonic-gate 			    pr_type((int)icp->icmp_type), li->li_name);
12417c478bd9Sstevel@tonic-gate 		}
12427c478bd9Sstevel@tonic-gate 		return (packetlen);
12437c478bd9Sstevel@tonic-gate 	}
12447c478bd9Sstevel@tonic-gate 	if (li->li_flags & IFF_NORTEXCH) {
12457c478bd9Sstevel@tonic-gate 		if (verbose) {
12467c478bd9Sstevel@tonic-gate 			logtrace("Suppressing sending %s on %s "
12477c478bd9Sstevel@tonic-gate 			    "(no route exchange on interface)\n",
12487c478bd9Sstevel@tonic-gate 			    pr_type((int)icp->icmp_type), li->li_name);
12497c478bd9Sstevel@tonic-gate 		}
12507c478bd9Sstevel@tonic-gate 		return (packetlen);
12517c478bd9Sstevel@tonic-gate 	}
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	ifaddr.sin_addr = li->li_address;
12547c478bd9Sstevel@tonic-gate 	if (debug)
12557c478bd9Sstevel@tonic-gate 		logdebug("Multicast to interface %s\n",
12567c478bd9Sstevel@tonic-gate 			pr_name(ifaddr.sin_addr));
12577c478bd9Sstevel@tonic-gate 	if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
12587c478bd9Sstevel@tonic-gate 	    (char *)&ifaddr.sin_addr,
12597c478bd9Sstevel@tonic-gate 	    sizeof (ifaddr.sin_addr)) < 0) {
12607c478bd9Sstevel@tonic-gate 		logperror("setsockopt (IP_MULTICAST_IF)");
12617c478bd9Sstevel@tonic-gate 		logerr("Cannot send multicast packet over interface %s\n",
12627c478bd9Sstevel@tonic-gate 			pr_name(ifaddr.sin_addr));
12637c478bd9Sstevel@tonic-gate 		return (-1);
12647c478bd9Sstevel@tonic-gate 	}
12657c478bd9Sstevel@tonic-gate 	cc = sendto(s, packet, packetlen, 0,
12667c478bd9Sstevel@tonic-gate 	    (struct sockaddr *)sin, sizeof (struct sockaddr));
12677c478bd9Sstevel@tonic-gate 	if (cc != packetlen) {
12687c478bd9Sstevel@tonic-gate 		logperror("sendmcast: sendto");
12697c478bd9Sstevel@tonic-gate 		logerr("Cannot send multicast packet over interface %s\n",
12707c478bd9Sstevel@tonic-gate 			pr_name(ifaddr.sin_addr));
12717c478bd9Sstevel@tonic-gate 	}
12727c478bd9Sstevel@tonic-gate 	return (cc);
12737c478bd9Sstevel@tonic-gate }
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate static void
12767c478bd9Sstevel@tonic-gate reinitifs(void)
12777c478bd9Sstevel@tonic-gate {
12787c478bd9Sstevel@tonic-gate 	(void) initifs(s, &g_joinaddr, g_preference);
12797c478bd9Sstevel@tonic-gate }
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate static void
12827c478bd9Sstevel@tonic-gate force_preference(int preference)
12837c478bd9Sstevel@tonic-gate {
12847c478bd9Sstevel@tonic-gate 	struct phyint *pi;
12857c478bd9Sstevel@tonic-gate 	struct logint *li;
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
12887c478bd9Sstevel@tonic-gate 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
12897c478bd9Sstevel@tonic-gate 			if (li->li_state & ST_DELETED)
12907c478bd9Sstevel@tonic-gate 				continue;
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 			li->li_preference = preference;
12937c478bd9Sstevel@tonic-gate 		}
12947c478bd9Sstevel@tonic-gate 	}
12957c478bd9Sstevel@tonic-gate }
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate /*
12987c478bd9Sstevel@tonic-gate  * Returns -1 on failure.
12997c478bd9Sstevel@tonic-gate  */
13007c478bd9Sstevel@tonic-gate static int
13017c478bd9Sstevel@tonic-gate initifs(int s, struct sockaddr_in *joinaddr, int preference)
13027c478bd9Sstevel@tonic-gate {
13037c478bd9Sstevel@tonic-gate 	struct ifconf ifc;
13047c478bd9Sstevel@tonic-gate 	struct ifreq ifreq, *ifr;
13057c478bd9Sstevel@tonic-gate 	struct lifreq lifreq;
13067c478bd9Sstevel@tonic-gate 	int n;
13077c478bd9Sstevel@tonic-gate 	char *buf;
13087c478bd9Sstevel@tonic-gate 	int numifs;
13097c478bd9Sstevel@tonic-gate 	unsigned bufsize;
13107c478bd9Sstevel@tonic-gate 	struct phyint *pi;
13117c478bd9Sstevel@tonic-gate 	struct logint *li;
13127c478bd9Sstevel@tonic-gate 	int num_deletions;
13137c478bd9Sstevel@tonic-gate 	char phyintname[IFNAMSIZ];
13147c478bd9Sstevel@tonic-gate 	char *cp;
13157c478bd9Sstevel@tonic-gate 	int old_num_usable_interfaces = num_usable_interfaces;
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 	/*
13187c478bd9Sstevel@tonic-gate 	 * Mark all interfaces so that we can determine which ones
13197c478bd9Sstevel@tonic-gate 	 * have gone away.
13207c478bd9Sstevel@tonic-gate 	 */
13217c478bd9Sstevel@tonic-gate 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
13227c478bd9Sstevel@tonic-gate 		pi->pi_state |= ST_MARKED;
13237c478bd9Sstevel@tonic-gate 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
13247c478bd9Sstevel@tonic-gate 			li->li_state |= ST_MARKED;
13257c478bd9Sstevel@tonic-gate 		}
13267c478bd9Sstevel@tonic-gate 	}
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 	if (sock < 0) {
13297c478bd9Sstevel@tonic-gate 		sock = socket(AF_INET, SOCK_DGRAM, 0);
13307c478bd9Sstevel@tonic-gate 		if (sock < 0) {
13317c478bd9Sstevel@tonic-gate 			logperror("initifs: socket");
13327c478bd9Sstevel@tonic-gate 			return (-1);
13337c478bd9Sstevel@tonic-gate 		}
13347c478bd9Sstevel@tonic-gate 	}
13357c478bd9Sstevel@tonic-gate #ifdef SIOCGIFNUM
13367c478bd9Sstevel@tonic-gate 	if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) {
13377c478bd9Sstevel@tonic-gate 		logperror("initifs: SIOCGIFNUM");
13387c478bd9Sstevel@tonic-gate 		return (-1);
13397c478bd9Sstevel@tonic-gate 	}
13407c478bd9Sstevel@tonic-gate #else
13417c478bd9Sstevel@tonic-gate 	numifs = MAXIFS;
13427c478bd9Sstevel@tonic-gate #endif
13437c478bd9Sstevel@tonic-gate 	bufsize = numifs * sizeof (struct ifreq);
13447c478bd9Sstevel@tonic-gate 	buf = (char *)malloc(bufsize);
13457c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
13467c478bd9Sstevel@tonic-gate 		logerr("out of memory\n");
13477c478bd9Sstevel@tonic-gate 		(void) close(sock);
13487c478bd9Sstevel@tonic-gate 		sock = -1;
13497c478bd9Sstevel@tonic-gate 		return (-1);
13507c478bd9Sstevel@tonic-gate 	}
13517c478bd9Sstevel@tonic-gate 	ifc.ifc_len = bufsize;
13527c478bd9Sstevel@tonic-gate 	ifc.ifc_buf = buf;
13537c478bd9Sstevel@tonic-gate 	if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
13547c478bd9Sstevel@tonic-gate 		logperror("initifs: ioctl (get interface configuration)");
13557c478bd9Sstevel@tonic-gate 		(void) close(sock);
13567c478bd9Sstevel@tonic-gate 		sock = -1;
13577c478bd9Sstevel@tonic-gate 		(void) free(buf);
13587c478bd9Sstevel@tonic-gate 		return (-1);
13597c478bd9Sstevel@tonic-gate 	}
13607c478bd9Sstevel@tonic-gate 	ifr = ifc.ifc_req;
13617c478bd9Sstevel@tonic-gate 	for (n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
13627c478bd9Sstevel@tonic-gate 		ifreq = *ifr;
13637c478bd9Sstevel@tonic-gate 		/*
13647c478bd9Sstevel@tonic-gate 		 * We need to use new interface ioctls to get 64-bit flags.
13657c478bd9Sstevel@tonic-gate 		 */
13667c478bd9Sstevel@tonic-gate 		(void) strncpy(lifreq.lifr_name, ifr->ifr_name,
13677c478bd9Sstevel@tonic-gate 		    sizeof (ifr->ifr_name));
13687c478bd9Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
13697c478bd9Sstevel@tonic-gate 			logperror("initifs: ioctl (get interface flags)");
13707c478bd9Sstevel@tonic-gate 			continue;
13717c478bd9Sstevel@tonic-gate 		}
13727c478bd9Sstevel@tonic-gate 		if (ifr->ifr_addr.sa_family != AF_INET)
13737c478bd9Sstevel@tonic-gate 			continue;
13747c478bd9Sstevel@tonic-gate 		if ((lifreq.lifr_flags & IFF_UP) == 0)
13757c478bd9Sstevel@tonic-gate 			continue;
13767c478bd9Sstevel@tonic-gate 		if (lifreq.lifr_flags & IFF_LOOPBACK)
13777c478bd9Sstevel@tonic-gate 			continue;
13787c478bd9Sstevel@tonic-gate 		if ((lifreq.lifr_flags & (IFF_MULTICAST | IFF_BROADCAST)) == 0)
13797c478bd9Sstevel@tonic-gate 			continue;
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 		/* Create the physical name by truncating at the ':' */
13827c478bd9Sstevel@tonic-gate 		strncpy(phyintname, ifreq.ifr_name, sizeof (phyintname));
13837c478bd9Sstevel@tonic-gate 		if ((cp = strchr(phyintname, ':')) != NULL)
13847c478bd9Sstevel@tonic-gate 			*cp = '\0';
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 		pi = find_phyint(phyintname);
13877c478bd9Sstevel@tonic-gate 		if (pi == NULL) {
13887c478bd9Sstevel@tonic-gate 			pi = add_phyint(phyintname);
13897c478bd9Sstevel@tonic-gate 			if (pi == NULL) {
13907c478bd9Sstevel@tonic-gate 				logerr("out of memory\n");
13917c478bd9Sstevel@tonic-gate 				(void) close(sock);
13927c478bd9Sstevel@tonic-gate 				sock = -1;
13937c478bd9Sstevel@tonic-gate 				(void) free(buf);
13947c478bd9Sstevel@tonic-gate 				return (-1);
13957c478bd9Sstevel@tonic-gate 			}
13967c478bd9Sstevel@tonic-gate 		}
13977c478bd9Sstevel@tonic-gate 		pi->pi_state &= ~ST_MARKED;
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 		li = find_logint(pi, ifreq.ifr_name);
14007c478bd9Sstevel@tonic-gate 		if (li != NULL) {
14017c478bd9Sstevel@tonic-gate 			/*
14027c478bd9Sstevel@tonic-gate 			 * Detect significant changes.
14037c478bd9Sstevel@tonic-gate 			 * We treat netmask changes as insignificant but all
14047c478bd9Sstevel@tonic-gate 			 * other changes cause a delete plus add of the
14057c478bd9Sstevel@tonic-gate 			 * logical interface.
14067c478bd9Sstevel@tonic-gate 			 * Note: if the flags and localaddr are unchanged
14077c478bd9Sstevel@tonic-gate 			 * then nothing but the netmask and the broadcast
14087c478bd9Sstevel@tonic-gate 			 * address could have changed since the other addresses
14097c478bd9Sstevel@tonic-gate 			 * are derived from the flags and the localaddr.
14107c478bd9Sstevel@tonic-gate 			 */
14117c478bd9Sstevel@tonic-gate 			struct logint newli;
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 			if (!getconfig(sock, lifreq.lifr_flags, &ifr->ifr_addr,
14147c478bd9Sstevel@tonic-gate 			    &ifreq, &newli)) {
14157c478bd9Sstevel@tonic-gate 				free_logint(li);
14167c478bd9Sstevel@tonic-gate 				continue;
14177c478bd9Sstevel@tonic-gate 			}
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 			if (newli.li_flags != li->li_flags ||
14207c478bd9Sstevel@tonic-gate 			    newli.li_localaddr.s_addr !=
14217c478bd9Sstevel@tonic-gate 			    li->li_localaddr.s_addr || newli.li_index !=
14227c478bd9Sstevel@tonic-gate 			    li->li_index) {
14237c478bd9Sstevel@tonic-gate 				/* Treat as an interface deletion + addition */
14247c478bd9Sstevel@tonic-gate 				li->li_state |= ST_DELETED;
14257c478bd9Sstevel@tonic-gate 				deleted_logint(li, &newli, s, joinaddr);
14267c478bd9Sstevel@tonic-gate 				free_logint(li);
14277c478bd9Sstevel@tonic-gate 				li = NULL;	/* li recreated below */
14287c478bd9Sstevel@tonic-gate 			} else {
14297c478bd9Sstevel@tonic-gate 				/*
14307c478bd9Sstevel@tonic-gate 				 * No significant changes.
14317c478bd9Sstevel@tonic-gate 				 * Just update the netmask, and broadcast.
14327c478bd9Sstevel@tonic-gate 				 */
14337c478bd9Sstevel@tonic-gate 				li->li_netmask = newli.li_netmask;
14347c478bd9Sstevel@tonic-gate 				li->li_bcastaddr = newli.li_bcastaddr;
14357c478bd9Sstevel@tonic-gate 			}
14367c478bd9Sstevel@tonic-gate 		}
14377c478bd9Sstevel@tonic-gate 		if (li == NULL) {
14387c478bd9Sstevel@tonic-gate 			li = add_logint(pi, ifreq.ifr_name);
14397c478bd9Sstevel@tonic-gate 			if (li == NULL) {
14407c478bd9Sstevel@tonic-gate 				logerr("out of memory\n");
14417c478bd9Sstevel@tonic-gate 				(void) close(sock);
14427c478bd9Sstevel@tonic-gate 				sock = -1;
14437c478bd9Sstevel@tonic-gate 				(void) free(buf);
14447c478bd9Sstevel@tonic-gate 				return (-1);
14457c478bd9Sstevel@tonic-gate 			}
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 			/* init li */
14487c478bd9Sstevel@tonic-gate 			if (!getconfig(sock, lifreq.lifr_flags, &ifr->ifr_addr,
14497c478bd9Sstevel@tonic-gate 			    &ifreq, li)) {
14507c478bd9Sstevel@tonic-gate 				free_logint(li);
14517c478bd9Sstevel@tonic-gate 				continue;
14527c478bd9Sstevel@tonic-gate 			}
14537c478bd9Sstevel@tonic-gate 			li->li_preference = preference;
14547c478bd9Sstevel@tonic-gate 			added_logint(li, s, joinaddr);
14557c478bd9Sstevel@tonic-gate 		}
14567c478bd9Sstevel@tonic-gate 		li->li_state &= ~ST_MARKED;
14577c478bd9Sstevel@tonic-gate 	}
14587c478bd9Sstevel@tonic-gate 	(void) free(buf);
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	/*
14617c478bd9Sstevel@tonic-gate 	 * Determine which interfaces have gone away.
14627c478bd9Sstevel@tonic-gate 	 * The deletion is done in three phases:
14637c478bd9Sstevel@tonic-gate 	 * 1. Mark ST_DELETED
14647c478bd9Sstevel@tonic-gate 	 * 2. Inform using the deleted_* function.
14657c478bd9Sstevel@tonic-gate 	 * 3. Unlink and free the actual memory.
14667c478bd9Sstevel@tonic-gate 	 * Note that for #3 the physical interface must be deleted after
14677c478bd9Sstevel@tonic-gate 	 * the logical ones.
14687c478bd9Sstevel@tonic-gate 	 * Also count the number of physical interfaces.
14697c478bd9Sstevel@tonic-gate 	 */
14707c478bd9Sstevel@tonic-gate 	num_usable_interfaces = 0;
14717c478bd9Sstevel@tonic-gate 	num_deletions = 0;
14727c478bd9Sstevel@tonic-gate 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
14737c478bd9Sstevel@tonic-gate 		if (pi->pi_state & ST_MARKED) {
14747c478bd9Sstevel@tonic-gate 			num_deletions++;
14757c478bd9Sstevel@tonic-gate 			pi->pi_state |= ST_DELETED;
14767c478bd9Sstevel@tonic-gate 		}
14777c478bd9Sstevel@tonic-gate 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
14787c478bd9Sstevel@tonic-gate 			if (li->li_state & ST_MARKED) {
14797c478bd9Sstevel@tonic-gate 				num_deletions++;
14807c478bd9Sstevel@tonic-gate 				li->li_state |= ST_DELETED;
14817c478bd9Sstevel@tonic-gate 			}
14827c478bd9Sstevel@tonic-gate 		}
14837c478bd9Sstevel@tonic-gate 		if (!(pi->pi_state & ST_DELETED))
14847c478bd9Sstevel@tonic-gate 			num_usable_interfaces++;
14857c478bd9Sstevel@tonic-gate 	}
14867c478bd9Sstevel@tonic-gate 	if (num_deletions != 0) {
14877c478bd9Sstevel@tonic-gate 		struct phyint *nextpi;
14887c478bd9Sstevel@tonic-gate 		struct logint *nextli;
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 		for (pi = phyint; pi != NULL; pi = pi->pi_next) {
14917c478bd9Sstevel@tonic-gate 			if (pi->pi_state & ST_DELETED) {
14927c478bd9Sstevel@tonic-gate 				/*
14937c478bd9Sstevel@tonic-gate 				 * By deleting the physical interface pi, all of
14947c478bd9Sstevel@tonic-gate 				 * the corresponding logical interfaces will
14957c478bd9Sstevel@tonic-gate 				 * also be deleted so there is no need to delete
14967c478bd9Sstevel@tonic-gate 				 * them individually.
14977c478bd9Sstevel@tonic-gate 				 */
14987c478bd9Sstevel@tonic-gate 				deleted_phyint(pi, s, joinaddr);
14997c478bd9Sstevel@tonic-gate 			} else {
15007c478bd9Sstevel@tonic-gate 				for (li = pi->pi_logical_first; li != NULL;
15017c478bd9Sstevel@tonic-gate 				    li = li->li_next) {
15027c478bd9Sstevel@tonic-gate 					if (li->li_state & ST_DELETED) {
15037c478bd9Sstevel@tonic-gate 						deleted_logint(li, NULL, s,
15047c478bd9Sstevel@tonic-gate 						    joinaddr);
15057c478bd9Sstevel@tonic-gate 					}
15067c478bd9Sstevel@tonic-gate 				}
15077c478bd9Sstevel@tonic-gate 			}
15087c478bd9Sstevel@tonic-gate 		}
15097c478bd9Sstevel@tonic-gate 		/* Do the actual linked list update + free */
15107c478bd9Sstevel@tonic-gate 		for (pi = phyint; pi != NULL; pi = nextpi) {
15117c478bd9Sstevel@tonic-gate 			nextpi = pi->pi_next;
15127c478bd9Sstevel@tonic-gate 			for (li = pi->pi_logical_first; li != NULL;
15137c478bd9Sstevel@tonic-gate 			    li = nextli) {
15147c478bd9Sstevel@tonic-gate 				nextli = li->li_next;
15157c478bd9Sstevel@tonic-gate 				if (li->li_state & ST_DELETED)
15167c478bd9Sstevel@tonic-gate 					free_logint(li);
15177c478bd9Sstevel@tonic-gate 			}
15187c478bd9Sstevel@tonic-gate 			if (pi->pi_state & ST_DELETED)
15197c478bd9Sstevel@tonic-gate 				free_phyint(pi);
15207c478bd9Sstevel@tonic-gate 		}
15217c478bd9Sstevel@tonic-gate 	}
15227c478bd9Sstevel@tonic-gate 	/*
15237c478bd9Sstevel@tonic-gate 	 * When the set of available interfaces goes from zero to
15247c478bd9Sstevel@tonic-gate 	 * non-zero we restart solicitations if '-s' was specified.
15257c478bd9Sstevel@tonic-gate 	 */
15267c478bd9Sstevel@tonic-gate 	if (old_num_usable_interfaces == 0 && num_usable_interfaces > 0 &&
15277c478bd9Sstevel@tonic-gate 	    start_solicit && !solicit) {
15287c478bd9Sstevel@tonic-gate 		if (debug)
15297c478bd9Sstevel@tonic-gate 			logdebug("switching to solicitations: num if %d\n",
15307c478bd9Sstevel@tonic-gate 			    num_usable_interfaces);
15317c478bd9Sstevel@tonic-gate 		solicit = start_solicit;
15327c478bd9Sstevel@tonic-gate 		ntransmitted = 0;
15337c478bd9Sstevel@tonic-gate 		ntransmitted++;
15347c478bd9Sstevel@tonic-gate 		solicitor(&whereto);
15357c478bd9Sstevel@tonic-gate 	}
15367c478bd9Sstevel@tonic-gate 	return (0);
15377c478bd9Sstevel@tonic-gate }
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate static boolean_t
15407c478bd9Sstevel@tonic-gate getconfig(int sock, uint64_t if_flags, struct sockaddr *addr,
15417c478bd9Sstevel@tonic-gate     struct ifreq *ifr, struct logint *li)
15427c478bd9Sstevel@tonic-gate {
15437c478bd9Sstevel@tonic-gate 	struct ifreq ifreq;
15447c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
15457c478bd9Sstevel@tonic-gate 	struct lifreq lifreq;
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	ifreq = *ifr;	/* Copy name etc */
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 	li->li_flags = if_flags;
15507c478bd9Sstevel@tonic-gate 	sin = (struct sockaddr_in *)ALIGN(addr);
15517c478bd9Sstevel@tonic-gate 	li->li_localaddr = sin->sin_addr;
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 	(void) strlcpy(lifreq.lifr_name, ifr->ifr_name,
15547c478bd9Sstevel@tonic-gate 	    sizeof (lifreq.lifr_name));
15557c478bd9Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFINDEX, &lifreq) < 0) {
15567c478bd9Sstevel@tonic-gate 		logperror("initifs: ioctl (get if index)");
15577c478bd9Sstevel@tonic-gate 		/* Continue with 0; a safe value never used for interfaces */
15587c478bd9Sstevel@tonic-gate 		li->li_index = 0;
15597c478bd9Sstevel@tonic-gate 	} else {
15607c478bd9Sstevel@tonic-gate 		li->li_index = lifreq.lifr_index;
15617c478bd9Sstevel@tonic-gate 	}
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 	if (if_flags & IFF_POINTOPOINT) {
15647c478bd9Sstevel@tonic-gate 		li->li_netmask.s_addr = (unsigned long)0xffffffff;
15657c478bd9Sstevel@tonic-gate 		if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
15667c478bd9Sstevel@tonic-gate 			logperror("initifs: ioctl (get dest addr)");
15677c478bd9Sstevel@tonic-gate 			return (B_FALSE);
15687c478bd9Sstevel@tonic-gate 		}
15697c478bd9Sstevel@tonic-gate 		/* A pt-pt link is identified by the remote address */
15707c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr);
15717c478bd9Sstevel@tonic-gate 		li->li_address = sin->sin_addr;
15727c478bd9Sstevel@tonic-gate 		li->li_remoteaddr = sin->sin_addr;
15737c478bd9Sstevel@tonic-gate 		/* Simulate broadcast for pt-pt */
15747c478bd9Sstevel@tonic-gate 		li->li_bcastaddr = sin->sin_addr;
15757c478bd9Sstevel@tonic-gate 		li->li_flags |= IFF_BROADCAST;
15767c478bd9Sstevel@tonic-gate 	} else {
15777c478bd9Sstevel@tonic-gate 		/*
15787c478bd9Sstevel@tonic-gate 		 * Non pt-pt links are identified by the local
15797c478bd9Sstevel@tonic-gate 		 * address
15807c478bd9Sstevel@tonic-gate 		 */
15817c478bd9Sstevel@tonic-gate 		li->li_address = li->li_localaddr;
15827c478bd9Sstevel@tonic-gate 		li->li_remoteaddr = li->li_address;
15837c478bd9Sstevel@tonic-gate 		if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
15847c478bd9Sstevel@tonic-gate 			logperror("initifs: ioctl (get netmask)");
15857c478bd9Sstevel@tonic-gate 			return (B_FALSE);
15867c478bd9Sstevel@tonic-gate 		}
15877c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr);
15887c478bd9Sstevel@tonic-gate 		li->li_netmask = sin->sin_addr;
15897c478bd9Sstevel@tonic-gate 		if (if_flags & IFF_BROADCAST) {
15907c478bd9Sstevel@tonic-gate 			if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
15917c478bd9Sstevel@tonic-gate 				logperror(
15927c478bd9Sstevel@tonic-gate 				    "initifs: ioctl (get broadcast address)");
15937c478bd9Sstevel@tonic-gate 				return (B_FALSE);
15947c478bd9Sstevel@tonic-gate 			}
15957c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr);
15967c478bd9Sstevel@tonic-gate 			li->li_bcastaddr = sin->sin_addr;
15977c478bd9Sstevel@tonic-gate 		}
15987c478bd9Sstevel@tonic-gate 	}
15997c478bd9Sstevel@tonic-gate 	return (B_TRUE);
16007c478bd9Sstevel@tonic-gate }
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate static int
16047c478bd9Sstevel@tonic-gate support_multicast(void)
16057c478bd9Sstevel@tonic-gate {
16067c478bd9Sstevel@tonic-gate 	int sock;
16077c478bd9Sstevel@tonic-gate 	uchar_t ttl = 1;
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
16107c478bd9Sstevel@tonic-gate 	if (sock < 0) {
16117c478bd9Sstevel@tonic-gate 		logperror("support_multicast: socket");
16127c478bd9Sstevel@tonic-gate 		return (0);
16137c478bd9Sstevel@tonic-gate 	}
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 	if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
16167c478bd9Sstevel@tonic-gate 	    (char *)&ttl, sizeof (ttl)) < 0) {
16177c478bd9Sstevel@tonic-gate 		(void) close(sock);
16187c478bd9Sstevel@tonic-gate 		return (0);
16197c478bd9Sstevel@tonic-gate 	}
16207c478bd9Sstevel@tonic-gate 	(void) close(sock);
16217c478bd9Sstevel@tonic-gate 	return (1);
16227c478bd9Sstevel@tonic-gate }
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate /*
16257c478bd9Sstevel@tonic-gate  * For a given destination address, find the logical interface to use.
16267c478bd9Sstevel@tonic-gate  * If opi is NULL check all interfaces. Otherwise just match against
16277c478bd9Sstevel@tonic-gate  * the specified physical interface.
16287c478bd9Sstevel@tonic-gate  * Return logical interface if there's a match, NULL otherwise.
16297c478bd9Sstevel@tonic-gate  */
16307c478bd9Sstevel@tonic-gate static struct logint *
16317c478bd9Sstevel@tonic-gate find_directly_connected_logint(struct in_addr in, struct phyint *opi)
16327c478bd9Sstevel@tonic-gate {
16337c478bd9Sstevel@tonic-gate 	struct phyint *pi;
16347c478bd9Sstevel@tonic-gate 	struct logint *li;
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	if (opi == NULL)
16377c478bd9Sstevel@tonic-gate 		pi = phyint;
16387c478bd9Sstevel@tonic-gate 	else
16397c478bd9Sstevel@tonic-gate 		pi = opi;
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 	for (; pi != NULL; pi = pi->pi_next) {
16427c478bd9Sstevel@tonic-gate 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
16437c478bd9Sstevel@tonic-gate 			if (li->li_state & ST_DELETED)
16447c478bd9Sstevel@tonic-gate 				continue;
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate 			/* Check that the subnetwork numbers match */
16477c478bd9Sstevel@tonic-gate 			if ((in.s_addr & li->li_netmask.s_addr) ==
16487c478bd9Sstevel@tonic-gate 			    (li->li_remoteaddr.s_addr &
16497c478bd9Sstevel@tonic-gate 			    li->li_netmask.s_addr))
16507c478bd9Sstevel@tonic-gate 				return (li);
16517c478bd9Sstevel@tonic-gate 		}
16527c478bd9Sstevel@tonic-gate 		if (opi != NULL)
16537c478bd9Sstevel@tonic-gate 			break;
16547c478bd9Sstevel@tonic-gate 	}
16557c478bd9Sstevel@tonic-gate 	return (NULL);
16567c478bd9Sstevel@tonic-gate }
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate /*
16597c478bd9Sstevel@tonic-gate  * INTERFACES - physical and logical identified by name
16607c478bd9Sstevel@tonic-gate  */
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate static void
16647c478bd9Sstevel@tonic-gate report_interfaces(void)
16657c478bd9Sstevel@tonic-gate {
16667c478bd9Sstevel@tonic-gate 	struct phyint *pi;
16677c478bd9Sstevel@tonic-gate 	struct logint *li;
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	logdebug("\nInterfaces:\n\n");
16707c478bd9Sstevel@tonic-gate 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
16717c478bd9Sstevel@tonic-gate 		logdebug("Phyint %s state 0x%x\n",
16727c478bd9Sstevel@tonic-gate 		    pi->pi_name, pi->pi_state);
16737c478bd9Sstevel@tonic-gate 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
16747c478bd9Sstevel@tonic-gate 			logdebug("IF %s state 0x%x, flags 0x%x, addr %s\n",
16757c478bd9Sstevel@tonic-gate 			    li->li_name, li->li_state, li->li_flags,
16767c478bd9Sstevel@tonic-gate 			    pr_name(li->li_address));
16777c478bd9Sstevel@tonic-gate 			logdebug("\tlocal %s pref 0x%x ",
16787c478bd9Sstevel@tonic-gate 			    pr_name(li->li_localaddr), li->li_preference);
16797c478bd9Sstevel@tonic-gate 			logdebug("bcast %s\n",
16807c478bd9Sstevel@tonic-gate 			    pr_name(li->li_bcastaddr));
16817c478bd9Sstevel@tonic-gate 			logdebug("\tremote %s ",
16827c478bd9Sstevel@tonic-gate 			    pr_name(li->li_remoteaddr));
16837c478bd9Sstevel@tonic-gate 			logdebug("netmask %s\n",
16847c478bd9Sstevel@tonic-gate 			    pr_name(li->li_netmask));
16857c478bd9Sstevel@tonic-gate 		}
16867c478bd9Sstevel@tonic-gate 	}
16877c478bd9Sstevel@tonic-gate }
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate static struct phyint *
16907c478bd9Sstevel@tonic-gate find_phyint(char *name)
16917c478bd9Sstevel@tonic-gate {
16927c478bd9Sstevel@tonic-gate 	struct phyint *pi;
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
16957c478bd9Sstevel@tonic-gate 		if (strcmp(pi->pi_name, name) == 0)
16967c478bd9Sstevel@tonic-gate 			return (pi);
16977c478bd9Sstevel@tonic-gate 	}
16987c478bd9Sstevel@tonic-gate 	return (NULL);
16997c478bd9Sstevel@tonic-gate }
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate /* Assumes that the entry does not exist - caller must use find_* */
17027c478bd9Sstevel@tonic-gate static struct phyint *
17037c478bd9Sstevel@tonic-gate add_phyint(char *name)
17047c478bd9Sstevel@tonic-gate {
17057c478bd9Sstevel@tonic-gate 	struct phyint *pi;
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	pi = malloc(sizeof (*pi));
17087c478bd9Sstevel@tonic-gate 	if (pi == NULL)
17097c478bd9Sstevel@tonic-gate 		return (NULL);
17107c478bd9Sstevel@tonic-gate 	bzero((char *)pi, sizeof (*pi));
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 	strncpy(pi->pi_name, name, sizeof (pi->pi_name));
17137c478bd9Sstevel@tonic-gate 	/* Link into list */
17147c478bd9Sstevel@tonic-gate 	pi->pi_next = phyint;
17157c478bd9Sstevel@tonic-gate 	pi->pi_prev = NULL;
17167c478bd9Sstevel@tonic-gate 	if (phyint != NULL)
17177c478bd9Sstevel@tonic-gate 		phyint->pi_prev = pi;
17187c478bd9Sstevel@tonic-gate 	phyint = pi;
17197c478bd9Sstevel@tonic-gate 	return (pi);
17207c478bd9Sstevel@tonic-gate }
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate static void
17237c478bd9Sstevel@tonic-gate free_phyint(struct phyint *pi)
17247c478bd9Sstevel@tonic-gate {
17257c478bd9Sstevel@tonic-gate 	assert(pi->pi_logical_first == NULL);
17267c478bd9Sstevel@tonic-gate 	assert(pi->pi_logical_last == NULL);
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	if (pi->pi_prev == NULL) {
17297c478bd9Sstevel@tonic-gate 		/* Delete first */
17307c478bd9Sstevel@tonic-gate 		assert(phyint == pi);
17317c478bd9Sstevel@tonic-gate 		phyint = pi->pi_next;
17327c478bd9Sstevel@tonic-gate 	} else {
17337c478bd9Sstevel@tonic-gate 		assert(pi->pi_prev->pi_next == pi);
17347c478bd9Sstevel@tonic-gate 		pi->pi_prev->pi_next = pi->pi_next;
17357c478bd9Sstevel@tonic-gate 	}
17367c478bd9Sstevel@tonic-gate 	if (pi->pi_next != NULL) {
17377c478bd9Sstevel@tonic-gate 		assert(pi->pi_next->pi_prev == pi);
17387c478bd9Sstevel@tonic-gate 		pi->pi_next->pi_prev = pi->pi_prev;
17397c478bd9Sstevel@tonic-gate 	}
17407c478bd9Sstevel@tonic-gate 	free(pi);
17417c478bd9Sstevel@tonic-gate }
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate static struct logint *
17447c478bd9Sstevel@tonic-gate find_logint(struct phyint *pi, char *name)
17457c478bd9Sstevel@tonic-gate {
17467c478bd9Sstevel@tonic-gate 	struct logint *li;
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 	for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
17497c478bd9Sstevel@tonic-gate 		if (strcmp(li->li_name, name) == 0)
17507c478bd9Sstevel@tonic-gate 			return (li);
17517c478bd9Sstevel@tonic-gate 	}
17527c478bd9Sstevel@tonic-gate 	return (NULL);
17537c478bd9Sstevel@tonic-gate }
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate /*
17567c478bd9Sstevel@tonic-gate  * Assumes that the entry does not exist - caller must use find_*
17577c478bd9Sstevel@tonic-gate  * Tail insertion.
17587c478bd9Sstevel@tonic-gate  */
17597c478bd9Sstevel@tonic-gate static struct logint *
17607c478bd9Sstevel@tonic-gate add_logint(struct phyint *pi, char *name)
17617c478bd9Sstevel@tonic-gate {
17627c478bd9Sstevel@tonic-gate 	struct logint *li;
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	li = malloc(sizeof (*li));
17657c478bd9Sstevel@tonic-gate 	if (li == NULL)
17667c478bd9Sstevel@tonic-gate 		return (NULL);
17677c478bd9Sstevel@tonic-gate 	bzero((char *)li, sizeof (*li));
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	strncpy(li->li_name, name, sizeof (li->li_name));
17707c478bd9Sstevel@tonic-gate 	/* Link into list */
17717c478bd9Sstevel@tonic-gate 	li->li_prev = pi->pi_logical_last;
17727c478bd9Sstevel@tonic-gate 	if (pi->pi_logical_last == NULL) {
17737c478bd9Sstevel@tonic-gate 		/* First one */
17747c478bd9Sstevel@tonic-gate 		assert(pi->pi_logical_first == NULL);
17757c478bd9Sstevel@tonic-gate 		pi->pi_logical_first = li;
17767c478bd9Sstevel@tonic-gate 	} else {
17777c478bd9Sstevel@tonic-gate 		pi->pi_logical_last->li_next = li;
17787c478bd9Sstevel@tonic-gate 	}
17797c478bd9Sstevel@tonic-gate 	li->li_next = NULL;
17807c478bd9Sstevel@tonic-gate 	li->li_physical = pi;
17817c478bd9Sstevel@tonic-gate 	pi->pi_logical_last = li;
17827c478bd9Sstevel@tonic-gate 	return (li);
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate static void
17877c478bd9Sstevel@tonic-gate free_logint(struct logint *li)
17887c478bd9Sstevel@tonic-gate {
17897c478bd9Sstevel@tonic-gate 	struct phyint *pi;
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	pi = li->li_physical;
17927c478bd9Sstevel@tonic-gate 	if (li->li_prev == NULL) {
17937c478bd9Sstevel@tonic-gate 		/* Delete first */
17947c478bd9Sstevel@tonic-gate 		assert(pi->pi_logical_first == li);
17957c478bd9Sstevel@tonic-gate 		pi->pi_logical_first = li->li_next;
17967c478bd9Sstevel@tonic-gate 	} else {
17977c478bd9Sstevel@tonic-gate 		assert(li->li_prev->li_next == li);
17987c478bd9Sstevel@tonic-gate 		li->li_prev->li_next = li->li_next;
17997c478bd9Sstevel@tonic-gate 	}
18007c478bd9Sstevel@tonic-gate 	if (li->li_next == NULL) {
18017c478bd9Sstevel@tonic-gate 		/* Delete last */
18027c478bd9Sstevel@tonic-gate 		assert(pi->pi_logical_last == li);
18037c478bd9Sstevel@tonic-gate 		pi->pi_logical_last = li->li_prev;
18047c478bd9Sstevel@tonic-gate 	} else {
18057c478bd9Sstevel@tonic-gate 		assert(li->li_next->li_prev == li);
18067c478bd9Sstevel@tonic-gate 		li->li_next->li_prev = li->li_prev;
18077c478bd9Sstevel@tonic-gate 	}
18087c478bd9Sstevel@tonic-gate 	free(li);
18097c478bd9Sstevel@tonic-gate }
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate /* Tell all the logical interfaces that they are going away */
18137c478bd9Sstevel@tonic-gate static void
18147c478bd9Sstevel@tonic-gate deleted_phyint(struct phyint *pi, int s,
18157c478bd9Sstevel@tonic-gate     struct sockaddr_in *joinaddr)
18167c478bd9Sstevel@tonic-gate {
18177c478bd9Sstevel@tonic-gate 	struct logint *li;
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate 	if (debug)
18207c478bd9Sstevel@tonic-gate 		logdebug("Deleting physical interface %s\n", pi->pi_name);
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
18237c478bd9Sstevel@tonic-gate 		li->li_state |= ST_DELETED;
18247c478bd9Sstevel@tonic-gate 	}
18257c478bd9Sstevel@tonic-gate 	for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
18267c478bd9Sstevel@tonic-gate 		deleted_logint(li, NULL, s, joinaddr);
18277c478bd9Sstevel@tonic-gate 	}
18287c478bd9Sstevel@tonic-gate }
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate /*
18317c478bd9Sstevel@tonic-gate  * Join the multicast address if no other logical interface has done
18327c478bd9Sstevel@tonic-gate  * so for this physical interface.
18337c478bd9Sstevel@tonic-gate  */
18347c478bd9Sstevel@tonic-gate static void
18357c478bd9Sstevel@tonic-gate added_logint(struct logint *li, int s,
18367c478bd9Sstevel@tonic-gate     struct sockaddr_in *joinaddr)
18377c478bd9Sstevel@tonic-gate {
18387c478bd9Sstevel@tonic-gate 	if (debug)
18397c478bd9Sstevel@tonic-gate 		logdebug("Adding logical interface %s\n", li->li_name);
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 	if ((!(li->li_physical->pi_state & ST_JOINED)) &&
18427c478bd9Sstevel@tonic-gate 	    (!isbroadcast(joinaddr))) {
18437c478bd9Sstevel@tonic-gate 		struct ip_mreq mreq;
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 		mreq.imr_multiaddr = joinaddr->sin_addr;
18467c478bd9Sstevel@tonic-gate 		mreq.imr_interface = li->li_address;
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 		if (debug)
18497c478bd9Sstevel@tonic-gate 			logdebug("Joining MC on interface %s\n", li->li_name);
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate 		if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
18527c478bd9Sstevel@tonic-gate 		    (char *)&mreq, sizeof (mreq)) < 0) {
18537c478bd9Sstevel@tonic-gate 			logperror("setsockopt (IP_ADD_MEMBERSHIP)");
18547c478bd9Sstevel@tonic-gate 		} else {
18557c478bd9Sstevel@tonic-gate 			li->li_physical->pi_state |= ST_JOINED;
18567c478bd9Sstevel@tonic-gate 			li->li_state |= ST_JOINED;
18577c478bd9Sstevel@tonic-gate 		}
18587c478bd9Sstevel@tonic-gate 	}
18597c478bd9Sstevel@tonic-gate }
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate /*
18627c478bd9Sstevel@tonic-gate  * Leave the multicast address if this logical interface joined it.
18637c478bd9Sstevel@tonic-gate  * Look for a replacement logical interface for the same physical interface.
18647c478bd9Sstevel@tonic-gate  * Remove any routes which are no longer reachable.
18657c478bd9Sstevel@tonic-gate  *
18667c478bd9Sstevel@tonic-gate  * If newli is non-NULL, then it is likely that the address of a logical
18677c478bd9Sstevel@tonic-gate  * interface has changed.  In this case, the membership should be dropped using
18687c478bd9Sstevel@tonic-gate  * the new address of the interface in question.
18697c478bd9Sstevel@tonic-gate  *
18707c478bd9Sstevel@tonic-gate  * XXX When a physical interface is being deleted by deleted_phyint(), this
18717c478bd9Sstevel@tonic-gate  * routine will be called for each logical interface associated with the
18727c478bd9Sstevel@tonic-gate  * physical one.  This should be made more efficient as there is no point in
18737c478bd9Sstevel@tonic-gate  * searching for an alternate logical interface to add group membership to as
18747c478bd9Sstevel@tonic-gate  * they all are marked ST_DELETED.
18757c478bd9Sstevel@tonic-gate  */
18767c478bd9Sstevel@tonic-gate static void
18777c478bd9Sstevel@tonic-gate deleted_logint(struct logint *li, struct logint *newli, int s,
18787c478bd9Sstevel@tonic-gate     struct sockaddr_in *joinaddr)
18797c478bd9Sstevel@tonic-gate {
18807c478bd9Sstevel@tonic-gate 	struct phyint *pi;
18817c478bd9Sstevel@tonic-gate 	struct logint *oli;
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 	if (debug)
18847c478bd9Sstevel@tonic-gate 		logdebug("Deleting logical interface %s\n", li->li_name);
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate 	assert(li->li_state & ST_DELETED);
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 	if (li->li_state & ST_JOINED) {
18897c478bd9Sstevel@tonic-gate 		struct ip_mreq mreq;
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 		pi = li->li_physical;
18927c478bd9Sstevel@tonic-gate 		assert(pi->pi_state & ST_JOINED);
18937c478bd9Sstevel@tonic-gate 		assert(!isbroadcast(joinaddr));
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 		mreq.imr_multiaddr = joinaddr->sin_addr;
18967c478bd9Sstevel@tonic-gate 		if (newli != NULL)
18977c478bd9Sstevel@tonic-gate 			mreq.imr_interface = newli->li_address;
18987c478bd9Sstevel@tonic-gate 		else
18997c478bd9Sstevel@tonic-gate 			mreq.imr_interface = li->li_address;
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 		if (debug)
19027c478bd9Sstevel@tonic-gate 			logdebug("Leaving MC on interface %s\n", li->li_name);
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 		if (setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP,
19057c478bd9Sstevel@tonic-gate 		    (char *)&mreq, sizeof (mreq)) < 0) {
19067c478bd9Sstevel@tonic-gate 			/*
19077c478bd9Sstevel@tonic-gate 			 * EADDRNOTAVAIL will be returned if the interface has
19087c478bd9Sstevel@tonic-gate 			 * been unplumbed or if the interface no longer has
19097c478bd9Sstevel@tonic-gate 			 * IFF_MULTICAST set.  The former is the common case
19107c478bd9Sstevel@tonic-gate 			 * while the latter is rare so don't log the error
19117c478bd9Sstevel@tonic-gate 			 * unless some other error was returned or if debug is
19127c478bd9Sstevel@tonic-gate 			 * set.
19137c478bd9Sstevel@tonic-gate 			 */
19147c478bd9Sstevel@tonic-gate 			if (errno != EADDRNOTAVAIL) {
19157c478bd9Sstevel@tonic-gate 				logperror("setsockopt (IP_DROP_MEMBERSHIP)");
19167c478bd9Sstevel@tonic-gate 			} else if (debug) {
19177c478bd9Sstevel@tonic-gate 				logdebug("%s: %s\n",
19187c478bd9Sstevel@tonic-gate 				    "setsockopt (IP_DROP_MEMBERSHIP)",
19197c478bd9Sstevel@tonic-gate 				    strerror(errno));
19207c478bd9Sstevel@tonic-gate 			}
19217c478bd9Sstevel@tonic-gate 		}
19227c478bd9Sstevel@tonic-gate 		li->li_physical->pi_state &= ~ST_JOINED;
19237c478bd9Sstevel@tonic-gate 		li->li_state &= ~ST_JOINED;
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 		/* Is there another interface that can join? */
19267c478bd9Sstevel@tonic-gate 		for (oli = pi->pi_logical_first; oli != NULL;
19277c478bd9Sstevel@tonic-gate 		    oli = oli->li_next) {
19287c478bd9Sstevel@tonic-gate 			if (oli->li_state & ST_DELETED)
19297c478bd9Sstevel@tonic-gate 				continue;
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 			mreq.imr_multiaddr = joinaddr->sin_addr;
19327c478bd9Sstevel@tonic-gate 			mreq.imr_interface = oli->li_address;
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 			if (debug)
19357c478bd9Sstevel@tonic-gate 				logdebug("Joining MC on interface %s\n",
19367c478bd9Sstevel@tonic-gate 				    oli->li_name);
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 			if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
19397c478bd9Sstevel@tonic-gate 				(char *)&mreq, sizeof (mreq)) < 0) {
19407c478bd9Sstevel@tonic-gate 				logperror("setsockopt (IP_ADD_MEMBERSHIP)");
19417c478bd9Sstevel@tonic-gate 			} else {
19427c478bd9Sstevel@tonic-gate 				pi->pi_state |= ST_JOINED;
19437c478bd9Sstevel@tonic-gate 				oli->li_state |= ST_JOINED;
19447c478bd9Sstevel@tonic-gate 				break;
19457c478bd9Sstevel@tonic-gate 			}
19467c478bd9Sstevel@tonic-gate 		}
19477c478bd9Sstevel@tonic-gate 	}
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate 	flush_unreachable_routers();
19507c478bd9Sstevel@tonic-gate }
19517c478bd9Sstevel@tonic-gate 
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate /*
19557c478bd9Sstevel@tonic-gate  * TABLES
19567c478bd9Sstevel@tonic-gate  */
19577c478bd9Sstevel@tonic-gate struct table {
19587c478bd9Sstevel@tonic-gate 	struct in_addr	router;
19597c478bd9Sstevel@tonic-gate 	int		preference;
19607c478bd9Sstevel@tonic-gate 	int		remaining_time;
19617c478bd9Sstevel@tonic-gate 	int		in_kernel;
19627c478bd9Sstevel@tonic-gate 	struct table	*next;
19637c478bd9Sstevel@tonic-gate };
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate struct table *table;
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate static void
19687c478bd9Sstevel@tonic-gate report_routes(void)
19697c478bd9Sstevel@tonic-gate {
19707c478bd9Sstevel@tonic-gate 	struct table *tp;
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 	logdebug("\nRoutes:\n\n");
19737c478bd9Sstevel@tonic-gate 	tp = table;
19747c478bd9Sstevel@tonic-gate 	while (tp) {
19757c478bd9Sstevel@tonic-gate 		logdebug("Router %s, pref 0x%x, time %d, %s kernel\n",
19767c478bd9Sstevel@tonic-gate 		    pr_name(tp->router), tp->preference,
19777c478bd9Sstevel@tonic-gate 		    tp->remaining_time,
19787c478bd9Sstevel@tonic-gate 		    (tp->in_kernel ? "in" : "not in"));
19797c478bd9Sstevel@tonic-gate 		tp = tp->next;
19807c478bd9Sstevel@tonic-gate 	}
19817c478bd9Sstevel@tonic-gate }
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate static struct table *
19847c478bd9Sstevel@tonic-gate find_router(struct in_addr addr)
19857c478bd9Sstevel@tonic-gate {
19867c478bd9Sstevel@tonic-gate 	struct table *tp;
19877c478bd9Sstevel@tonic-gate 
19887c478bd9Sstevel@tonic-gate 	tp = table;
19897c478bd9Sstevel@tonic-gate 	while (tp) {
19907c478bd9Sstevel@tonic-gate 		if (tp->router.s_addr == addr.s_addr)
19917c478bd9Sstevel@tonic-gate 			return (tp);
19927c478bd9Sstevel@tonic-gate 		tp = tp->next;
19937c478bd9Sstevel@tonic-gate 	}
19947c478bd9Sstevel@tonic-gate 	return (NULL);
19957c478bd9Sstevel@tonic-gate }
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate static int
19987c478bd9Sstevel@tonic-gate max_preference(void)
19997c478bd9Sstevel@tonic-gate {
20007c478bd9Sstevel@tonic-gate 	struct table *tp;
20017c478bd9Sstevel@tonic-gate 	int max = (int)IGNORE_PREFERENCE;
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 	tp = table;
20047c478bd9Sstevel@tonic-gate 	while (tp) {
20057c478bd9Sstevel@tonic-gate 		if (tp->preference > max)
20067c478bd9Sstevel@tonic-gate 			max = tp->preference;
20077c478bd9Sstevel@tonic-gate 		tp = tp->next;
20087c478bd9Sstevel@tonic-gate 	}
20097c478bd9Sstevel@tonic-gate 	return (max);
20107c478bd9Sstevel@tonic-gate }
20117c478bd9Sstevel@tonic-gate 
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate /* Note: this might leave the kernel with no default route for a short time. */
20147c478bd9Sstevel@tonic-gate static void
20157c478bd9Sstevel@tonic-gate age_table(int time)
20167c478bd9Sstevel@tonic-gate {
20177c478bd9Sstevel@tonic-gate 	struct table **tpp, *tp;
20187c478bd9Sstevel@tonic-gate 	int recalculate_max = 0;
20197c478bd9Sstevel@tonic-gate 	int max = max_preference();
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 	tpp = &table;
20227c478bd9Sstevel@tonic-gate 	while (*tpp != NULL) {
20237c478bd9Sstevel@tonic-gate 		tp = *tpp;
20247c478bd9Sstevel@tonic-gate 		tp->remaining_time -= time;
20257c478bd9Sstevel@tonic-gate 		if (tp->remaining_time <= 0) {
20267c478bd9Sstevel@tonic-gate 			*tpp = tp->next;
20277c478bd9Sstevel@tonic-gate 			if (debug) {
20287c478bd9Sstevel@tonic-gate 				logdebug("Timed out router %s\n",
20297c478bd9Sstevel@tonic-gate 				    pr_name(tp->router));
20307c478bd9Sstevel@tonic-gate 			}
20317c478bd9Sstevel@tonic-gate 			if (tp->in_kernel)
20327c478bd9Sstevel@tonic-gate 				del_route(tp->router);
20337c478bd9Sstevel@tonic-gate 			if (best_preference &&
20347c478bd9Sstevel@tonic-gate 			    tp->preference == max)
20357c478bd9Sstevel@tonic-gate 				recalculate_max++;
20367c478bd9Sstevel@tonic-gate 			free((char *)tp);
20377c478bd9Sstevel@tonic-gate 		} else {
20387c478bd9Sstevel@tonic-gate 			tpp = &tp->next;
20397c478bd9Sstevel@tonic-gate 		}
20407c478bd9Sstevel@tonic-gate 	}
20417c478bd9Sstevel@tonic-gate 	if (recalculate_max) {
20427c478bd9Sstevel@tonic-gate 		int max = max_preference();
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate 		if (max != IGNORE_PREFERENCE) {
20457c478bd9Sstevel@tonic-gate 			tp = table;
20467c478bd9Sstevel@tonic-gate 			while (tp) {
20477c478bd9Sstevel@tonic-gate 				if (tp->preference == max && !tp->in_kernel) {
20487c478bd9Sstevel@tonic-gate 					add_route(tp->router);
20497c478bd9Sstevel@tonic-gate 					tp->in_kernel++;
20507c478bd9Sstevel@tonic-gate 				}
20517c478bd9Sstevel@tonic-gate 				tp = tp->next;
20527c478bd9Sstevel@tonic-gate 			}
20537c478bd9Sstevel@tonic-gate 		}
20547c478bd9Sstevel@tonic-gate 	}
20557c478bd9Sstevel@tonic-gate }
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate /*
20587c478bd9Sstevel@tonic-gate  * Remove any routes which are no longer directly connected.
20597c478bd9Sstevel@tonic-gate  */
20607c478bd9Sstevel@tonic-gate static void
20617c478bd9Sstevel@tonic-gate flush_unreachable_routers(void)
20627c478bd9Sstevel@tonic-gate {
20637c478bd9Sstevel@tonic-gate 	struct table **tpp, *tp;
20647c478bd9Sstevel@tonic-gate 	int recalculate_max = 0;
20657c478bd9Sstevel@tonic-gate 	int max = max_preference();
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	tpp = &table;
20687c478bd9Sstevel@tonic-gate 	while (*tpp != NULL) {
20697c478bd9Sstevel@tonic-gate 		tp = *tpp;
20707c478bd9Sstevel@tonic-gate 		if (find_directly_connected_logint(tp->router, NULL) == NULL) {
20717c478bd9Sstevel@tonic-gate 			*tpp = tp->next;
20727c478bd9Sstevel@tonic-gate 			if (debug) {
20737c478bd9Sstevel@tonic-gate 				logdebug("Unreachable router %s\n",
20747c478bd9Sstevel@tonic-gate 				    pr_name(tp->router));
20757c478bd9Sstevel@tonic-gate 			}
20767c478bd9Sstevel@tonic-gate 			if (tp->in_kernel)
20777c478bd9Sstevel@tonic-gate 				del_route(tp->router);
20787c478bd9Sstevel@tonic-gate 			if (best_preference &&
20797c478bd9Sstevel@tonic-gate 			    tp->preference == max)
20807c478bd9Sstevel@tonic-gate 				recalculate_max++;
20817c478bd9Sstevel@tonic-gate 			free((char *)tp);
20827c478bd9Sstevel@tonic-gate 		} else {
20837c478bd9Sstevel@tonic-gate 			tpp = &tp->next;
20847c478bd9Sstevel@tonic-gate 		}
20857c478bd9Sstevel@tonic-gate 	}
20867c478bd9Sstevel@tonic-gate 	if (recalculate_max) {
20877c478bd9Sstevel@tonic-gate 		int max = max_preference();
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 		if (max != IGNORE_PREFERENCE) {
20907c478bd9Sstevel@tonic-gate 			tp = table;
20917c478bd9Sstevel@tonic-gate 			while (tp) {
20927c478bd9Sstevel@tonic-gate 				if (tp->preference == max && !tp->in_kernel) {
20937c478bd9Sstevel@tonic-gate 					add_route(tp->router);
20947c478bd9Sstevel@tonic-gate 					tp->in_kernel++;
20957c478bd9Sstevel@tonic-gate 				}
20967c478bd9Sstevel@tonic-gate 				tp = tp->next;
20977c478bd9Sstevel@tonic-gate 			}
20987c478bd9Sstevel@tonic-gate 		}
20997c478bd9Sstevel@tonic-gate 	}
21007c478bd9Sstevel@tonic-gate }
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate static void
21037c478bd9Sstevel@tonic-gate record_router(struct in_addr router, long preference, int ttl)
21047c478bd9Sstevel@tonic-gate {
21057c478bd9Sstevel@tonic-gate 	struct table *tp;
21067c478bd9Sstevel@tonic-gate 	int old_max = max_preference();
21077c478bd9Sstevel@tonic-gate 	int changed_up = 0;	/* max preference could have increased */
21087c478bd9Sstevel@tonic-gate 	int changed_down = 0;	/* max preference could have decreased */
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate 	if (debug)
21117c478bd9Sstevel@tonic-gate 		logdebug("Recording %s, preference 0x%x\n",
21127c478bd9Sstevel@tonic-gate 			pr_name(router),
21137c478bd9Sstevel@tonic-gate 			preference);
21147c478bd9Sstevel@tonic-gate 	tp = find_router(router);
21157c478bd9Sstevel@tonic-gate 	if (tp) {
21167c478bd9Sstevel@tonic-gate 		if (tp->preference > preference &&
21177c478bd9Sstevel@tonic-gate 		    tp->preference == old_max)
21187c478bd9Sstevel@tonic-gate 			changed_down++;
21197c478bd9Sstevel@tonic-gate 		else if (preference > tp->preference)
21207c478bd9Sstevel@tonic-gate 			changed_up++;
21217c478bd9Sstevel@tonic-gate 		tp->preference = preference;
21227c478bd9Sstevel@tonic-gate 		tp->remaining_time = ttl;
21237c478bd9Sstevel@tonic-gate 	} else {
21247c478bd9Sstevel@tonic-gate 		if (preference > old_max)
21257c478bd9Sstevel@tonic-gate 			changed_up++;
21267c478bd9Sstevel@tonic-gate 		tp = (struct table *)ALIGN(malloc(sizeof (struct table)));
21277c478bd9Sstevel@tonic-gate 		if (tp == NULL) {
21287c478bd9Sstevel@tonic-gate 			logerr("Out of memory\n");
21297c478bd9Sstevel@tonic-gate 			return;
21307c478bd9Sstevel@tonic-gate 		}
21317c478bd9Sstevel@tonic-gate 		tp->router = router;
21327c478bd9Sstevel@tonic-gate 		tp->preference = preference;
21337c478bd9Sstevel@tonic-gate 		tp->remaining_time = ttl;
21347c478bd9Sstevel@tonic-gate 		tp->in_kernel = 0;
21357c478bd9Sstevel@tonic-gate 		tp->next = table;
21367c478bd9Sstevel@tonic-gate 		table = tp;
21377c478bd9Sstevel@tonic-gate 	}
21387c478bd9Sstevel@tonic-gate 	if (!tp->in_kernel &&
21397c478bd9Sstevel@tonic-gate 	    (!best_preference || tp->preference == max_preference()) &&
21407c478bd9Sstevel@tonic-gate 	    tp->preference != IGNORE_PREFERENCE) {
21417c478bd9Sstevel@tonic-gate 		add_route(tp->router);
21427c478bd9Sstevel@tonic-gate 		tp->in_kernel++;
21437c478bd9Sstevel@tonic-gate 	}
21447c478bd9Sstevel@tonic-gate 	if (tp->preference == IGNORE_PREFERENCE && tp->in_kernel) {
21457c478bd9Sstevel@tonic-gate 		del_route(tp->router);
21467c478bd9Sstevel@tonic-gate 		tp->in_kernel = 0;
21477c478bd9Sstevel@tonic-gate 	}
21487c478bd9Sstevel@tonic-gate 	if (best_preference && changed_down) {
21497c478bd9Sstevel@tonic-gate 		/* Check if we should add routes */
21507c478bd9Sstevel@tonic-gate 		int new_max = max_preference();
21517c478bd9Sstevel@tonic-gate 		if (new_max != IGNORE_PREFERENCE) {
21527c478bd9Sstevel@tonic-gate 			tp = table;
21537c478bd9Sstevel@tonic-gate 			while (tp) {
21547c478bd9Sstevel@tonic-gate 				if (tp->preference == new_max &&
21557c478bd9Sstevel@tonic-gate 				    !tp->in_kernel) {
21567c478bd9Sstevel@tonic-gate 					add_route(tp->router);
21577c478bd9Sstevel@tonic-gate 					tp->in_kernel++;
21587c478bd9Sstevel@tonic-gate 				}
21597c478bd9Sstevel@tonic-gate 				tp = tp->next;
21607c478bd9Sstevel@tonic-gate 			}
21617c478bd9Sstevel@tonic-gate 		}
21627c478bd9Sstevel@tonic-gate 	}
21637c478bd9Sstevel@tonic-gate 	if (best_preference && (changed_up || changed_down)) {
21647c478bd9Sstevel@tonic-gate 		/* Check if we should remove routes already in the kernel */
21657c478bd9Sstevel@tonic-gate 		int new_max = max_preference();
21667c478bd9Sstevel@tonic-gate 		tp = table;
21677c478bd9Sstevel@tonic-gate 		while (tp) {
21687c478bd9Sstevel@tonic-gate 			if (tp->preference < new_max && tp->in_kernel) {
21697c478bd9Sstevel@tonic-gate 				del_route(tp->router);
21707c478bd9Sstevel@tonic-gate 				tp->in_kernel = 0;
21717c478bd9Sstevel@tonic-gate 			}
21727c478bd9Sstevel@tonic-gate 			tp = tp->next;
21737c478bd9Sstevel@tonic-gate 		}
21747c478bd9Sstevel@tonic-gate 	}
21757c478bd9Sstevel@tonic-gate }
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate #include <net/route.h>
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate static void
21817c478bd9Sstevel@tonic-gate add_route(struct in_addr addr)
21827c478bd9Sstevel@tonic-gate {
21837c478bd9Sstevel@tonic-gate 	if (debug)
21847c478bd9Sstevel@tonic-gate 		logdebug("Add default route to %s\n", pr_name(addr));
21857c478bd9Sstevel@tonic-gate 	rtioctl(addr, SIOCADDRT);
21867c478bd9Sstevel@tonic-gate }
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate static void
21897c478bd9Sstevel@tonic-gate del_route(struct in_addr addr)
21907c478bd9Sstevel@tonic-gate {
21917c478bd9Sstevel@tonic-gate 	if (debug)
21927c478bd9Sstevel@tonic-gate 		logdebug("Delete default route to %s\n", pr_name(addr));
21937c478bd9Sstevel@tonic-gate 	rtioctl(addr, SIOCDELRT);
21947c478bd9Sstevel@tonic-gate }
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate static void
21977c478bd9Sstevel@tonic-gate rtioctl(struct in_addr addr, int op)
21987c478bd9Sstevel@tonic-gate {
21997c478bd9Sstevel@tonic-gate 	int sock;
22007c478bd9Sstevel@tonic-gate 	struct rtentry rt;
22017c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
22027c478bd9Sstevel@tonic-gate 	bzero((char *)&rt, sizeof (struct rtentry));
22037c478bd9Sstevel@tonic-gate 	rt.rt_dst.sa_family = AF_INET;
22047c478bd9Sstevel@tonic-gate 	rt.rt_gateway.sa_family = AF_INET;
22057c478bd9Sstevel@tonic-gate 	sin = (struct sockaddr_in *)ALIGN(&rt.rt_gateway);
22067c478bd9Sstevel@tonic-gate 	sin->sin_addr = addr;
22077c478bd9Sstevel@tonic-gate 	rt.rt_flags = RTF_UP | RTF_GATEWAY;
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
22107c478bd9Sstevel@tonic-gate 	if (sock < 0) {
22117c478bd9Sstevel@tonic-gate 		logperror("rtioctl: socket");
22127c478bd9Sstevel@tonic-gate 		return;
22137c478bd9Sstevel@tonic-gate 	}
22147c478bd9Sstevel@tonic-gate 	if (ioctl(sock, op, (char *)&rt) < 0) {
22157c478bd9Sstevel@tonic-gate 		if (!(op == SIOCADDRT && errno == EEXIST))
22167c478bd9Sstevel@tonic-gate 			logperror("ioctl (add/delete route)");
22177c478bd9Sstevel@tonic-gate 	}
22187c478bd9Sstevel@tonic-gate 	(void) close(sock);
22197c478bd9Sstevel@tonic-gate }
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate /*
22247c478bd9Sstevel@tonic-gate  * LOGGER
22257c478bd9Sstevel@tonic-gate  */
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate #include <syslog.h>
22287c478bd9Sstevel@tonic-gate 
2229aee32e3dScarlsonj static int logging = 0;
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate static void
22327c478bd9Sstevel@tonic-gate initlog(void)
22337c478bd9Sstevel@tonic-gate {
22347c478bd9Sstevel@tonic-gate 	logging++;
22357c478bd9Sstevel@tonic-gate 	openlog("in.rdisc", LOG_PID | LOG_CONS, LOG_DAEMON);
22367c478bd9Sstevel@tonic-gate }
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate /* VARARGS1 */
22397c478bd9Sstevel@tonic-gate void
22407c478bd9Sstevel@tonic-gate logerr(fmt, a, b, c, d, e, f, g, h)
22417c478bd9Sstevel@tonic-gate 	char *fmt;
22427c478bd9Sstevel@tonic-gate {
22437c478bd9Sstevel@tonic-gate 	if (logging)
22447c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, fmt, a, b, c, d, e, f, g, h);
22457c478bd9Sstevel@tonic-gate 	else
22467c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, fmt, a, b, c, d, e, f, g, h);
22477c478bd9Sstevel@tonic-gate }
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate /* VARARGS1 */
22507c478bd9Sstevel@tonic-gate void
22517c478bd9Sstevel@tonic-gate logtrace(fmt, a, b, c, d, e, f, g, h)
22527c478bd9Sstevel@tonic-gate 	char *fmt;
22537c478bd9Sstevel@tonic-gate {
22547c478bd9Sstevel@tonic-gate 	if (logging)
22557c478bd9Sstevel@tonic-gate 		syslog(LOG_INFO, fmt, a, b, c, d, e, f, g, h);
22567c478bd9Sstevel@tonic-gate 	else
22577c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, fmt, a, b, c, d, e, f, g, h);
22587c478bd9Sstevel@tonic-gate }
22597c478bd9Sstevel@tonic-gate 
22607c478bd9Sstevel@tonic-gate /* VARARGS1 */
22617c478bd9Sstevel@tonic-gate void
22627c478bd9Sstevel@tonic-gate logdebug(fmt, a, b, c, d, e, f, g, h)
22637c478bd9Sstevel@tonic-gate 	char *fmt;
22647c478bd9Sstevel@tonic-gate {
22657c478bd9Sstevel@tonic-gate 	if (logging)
22667c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, fmt, a, b, c, d, e, f, g, h);
22677c478bd9Sstevel@tonic-gate 	else
22687c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, fmt, a, b, c, d, e, f, g, h);
22697c478bd9Sstevel@tonic-gate }
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate void
22727c478bd9Sstevel@tonic-gate logperror(str)
22737c478bd9Sstevel@tonic-gate 	char *str;
22747c478bd9Sstevel@tonic-gate {
22757c478bd9Sstevel@tonic-gate 	if (logging)
22767c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "%s: %s\n", str, strerror(errno));
22777c478bd9Sstevel@tonic-gate 	else
22787c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
22797c478bd9Sstevel@tonic-gate }
2280