xref: /titanic_51/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/in.rdisc.c (revision a192e900f6d2b0e1a822e3252c0dfd795ed49d76)
1*a192e900Samaguire /*
2*a192e900Samaguire  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3*a192e900Samaguire  * Use is subject to license terms.
4*a192e900Samaguire  */
5*a192e900Samaguire 
6*a192e900Samaguire /*
7*a192e900Samaguire  * Copyright (c) 1987 Regents of the University of California.
8*a192e900Samaguire  * All rights reserved.
9*a192e900Samaguire  *
10*a192e900Samaguire  * Redistribution and use in source and binary forms are permitted
11*a192e900Samaguire  * provided that the above copyright notice and this paragraph are
12*a192e900Samaguire  * duplicated in all such forms and that any documentation,
13*a192e900Samaguire  * advertising materials, and other materials related to such
14*a192e900Samaguire  * distribution and use acknowledge that the software was developed
15*a192e900Samaguire  * by the University of California, Berkeley. The name of the
16*a192e900Samaguire  * University may not be used to endorse or promote products derived
17*a192e900Samaguire  * from this software without specific prior written permission.
18*a192e900Samaguire  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19*a192e900Samaguire  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20*a192e900Samaguire  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21*a192e900Samaguire  */
22*a192e900Samaguire 
23*a192e900Samaguire #pragma ident	"%Z%%M%	%I%	%E% SMI"
24*a192e900Samaguire 
25*a192e900Samaguire #include <stdio.h>
26*a192e900Samaguire #include <errno.h>
27*a192e900Samaguire #include <signal.h>
28*a192e900Samaguire #include <sys/types.h>
29*a192e900Samaguire #include <sys/time.h>
30*a192e900Samaguire #include <sys/stat.h>
31*a192e900Samaguire 
32*a192e900Samaguire #include <sys/param.h>
33*a192e900Samaguire #include <sys/socket.h>
34*a192e900Samaguire #include <sys/file.h>
35*a192e900Samaguire 
36*a192e900Samaguire #include <sys/ioctl.h>
37*a192e900Samaguire #include <net/if.h>
38*a192e900Samaguire 
39*a192e900Samaguire #include <netinet/in_systm.h>
40*a192e900Samaguire #include <netinet/in.h>
41*a192e900Samaguire #include <netinet/ip.h>
42*a192e900Samaguire #include <netinet/ip_icmp.h>
43*a192e900Samaguire #include <netdb.h>
44*a192e900Samaguire #include <arpa/inet.h>
45*a192e900Samaguire 
46*a192e900Samaguire #include <fcntl.h>
47*a192e900Samaguire #include <strings.h>
48*a192e900Samaguire #include <stdlib.h>
49*a192e900Samaguire #include <unistd.h>
50*a192e900Samaguire #include <assert.h>
51*a192e900Samaguire 
52*a192e900Samaguire #ifdef lint
53*a192e900Samaguire #define	ALIGN(ptr)	(ptr ? 0 : 0)
54*a192e900Samaguire #else
55*a192e900Samaguire #define	ALIGN(ptr)	(ptr)
56*a192e900Samaguire #endif
57*a192e900Samaguire 
58*a192e900Samaguire #ifdef SYSV
59*a192e900Samaguire #define	signal(s, f)	sigset(s, (void (*)(int))f)
60*a192e900Samaguire #define	random()	rand()
61*a192e900Samaguire #endif
62*a192e900Samaguire 
63*a192e900Samaguire #define	ALL_HOSTS_ADDRESS		"224.0.0.1"
64*a192e900Samaguire #define	ALL_ROUTERS_ADDRESS		"224.0.0.2"
65*a192e900Samaguire 
66*a192e900Samaguire #define	MAXIFS 256
67*a192e900Samaguire 
68*a192e900Samaguire /* For router advertisement */
69*a192e900Samaguire struct icmp_ra {
70*a192e900Samaguire 	uchar_t		icmp_type;	/* type of message, see below */
71*a192e900Samaguire 	uchar_t		icmp_code;	/* type sub code */
72*a192e900Samaguire 	ushort_t	icmp_cksum;	/* ones complement cksum of struct */
73*a192e900Samaguire 	uchar_t		icmp_num_addrs;
74*a192e900Samaguire 	uchar_t		icmp_wpa;	/* Words per address */
75*a192e900Samaguire 	short		icmp_lifetime;
76*a192e900Samaguire };
77*a192e900Samaguire 
78*a192e900Samaguire struct icmp_ra_addr {
79*a192e900Samaguire 	ulong_t	addr;
80*a192e900Samaguire 	ulong_t preference;
81*a192e900Samaguire };
82*a192e900Samaguire 
83*a192e900Samaguire /* Router constants */
84*a192e900Samaguire #define	MAX_INITIAL_ADVERT_INTERVAL	16
85*a192e900Samaguire #define	MAX_INITIAL_ADVERTISEMENTS 	3
86*a192e900Samaguire #define	MAX_RESPONSE_DELAY		2	/* Not used */
87*a192e900Samaguire 
88*a192e900Samaguire /* Host constants */
89*a192e900Samaguire #define	MAX_SOLICITATIONS		3
90*a192e900Samaguire #define	SOLICITATION_INTERVAL		3
91*a192e900Samaguire #define	MAX_SOLICITATION_DELAY		1	/* Not used */
92*a192e900Samaguire 
93*a192e900Samaguire #define	IGNORE_PREFERENCE	0x80000000	/* Maximum negative */
94*a192e900Samaguire 
95*a192e900Samaguire #define	MAX_ADV_INT 600
96*a192e900Samaguire 
97*a192e900Samaguire 
98*a192e900Samaguire /*
99*a192e900Samaguire  * A doubly linked list of all physical interfaces that each contain a
100*a192e900Samaguire  * doubly linked list of logical interfaces aka IP addresses.
101*a192e900Samaguire  */
102*a192e900Samaguire struct phyint {
103*a192e900Samaguire 	char		pi_name[IFNAMSIZ];	/* Used to identify it */
104*a192e900Samaguire 	int		pi_state;		/* See below */
105*a192e900Samaguire 	struct logint	*pi_logical_first;
106*a192e900Samaguire 	struct logint	*pi_logical_last;
107*a192e900Samaguire 	struct phyint	*pi_next;
108*a192e900Samaguire 	struct phyint	*pi_prev;
109*a192e900Samaguire };
110*a192e900Samaguire 
111*a192e900Samaguire struct logint {
112*a192e900Samaguire 	char		li_name[IFNAMSIZ];	/* Used to identify it */
113*a192e900Samaguire 	int		li_state;		/* See below */
114*a192e900Samaguire 	struct in_addr	li_address;	/* Used to identify the interface */
115*a192e900Samaguire 	struct in_addr	li_localaddr;	/* Actual address of the interface */
116*a192e900Samaguire 	int		li_preference;
117*a192e900Samaguire 	int		li_index;	/* interface index (SIOCGLIFINDEX) */
118*a192e900Samaguire 	uint64_t	li_flags;
119*a192e900Samaguire 	struct in_addr	li_bcastaddr;
120*a192e900Samaguire 	struct in_addr	li_remoteaddr;
121*a192e900Samaguire 	struct in_addr	li_netmask;
122*a192e900Samaguire 	struct logint	*li_next;	/* Next logical for this physical */
123*a192e900Samaguire 	struct logint	*li_prev;	/* Prev logical for this physical */
124*a192e900Samaguire 	struct phyint	*li_physical;	/* Back pointer */
125*a192e900Samaguire };
126*a192e900Samaguire 
127*a192e900Samaguire struct phyint *phyint;
128*a192e900Samaguire int num_usable_interfaces;		/* Num used for sending/receiving */
129*a192e900Samaguire 
130*a192e900Samaguire /*
131*a192e900Samaguire  * State bits
132*a192e900Samaguire  */
133*a192e900Samaguire #define	ST_MARKED	0x01		/* To determine removed interfaces */
134*a192e900Samaguire #define	ST_JOINED	0x02		/* Joined multicast group */
135*a192e900Samaguire #define	ST_DELETED	0x04		/* Interface should be ignored */
136*a192e900Samaguire 
137*a192e900Samaguire /* Function prototypes */
138*a192e900Samaguire static void	solicitor(struct sockaddr_in *sin);
139*a192e900Samaguire static void	advertise(struct sockaddr_in *sin);
140*a192e900Samaguire 
141*a192e900Samaguire static void	age_table(int time);
142*a192e900Samaguire static void	flush_unreachable_routers(void);
143*a192e900Samaguire static void	record_router(struct in_addr router, long preference, int ttl);
144*a192e900Samaguire 
145*a192e900Samaguire static void	add_route(struct in_addr addr);
146*a192e900Samaguire static void	del_route(struct in_addr addr);
147*a192e900Samaguire static void	rtioctl(struct in_addr addr, int op);
148*a192e900Samaguire 
149*a192e900Samaguire static int	support_multicast(void);
150*a192e900Samaguire static int	sendbcast(int s, char *packet, int packetlen);
151*a192e900Samaguire static int	sendbcastif(int s, char *packet, int packetlen,
152*a192e900Samaguire 		    struct logint *li);
153*a192e900Samaguire static int	sendmcast(int s, char *packet, int packetlen,
154*a192e900Samaguire 		    struct sockaddr_in *sin);
155*a192e900Samaguire static int	sendmcastif(int s, char *packet, int packetlen,
156*a192e900Samaguire 		    struct sockaddr_in *sin, struct logint *li);
157*a192e900Samaguire 
158*a192e900Samaguire static int	ismulticast(struct sockaddr_in *sin);
159*a192e900Samaguire static int	isbroadcast(struct sockaddr_in *sin);
160*a192e900Samaguire int		in_cksum(ushort_t *addr, int len);
161*a192e900Samaguire static struct logint *find_directly_connected_logint(struct in_addr in,
162*a192e900Samaguire     struct phyint *pi);
163*a192e900Samaguire static void	force_preference(int preference);
164*a192e900Samaguire 
165*a192e900Samaguire static void	timer(void);
166*a192e900Samaguire static void	finish(void);
167*a192e900Samaguire static void	report(void);
168*a192e900Samaguire static void	report_interfaces(void);
169*a192e900Samaguire static void	report_routes(void);
170*a192e900Samaguire static void	reinitifs(void);
171*a192e900Samaguire 
172*a192e900Samaguire static struct phyint *find_phyint(char *name);
173*a192e900Samaguire static struct phyint *add_phyint(char *name);
174*a192e900Samaguire static void	free_phyint(struct phyint *pi);
175*a192e900Samaguire static struct logint *find_logint(struct phyint *pi, char *name);
176*a192e900Samaguire static struct logint *add_logint(struct phyint *pi, char *name);
177*a192e900Samaguire static void	free_logint(struct logint *li);
178*a192e900Samaguire 
179*a192e900Samaguire static void	deleted_phyint(struct phyint *pi, int s,
180*a192e900Samaguire 		    struct sockaddr_in *joinaddr);
181*a192e900Samaguire static void	added_logint(struct logint *li, int s,
182*a192e900Samaguire 		    struct sockaddr_in *joinaddr);
183*a192e900Samaguire static void	deleted_logint(struct logint *li, struct logint *newli, int s,
184*a192e900Samaguire 		    struct sockaddr_in *joinaddr);
185*a192e900Samaguire 
186*a192e900Samaguire static int	initifs(int s, struct sockaddr_in *joinaddr, int preference);
187*a192e900Samaguire static boolean_t getconfig(int sock, uint64_t if_flags, struct sockaddr *addr,
188*a192e900Samaguire 		    struct ifreq *ifr, struct logint *li);
189*a192e900Samaguire 
190*a192e900Samaguire static void	pr_pack(char *buf, int cc, struct sockaddr_in *from);
191*a192e900Samaguire char		*pr_name(struct in_addr addr);
192*a192e900Samaguire char		*pr_type(int t);
193*a192e900Samaguire 
194*a192e900Samaguire static void	initlog(void);
195*a192e900Samaguire void		logerr(), logtrace(), logdebug(), logperror();
196*a192e900Samaguire 
197*a192e900Samaguire /* Local variables */
198*a192e900Samaguire 
199*a192e900Samaguire #define	MAXPACKET	4096	/* max packet size */
200*a192e900Samaguire uchar_t	packet[MAXPACKET];
201*a192e900Samaguire 
202*a192e900Samaguire char usage[] =
203*a192e900Samaguire "Usage:	rdisc [-s] [-v] [-f] [-a] [send_address] [receive_address]\n"
204*a192e900Samaguire "	rdisc -r [-v] [-p <preference>] [-T <secs>] \n"
205*a192e900Samaguire "		[send_address] [receive_address]\n";
206*a192e900Samaguire 
207*a192e900Samaguire 
208*a192e900Samaguire int s;				/* Socket file descriptor */
209*a192e900Samaguire struct sockaddr_in whereto;	/* Address to send to */
210*a192e900Samaguire struct sockaddr_in g_joinaddr;	/* Address to receive on */
211*a192e900Samaguire char    *sendaddress, *recvaddress;	/* For logging purposes only */
212*a192e900Samaguire 
213*a192e900Samaguire /* Common variables */
214*a192e900Samaguire int verbose = 0;
215*a192e900Samaguire int debug = 0;
216*a192e900Samaguire int trace = 0;
217*a192e900Samaguire int start_solicit = 0;	/* -s parameter set */
218*a192e900Samaguire int solicit = 0;	/* Are we currently sending solicitations? */
219*a192e900Samaguire int responder;
220*a192e900Samaguire int ntransmitted = 0;
221*a192e900Samaguire int nreceived = 0;
222*a192e900Samaguire int forever = 0;	/* Never give up on host. If 0 defer fork until */
223*a192e900Samaguire 			/* first response.				*/
224*a192e900Samaguire 
225*a192e900Samaguire /* Router variables */
226*a192e900Samaguire int max_adv_int = MAX_ADV_INT;
227*a192e900Samaguire int min_adv_int;
228*a192e900Samaguire int lifetime;
229*a192e900Samaguire int initial_advert_interval = MAX_INITIAL_ADVERT_INTERVAL;
230*a192e900Samaguire int initial_advertisements = MAX_INITIAL_ADVERTISEMENTS;
231*a192e900Samaguire ulong_t g_preference = 0;	/* Setable with -p option */
232*a192e900Samaguire 
233*a192e900Samaguire /* Host variables */
234*a192e900Samaguire int max_solicitations = MAX_SOLICITATIONS;
235*a192e900Samaguire unsigned int solicitation_interval = SOLICITATION_INTERVAL;
236*a192e900Samaguire int best_preference = 1; 	/* Set to record only the router(s) with the */
237*a192e900Samaguire 				/* best preference in the kernel. Not set   */
238*a192e900Samaguire 				/* puts all routes in the kernel.	    */
239*a192e900Samaguire 
240*a192e900Samaguire 
241*a192e900Samaguire static void
242*a192e900Samaguire prusage()
243*a192e900Samaguire {
244*a192e900Samaguire 	(void) fprintf(stderr, usage);
245*a192e900Samaguire 	exit(1);
246*a192e900Samaguire }
247*a192e900Samaguire 
248*a192e900Samaguire static int	sock = -1;
249*a192e900Samaguire 
250*a192e900Samaguire static void
251*a192e900Samaguire do_fork()
252*a192e900Samaguire {
253*a192e900Samaguire 	int t;
254*a192e900Samaguire 
255*a192e900Samaguire 	if (trace)
256*a192e900Samaguire 		return;
257*a192e900Samaguire 
258*a192e900Samaguire 	if (fork())
259*a192e900Samaguire 		exit(0);
260*a192e900Samaguire 	for (t = 0; t < 20; t++)
261*a192e900Samaguire 		if (t != s)
262*a192e900Samaguire 			(void) close(t);
263*a192e900Samaguire 	sock = -1;
264*a192e900Samaguire 	(void) open("/", 0);
265*a192e900Samaguire 	(void) dup2(0, 1);
266*a192e900Samaguire 	(void) dup2(0, 2);
267*a192e900Samaguire #ifndef SYSV
268*a192e900Samaguire 	t = open("/dev/tty", 2);
269*a192e900Samaguire 	if (t >= 0) {
270*a192e900Samaguire 		(void) ioctl(t, TIOCNOTTY, (char *)0);
271*a192e900Samaguire 		(void) close(t);
272*a192e900Samaguire 	}
273*a192e900Samaguire #else
274*a192e900Samaguire 	(void) setpgrp();
275*a192e900Samaguire #endif
276*a192e900Samaguire 	initlog();
277*a192e900Samaguire }
278*a192e900Samaguire 
279*a192e900Samaguire /*
280*a192e900Samaguire  *			M A I N
281*a192e900Samaguire  */
282*a192e900Samaguire int
283*a192e900Samaguire main(int argc, char *argv[])
284*a192e900Samaguire {
285*a192e900Samaguire #ifndef SYSV
286*a192e900Samaguire 	struct sigvec sv;
287*a192e900Samaguire #endif
288*a192e900Samaguire 	struct sockaddr_in from;
289*a192e900Samaguire 	char **av = argv;
290*a192e900Samaguire 	struct sockaddr_in *to = &whereto;
291*a192e900Samaguire 	ulong_t val;
292*a192e900Samaguire 
293*a192e900Samaguire 	min_adv_int = (max_adv_int * 3 / 4);
294*a192e900Samaguire 	lifetime = (3*max_adv_int);
295*a192e900Samaguire 
296*a192e900Samaguire 	argc--, av++;
297*a192e900Samaguire 	while (argc > 0 && *av[0] == '-') {
298*a192e900Samaguire 	    while (*++av[0])
299*a192e900Samaguire 		switch (*av[0]) {
300*a192e900Samaguire 		case 'd':
301*a192e900Samaguire 			debug = 1;
302*a192e900Samaguire 			break;
303*a192e900Samaguire 		case 't':
304*a192e900Samaguire 			trace = 1;
305*a192e900Samaguire 			break;
306*a192e900Samaguire 		case 'v':
307*a192e900Samaguire 			verbose++;
308*a192e900Samaguire 			break;
309*a192e900Samaguire 		case 's':
310*a192e900Samaguire 			start_solicit = solicit = 1;
311*a192e900Samaguire 			break;
312*a192e900Samaguire 		case 'r':
313*a192e900Samaguire 			responder = 1;
314*a192e900Samaguire 			break;
315*a192e900Samaguire 		case 'a':
316*a192e900Samaguire 			best_preference = 0;
317*a192e900Samaguire 			break;
318*a192e900Samaguire 		case 'b':
319*a192e900Samaguire 			best_preference = 1;
320*a192e900Samaguire 			break;
321*a192e900Samaguire 		case 'f':
322*a192e900Samaguire 			forever = 1;
323*a192e900Samaguire 			break;
324*a192e900Samaguire 		case 'T':
325*a192e900Samaguire 			argc--, av++;
326*a192e900Samaguire 			if (argc != 0) {
327*a192e900Samaguire 				val = strtol(av[0], (char **)NULL, 0);
328*a192e900Samaguire 				if (val < 4 || val > 1800) {
329*a192e900Samaguire 					(void) fprintf(stderr,
330*a192e900Samaguire 					    "Bad Max Advertisement Interval\n");
331*a192e900Samaguire 					exit(1);
332*a192e900Samaguire 				}
333*a192e900Samaguire 				max_adv_int = val;
334*a192e900Samaguire 				min_adv_int = (max_adv_int * 3 / 4);
335*a192e900Samaguire 				lifetime = (3*max_adv_int);
336*a192e900Samaguire 			} else {
337*a192e900Samaguire 				prusage();
338*a192e900Samaguire 				/* NOTREACHED */
339*a192e900Samaguire 			}
340*a192e900Samaguire 			goto next;
341*a192e900Samaguire 		case 'p':
342*a192e900Samaguire 			argc--, av++;
343*a192e900Samaguire 			if (argc != 0) {
344*a192e900Samaguire 				val = strtoul(av[0], (char **)NULL, 0);
345*a192e900Samaguire 				g_preference = val;
346*a192e900Samaguire 			} else {
347*a192e900Samaguire 				prusage();
348*a192e900Samaguire 				/* NOTREACHED */
349*a192e900Samaguire 			}
350*a192e900Samaguire 			goto next;
351*a192e900Samaguire 		default:
352*a192e900Samaguire 			prusage();
353*a192e900Samaguire 			/* NOTREACHED */
354*a192e900Samaguire 		}
355*a192e900Samaguire 	next:
356*a192e900Samaguire 		argc--, av++;
357*a192e900Samaguire 	}
358*a192e900Samaguire 	if (argc < 1)  {
359*a192e900Samaguire 		if (support_multicast()) {
360*a192e900Samaguire 			if (responder)
361*a192e900Samaguire 				sendaddress = ALL_HOSTS_ADDRESS;
362*a192e900Samaguire 			else
363*a192e900Samaguire 				sendaddress = ALL_ROUTERS_ADDRESS;
364*a192e900Samaguire 		} else
365*a192e900Samaguire 			sendaddress = "255.255.255.255";
366*a192e900Samaguire 	} else {
367*a192e900Samaguire 		sendaddress = av[0];
368*a192e900Samaguire 		argc--;
369*a192e900Samaguire 	}
370*a192e900Samaguire 	if (argc < 1) {
371*a192e900Samaguire 		if (support_multicast()) {
372*a192e900Samaguire 			if (responder)
373*a192e900Samaguire 				recvaddress = ALL_ROUTERS_ADDRESS;
374*a192e900Samaguire 			else
375*a192e900Samaguire 				recvaddress = ALL_HOSTS_ADDRESS;
376*a192e900Samaguire 		} else
377*a192e900Samaguire 			recvaddress = "255.255.255.255";
378*a192e900Samaguire 	} else {
379*a192e900Samaguire 		recvaddress = av[0];
380*a192e900Samaguire 		argc--;
381*a192e900Samaguire 	}
382*a192e900Samaguire 	if (argc != 0) {
383*a192e900Samaguire 		(void) fprintf(stderr, "Extra paramaters\n");
384*a192e900Samaguire 		prusage();
385*a192e900Samaguire 		/* NOTREACHED */
386*a192e900Samaguire 	}
387*a192e900Samaguire 
388*a192e900Samaguire 	if (solicit && responder) {
389*a192e900Samaguire 		prusage();
390*a192e900Samaguire 		/* NOTREACHED */
391*a192e900Samaguire 	}
392*a192e900Samaguire 
393*a192e900Samaguire 	if (!(solicit && !forever)) {
394*a192e900Samaguire 		do_fork();
395*a192e900Samaguire 	}
396*a192e900Samaguire 
397*a192e900Samaguire 	bzero((char *)&whereto, sizeof (struct sockaddr_in));
398*a192e900Samaguire 	to->sin_family = AF_INET;
399*a192e900Samaguire 	to->sin_addr.s_addr = inet_addr(sendaddress);
400*a192e900Samaguire 	if (to->sin_addr.s_addr == (unsigned long)-1) {
401*a192e900Samaguire 		logerr("in.rdisc: bad address %s\n", sendaddress);
402*a192e900Samaguire 		exit(1);
403*a192e900Samaguire 	}
404*a192e900Samaguire 
405*a192e900Samaguire 	bzero((char *)&g_joinaddr, sizeof (struct sockaddr_in));
406*a192e900Samaguire 	g_joinaddr.sin_family = AF_INET;
407*a192e900Samaguire 	g_joinaddr.sin_addr.s_addr = inet_addr(recvaddress);
408*a192e900Samaguire 	if (g_joinaddr.sin_addr.s_addr == (unsigned long)-1) {
409*a192e900Samaguire 		logerr("in.rdisc: bad address %s\n", recvaddress);
410*a192e900Samaguire 		exit(1);
411*a192e900Samaguire 	}
412*a192e900Samaguire 
413*a192e900Samaguire 	if (responder) {
414*a192e900Samaguire #ifdef SYSV
415*a192e900Samaguire 		srand((int)gethostid());
416*a192e900Samaguire #else
417*a192e900Samaguire 		srandom((int)gethostid());
418*a192e900Samaguire #endif
419*a192e900Samaguire 	}
420*a192e900Samaguire 
421*a192e900Samaguire 	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
422*a192e900Samaguire 		logperror("socket");
423*a192e900Samaguire 		exit(5);
424*a192e900Samaguire 	}
425*a192e900Samaguire 
426*a192e900Samaguire #ifdef SYSV
427*a192e900Samaguire 	setvbuf(stdout, NULL, _IOLBF, 0);
428*a192e900Samaguire #else
429*a192e900Samaguire 	setlinebuf(stdout);
430*a192e900Samaguire #endif
431*a192e900Samaguire 
432*a192e900Samaguire 	(void) signal(SIGINT, finish);
433*a192e900Samaguire 	(void) signal(SIGTERM, finish);
434*a192e900Samaguire 	(void) signal(SIGHUP, reinitifs);
435*a192e900Samaguire 	(void) signal(SIGUSR1, report);
436*a192e900Samaguire 
437*a192e900Samaguire 	if (initifs(s, &g_joinaddr, g_preference) < 0) {
438*a192e900Samaguire 		logerr("Failed initializing interfaces\n");
439*a192e900Samaguire 		exit(2);
440*a192e900Samaguire 	}
441*a192e900Samaguire 
442*a192e900Samaguire 	/*
443*a192e900Samaguire 	 * If there are no usable interfaces and we are soliciting
444*a192e900Samaguire 	 * waiting for to return an exit code (i.e. forever isn't set)
445*a192e900Samaguire 	 * give up immediately.
446*a192e900Samaguire 	 */
447*a192e900Samaguire 	if (num_usable_interfaces == 0 && solicit && !forever) {
448*a192e900Samaguire 		logerr("in.rdisc: No interfaces up\n");
449*a192e900Samaguire 		exit(5);
450*a192e900Samaguire 	}
451*a192e900Samaguire 
452*a192e900Samaguire #ifdef SYSV
453*a192e900Samaguire 	(void) signal(SIGALRM, timer);
454*a192e900Samaguire #else
455*a192e900Samaguire 	/*
456*a192e900Samaguire 	 * Make sure that this signal actually interrupts (rather than
457*a192e900Samaguire 	 * restarts) the recvfrom call below.
458*a192e900Samaguire 	 */
459*a192e900Samaguire 	sv.sv_handler = timer;
460*a192e900Samaguire 	sv.sv_mask = 0;
461*a192e900Samaguire 	sv.sv_flags = SV_INTERRUPT;
462*a192e900Samaguire 	(void) sigvec(SIGALRM, &sv, (struct sigvec *)NULL);
463*a192e900Samaguire #endif
464*a192e900Samaguire 	timer();	/* start things going */
465*a192e900Samaguire 
466*a192e900Samaguire 	for (;;) {
467*a192e900Samaguire 		int len = sizeof (packet);
468*a192e900Samaguire 		socklen_t fromlen = (socklen_t)sizeof (from);
469*a192e900Samaguire 		int cc;
470*a192e900Samaguire 		sigset_t newmask, oldmask;
471*a192e900Samaguire 
472*a192e900Samaguire 		if ((cc = recvfrom(s, (char *)packet, len, 0,
473*a192e900Samaguire 		    (struct sockaddr *)&from,
474*a192e900Samaguire 		    &fromlen)) < 0) {
475*a192e900Samaguire 			if (errno == EINTR)
476*a192e900Samaguire 				continue;
477*a192e900Samaguire 			logperror("recvfrom");
478*a192e900Samaguire 			continue;
479*a192e900Samaguire 		}
480*a192e900Samaguire 		/* Block all signals while processing */
481*a192e900Samaguire 		(void) sigfillset(&newmask);
482*a192e900Samaguire 		(void) sigprocmask(SIG_SETMASK, &newmask, &oldmask);
483*a192e900Samaguire 		pr_pack((char *)packet, cc, &from);
484*a192e900Samaguire 		(void) sigprocmask(SIG_SETMASK, &oldmask, NULL);
485*a192e900Samaguire 	}
486*a192e900Samaguire 	/* NOTREACHED */
487*a192e900Samaguire }
488*a192e900Samaguire 
489*a192e900Samaguire static void
490*a192e900Samaguire report(void)
491*a192e900Samaguire {
492*a192e900Samaguire 	report_interfaces();
493*a192e900Samaguire 	report_routes();
494*a192e900Samaguire }
495*a192e900Samaguire 
496*a192e900Samaguire #define	TIMER_INTERVAL	6
497*a192e900Samaguire #define	GETIFCONF_TIMER	30
498*a192e900Samaguire 
499*a192e900Samaguire static int left_until_advertise;
500*a192e900Samaguire 
501*a192e900Samaguire /* Called every TIMER_INTERVAL */
502*a192e900Samaguire static void
503*a192e900Samaguire timer(void)
504*a192e900Samaguire {
505*a192e900Samaguire 	static int time;
506*a192e900Samaguire 	static int left_until_getifconf;
507*a192e900Samaguire 	static int left_until_solicit;
508*a192e900Samaguire 
509*a192e900Samaguire 	time += TIMER_INTERVAL;
510*a192e900Samaguire 
511*a192e900Samaguire 	left_until_getifconf -= TIMER_INTERVAL;
512*a192e900Samaguire 	left_until_advertise -= TIMER_INTERVAL;
513*a192e900Samaguire 	left_until_solicit -= TIMER_INTERVAL;
514*a192e900Samaguire 
515*a192e900Samaguire 	if (left_until_getifconf < 0) {
516*a192e900Samaguire 		(void) initifs(s, &g_joinaddr, g_preference);
517*a192e900Samaguire 		left_until_getifconf = GETIFCONF_TIMER;
518*a192e900Samaguire 	}
519*a192e900Samaguire 	if (responder && left_until_advertise <= 0) {
520*a192e900Samaguire 		ntransmitted++;
521*a192e900Samaguire 		advertise(&whereto);
522*a192e900Samaguire 		if (ntransmitted < initial_advertisements)
523*a192e900Samaguire 			left_until_advertise = initial_advert_interval;
524*a192e900Samaguire 		else
525*a192e900Samaguire 			left_until_advertise = min_adv_int +
526*a192e900Samaguire 				((max_adv_int - min_adv_int) *
527*a192e900Samaguire 				(random() % 1000)/1000);
528*a192e900Samaguire 	} else if (solicit && left_until_solicit <= 0) {
529*a192e900Samaguire 		if (ntransmitted < max_solicitations) {
530*a192e900Samaguire 			ntransmitted++;
531*a192e900Samaguire 			solicitor(&whereto);
532*a192e900Samaguire 			left_until_solicit = solicitation_interval;
533*a192e900Samaguire 		} else {
534*a192e900Samaguire 			solicit = 0;
535*a192e900Samaguire 			if (!forever && nreceived == 0)
536*a192e900Samaguire 				exit(5);
537*a192e900Samaguire 		}
538*a192e900Samaguire 	}
539*a192e900Samaguire 	age_table(TIMER_INTERVAL);
540*a192e900Samaguire 	(void) alarm(TIMER_INTERVAL);
541*a192e900Samaguire }
542*a192e900Samaguire 
543*a192e900Samaguire /*
544*a192e900Samaguire  *			S O L I C I T O R
545*a192e900Samaguire  *
546*a192e900Samaguire  * Compose and transmit an ICMP ROUTER SOLICITATION REQUEST packet.
547*a192e900Samaguire  * The IP packet will be added on by the kernel.
548*a192e900Samaguire  */
549*a192e900Samaguire static void
550*a192e900Samaguire solicitor(struct sockaddr_in *sin)
551*a192e900Samaguire {
552*a192e900Samaguire 	static uchar_t outpack[MAXPACKET];
553*a192e900Samaguire 	register struct icmp *icp = (struct icmp *)ALIGN(outpack);
554*a192e900Samaguire 	int packetlen, i;
555*a192e900Samaguire 
556*a192e900Samaguire 	if (verbose) {
557*a192e900Samaguire 		logtrace("Sending solicitation to %s\n",
558*a192e900Samaguire 			pr_name(sin->sin_addr));
559*a192e900Samaguire 	}
560*a192e900Samaguire 	icp->icmp_type = ICMP_ROUTERSOLICIT;
561*a192e900Samaguire 	icp->icmp_code = 0;
562*a192e900Samaguire 	icp->icmp_cksum = 0;
563*a192e900Samaguire 	icp->icmp_void = 0; /* Reserved */
564*a192e900Samaguire 	packetlen = 8;
565*a192e900Samaguire 
566*a192e900Samaguire 	/* Compute ICMP checksum here */
567*a192e900Samaguire 	icp->icmp_cksum = in_cksum((ushort_t *)icp, packetlen);
568*a192e900Samaguire 
569*a192e900Samaguire 	if (isbroadcast(sin))
570*a192e900Samaguire 		i = sendbcast(s, (char *)outpack, packetlen);
571*a192e900Samaguire 	else if (ismulticast(sin))
572*a192e900Samaguire 		i = sendmcast(s, (char *)outpack, packetlen, sin);
573*a192e900Samaguire 	else {
574*a192e900Samaguire 		struct logint *li;
575*a192e900Samaguire 
576*a192e900Samaguire 		li = find_directly_connected_logint(sin->sin_addr, NULL);
577*a192e900Samaguire 		if (li != NULL && (li->li_flags & IFF_NORTEXCH)) {
578*a192e900Samaguire 			if (verbose) {
579*a192e900Samaguire 				logtrace("Suppressing sending %s on %s "
580*a192e900Samaguire 				    "(no route exchange on interface)\n",
581*a192e900Samaguire 				    pr_type((int)icp->icmp_type), li->li_name);
582*a192e900Samaguire 			}
583*a192e900Samaguire 			return;
584*a192e900Samaguire 		} else {
585*a192e900Samaguire 			i = sendto(s, (char *)outpack, packetlen, 0,
586*a192e900Samaguire 			    (struct sockaddr *)sin, sizeof (struct sockaddr));
587*a192e900Samaguire 		}
588*a192e900Samaguire 	}
589*a192e900Samaguire 
590*a192e900Samaguire 	if (i < 0 || i != packetlen)  {
591*a192e900Samaguire 		if (i < 0) {
592*a192e900Samaguire 		    logperror("sendto");
593*a192e900Samaguire 		}
594*a192e900Samaguire 		logerr("wrote %s %d chars, ret=%d\n",
595*a192e900Samaguire 			sendaddress, packetlen, i);
596*a192e900Samaguire 	}
597*a192e900Samaguire }
598*a192e900Samaguire 
599*a192e900Samaguire /*
600*a192e900Samaguire  *			A D V E R T I S E
601*a192e900Samaguire  *
602*a192e900Samaguire  * Compose and transmit an ICMP ROUTER ADVERTISEMENT packet.
603*a192e900Samaguire  * The IP packet will be added on by the kernel.
604*a192e900Samaguire  */
605*a192e900Samaguire static void
606*a192e900Samaguire advertise(struct sockaddr_in *sin)
607*a192e900Samaguire {
608*a192e900Samaguire 	struct phyint *pi;
609*a192e900Samaguire 	struct logint *li, *li_tmp;
610*a192e900Samaguire 	static uchar_t outpack[MAXPACKET];
611*a192e900Samaguire 	register struct icmp_ra *rap = (struct icmp_ra *)ALIGN(outpack);
612*a192e900Samaguire 	struct icmp_ra_addr *ap;
613*a192e900Samaguire 	int packetlen, cc;
614*a192e900Samaguire 
615*a192e900Samaguire 	if (verbose) {
616*a192e900Samaguire 		logtrace("Sending advertisement to %s\n",
617*a192e900Samaguire 			pr_name(sin->sin_addr));
618*a192e900Samaguire 	}
619*a192e900Samaguire 
620*a192e900Samaguire 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
621*a192e900Samaguire 		rap->icmp_type = ICMP_ROUTERADVERT;
622*a192e900Samaguire 		rap->icmp_code = 0;
623*a192e900Samaguire 		rap->icmp_cksum = 0;
624*a192e900Samaguire 		rap->icmp_num_addrs = 0;
625*a192e900Samaguire 		rap->icmp_wpa = 2;
626*a192e900Samaguire 		rap->icmp_lifetime = htons(lifetime);
627*a192e900Samaguire 		packetlen = ICMP_MINLEN;
628*a192e900Samaguire 
629*a192e900Samaguire 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
630*a192e900Samaguire 			if (li->li_state & ST_DELETED)
631*a192e900Samaguire 				continue;
632*a192e900Samaguire 
633*a192e900Samaguire 			/*
634*a192e900Samaguire 			 * XXX Just truncate the list of addresses.
635*a192e900Samaguire 			 * Should probably send multiple packets.
636*a192e900Samaguire 			 */
637*a192e900Samaguire 			if (packetlen + rap->icmp_wpa * 4 > sizeof (outpack)) {
638*a192e900Samaguire 				if (debug)
639*a192e900Samaguire 					logdebug("full packet: %d addresses\n",
640*a192e900Samaguire 						rap->icmp_num_addrs);
641*a192e900Samaguire 				break;
642*a192e900Samaguire 			}
643*a192e900Samaguire 			ap = (struct icmp_ra_addr *)ALIGN(outpack + packetlen);
644*a192e900Samaguire 			ap->addr = li->li_localaddr.s_addr;
645*a192e900Samaguire 			ap->preference = htonl(li->li_preference);
646*a192e900Samaguire 			packetlen += rap->icmp_wpa * 4;
647*a192e900Samaguire 			rap->icmp_num_addrs++;
648*a192e900Samaguire 		}
649*a192e900Samaguire 
650*a192e900Samaguire 		if (rap->icmp_num_addrs == 0)
651*a192e900Samaguire 			continue;
652*a192e900Samaguire 
653*a192e900Samaguire 		/* Compute ICMP checksum here */
654*a192e900Samaguire 		rap->icmp_cksum = in_cksum((ushort_t *)rap, packetlen);
655*a192e900Samaguire 
656*a192e900Samaguire 		if (isbroadcast(sin))
657*a192e900Samaguire 			cc = sendbcastif(s, (char *)outpack, packetlen,
658*a192e900Samaguire 			    pi->pi_logical_first);
659*a192e900Samaguire 		else if (ismulticast(sin))
660*a192e900Samaguire 			cc = sendmcastif(s, (char *)outpack, packetlen, sin,
661*a192e900Samaguire 			    pi->pi_logical_first);
662*a192e900Samaguire 		else {
663*a192e900Samaguire 			/*
664*a192e900Samaguire 			 * Verify that the physical interface matches the
665*a192e900Samaguire 			 * destination address.
666*a192e900Samaguire 			 */
667*a192e900Samaguire 			li_tmp = find_directly_connected_logint(sin->sin_addr,
668*a192e900Samaguire 			    pi);
669*a192e900Samaguire 			if (li_tmp == NULL)
670*a192e900Samaguire 				continue;
671*a192e900Samaguire 			if (li_tmp->li_flags & IFF_NORTEXCH) {
672*a192e900Samaguire 				if (verbose) {
673*a192e900Samaguire 					logtrace("Suppressing sending %s on %s "
674*a192e900Samaguire 					    "(no route exchange on "
675*a192e900Samaguire 					    "interface)\n",
676*a192e900Samaguire 					    pr_type((int)rap->icmp_type),
677*a192e900Samaguire 					    li_tmp->li_name);
678*a192e900Samaguire 				}
679*a192e900Samaguire 				continue;
680*a192e900Samaguire 			}
681*a192e900Samaguire 			if (debug) {
682*a192e900Samaguire 				logdebug("Unicast to %s ",
683*a192e900Samaguire 				    pr_name(sin->sin_addr));
684*a192e900Samaguire 				logdebug("on interface %s\n", pi->pi_name);
685*a192e900Samaguire 			}
686*a192e900Samaguire 			cc = sendto(s, (char *)outpack, packetlen, 0,
687*a192e900Samaguire 			    (struct sockaddr *)sin, sizeof (struct sockaddr));
688*a192e900Samaguire 		}
689*a192e900Samaguire 		if (cc < 0 || cc != packetlen)  {
690*a192e900Samaguire 			if (cc < 0) {
691*a192e900Samaguire 				logperror("sendto");
692*a192e900Samaguire 			} else {
693*a192e900Samaguire 				logerr("wrote %s %d chars, ret=%d\n",
694*a192e900Samaguire 					sendaddress, packetlen, cc);
695*a192e900Samaguire 			}
696*a192e900Samaguire 		}
697*a192e900Samaguire 	}
698*a192e900Samaguire }
699*a192e900Samaguire 
700*a192e900Samaguire /*
701*a192e900Samaguire  *			P R _ T Y P E
702*a192e900Samaguire  *
703*a192e900Samaguire  * Convert an ICMP "type" field to a printable string.
704*a192e900Samaguire  */
705*a192e900Samaguire char *
706*a192e900Samaguire pr_type(int t)
707*a192e900Samaguire {
708*a192e900Samaguire 	static char *ttab[] = {
709*a192e900Samaguire 		"Echo Reply",
710*a192e900Samaguire 		"ICMP 1",
711*a192e900Samaguire 		"ICMP 2",
712*a192e900Samaguire 		"Dest Unreachable",
713*a192e900Samaguire 		"Source Quench",
714*a192e900Samaguire 		"Redirect",
715*a192e900Samaguire 		"ICMP 6",
716*a192e900Samaguire 		"ICMP 7",
717*a192e900Samaguire 		"Echo",
718*a192e900Samaguire 		"Router Advertise",
719*a192e900Samaguire 		"Router Solicitation",
720*a192e900Samaguire 		"Time Exceeded",
721*a192e900Samaguire 		"Parameter Problem",
722*a192e900Samaguire 		"Timestamp",
723*a192e900Samaguire 		"Timestamp Reply",
724*a192e900Samaguire 		"Info Request",
725*a192e900Samaguire 		"Info Reply",
726*a192e900Samaguire 		"Netmask Request",
727*a192e900Samaguire 		"Netmask Reply"
728*a192e900Samaguire 	};
729*a192e900Samaguire 
730*a192e900Samaguire 	if (t < 0 || t > 16)
731*a192e900Samaguire 		return ("OUT-OF-RANGE");
732*a192e900Samaguire 
733*a192e900Samaguire 	return (ttab[t]);
734*a192e900Samaguire }
735*a192e900Samaguire 
736*a192e900Samaguire /*
737*a192e900Samaguire  *			P R _ N A M E
738*a192e900Samaguire  *
739*a192e900Samaguire  * Return a string name for the given IP address.
740*a192e900Samaguire  */
741*a192e900Samaguire char *
742*a192e900Samaguire pr_name(struct in_addr addr)
743*a192e900Samaguire {
744*a192e900Samaguire 	struct hostent *phe;
745*a192e900Samaguire 	static char buf[256];
746*a192e900Samaguire 
747*a192e900Samaguire 	phe = gethostbyaddr((char *)&addr.s_addr, 4, AF_INET);
748*a192e900Samaguire 	if (phe == NULL)
749*a192e900Samaguire 		return (inet_ntoa(addr));
750*a192e900Samaguire 	(void) sprintf(buf, "%s (%s)", phe->h_name, inet_ntoa(addr));
751*a192e900Samaguire 	return (buf);
752*a192e900Samaguire }
753*a192e900Samaguire 
754*a192e900Samaguire /*
755*a192e900Samaguire  *			P R _ P A C K
756*a192e900Samaguire  *
757*a192e900Samaguire  * Print out the packet, if it came from us.  This logic is necessary
758*a192e900Samaguire  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
759*a192e900Samaguire  * which arrive ('tis only fair).  This permits multiple copies of this
760*a192e900Samaguire  * program to be run without having intermingled output (or statistics!).
761*a192e900Samaguire  */
762*a192e900Samaguire static void
763*a192e900Samaguire pr_pack(char *buf, int cc, struct sockaddr_in *from)
764*a192e900Samaguire {
765*a192e900Samaguire 	struct ip *ip;
766*a192e900Samaguire 	register struct icmp *icp;
767*a192e900Samaguire 	register int i;
768*a192e900Samaguire 	int hlen;
769*a192e900Samaguire 	struct logint *li;
770*a192e900Samaguire 
771*a192e900Samaguire 	ip = (struct ip *)ALIGN(buf);
772*a192e900Samaguire 	hlen = ip->ip_hl << 2;
773*a192e900Samaguire 	if (cc < hlen + ICMP_MINLEN) {
774*a192e900Samaguire 		if (verbose)
775*a192e900Samaguire 			logtrace("packet too short (%d bytes) from %s\n", cc,
776*a192e900Samaguire 				pr_name(from->sin_addr));
777*a192e900Samaguire 		return;
778*a192e900Samaguire 	}
779*a192e900Samaguire 
780*a192e900Samaguire 	cc -= hlen;
781*a192e900Samaguire 	icp = (struct icmp *)ALIGN(buf + hlen);
782*a192e900Samaguire 
783*a192e900Samaguire 	/*
784*a192e900Samaguire 	 * Let's check if IFF_NORTEXCH flag is set on the interface which
785*a192e900Samaguire 	 * recevied this packet.
786*a192e900Samaguire 	 * TODO: this code can be re-written using one socket per interface
787*a192e900Samaguire 	 * to determine which interface the packet is recevied.
788*a192e900Samaguire 	 */
789*a192e900Samaguire 	li = find_directly_connected_logint(ip->ip_src, NULL);
790*a192e900Samaguire 	if (li != NULL && (li->li_flags & IFF_NORTEXCH)) {
791*a192e900Samaguire 		if (verbose) {
792*a192e900Samaguire 			logtrace("Ignoring received %s on %s "
793*a192e900Samaguire 			    "(no route exchange on interface)",
794*a192e900Samaguire 			    pr_type((int)icp->icmp_type), li->li_name);
795*a192e900Samaguire 		}
796*a192e900Samaguire 		return;
797*a192e900Samaguire 	}
798*a192e900Samaguire 
799*a192e900Samaguire 	if (ip->ip_p == 0) {
800*a192e900Samaguire 		/*
801*a192e900Samaguire 		 * Assume that we are running on a pre-4.3BSD system
802*a192e900Samaguire 		 * such as SunOS before 4.0
803*a192e900Samaguire 		 */
804*a192e900Samaguire 		icp = (struct icmp *)ALIGN(buf);
805*a192e900Samaguire 	}
806*a192e900Samaguire 	switch (icp->icmp_type) {
807*a192e900Samaguire 	case ICMP_ROUTERADVERT: {
808*a192e900Samaguire 		struct icmp_ra *rap = (struct icmp_ra *)ALIGN(icp);
809*a192e900Samaguire 		struct icmp_ra_addr *ap;
810*a192e900Samaguire 
811*a192e900Samaguire 		if (responder)
812*a192e900Samaguire 			break;
813*a192e900Samaguire 
814*a192e900Samaguire 		/* TBD verify that the link is multicast or broadcast */
815*a192e900Samaguire 		/* XXX Find out the link it came in over? */
816*a192e900Samaguire #ifdef notdef
817*a192e900Samaguire 		if (debug) {
818*a192e900Samaguire 			logdebug("ROUTER_ADVERTISEMENT: \n");
819*a192e900Samaguire 			pr_hex(buf+hlen, cc);
820*a192e900Samaguire 		}
821*a192e900Samaguire #endif /* notdef */
822*a192e900Samaguire 		if (in_cksum((ushort_t *)ALIGN(buf+hlen), cc)) {
823*a192e900Samaguire 			if (verbose)
824*a192e900Samaguire 				logtrace("ICMP %s from %s: Bad checksum\n",
825*a192e900Samaguire 					pr_type((int)rap->icmp_type),
826*a192e900Samaguire 					pr_name(from->sin_addr));
827*a192e900Samaguire 			return;
828*a192e900Samaguire 		}
829*a192e900Samaguire 		if (rap->icmp_code != 0) {
830*a192e900Samaguire 			if (verbose)
831*a192e900Samaguire 				logtrace("ICMP %s from %s: Code = %d\n",
832*a192e900Samaguire 					pr_type((int)rap->icmp_type),
833*a192e900Samaguire 					pr_name(from->sin_addr),
834*a192e900Samaguire 					rap->icmp_code);
835*a192e900Samaguire 			return;
836*a192e900Samaguire 		}
837*a192e900Samaguire 		if (rap->icmp_num_addrs < 1) {
838*a192e900Samaguire 			if (verbose)
839*a192e900Samaguire 				logtrace("ICMP %s from %s: No addresses\n",
840*a192e900Samaguire 					pr_type((int)rap->icmp_type),
841*a192e900Samaguire 					pr_name(from->sin_addr));
842*a192e900Samaguire 			return;
843*a192e900Samaguire 		}
844*a192e900Samaguire 		if (rap->icmp_wpa < 2) {
845*a192e900Samaguire 			if (verbose)
846*a192e900Samaguire 				logtrace("ICMP %s from %s: Words/addr = %d\n",
847*a192e900Samaguire 					pr_type((int)rap->icmp_type),
848*a192e900Samaguire 					pr_name(from->sin_addr),
849*a192e900Samaguire 					rap->icmp_wpa);
850*a192e900Samaguire 			return;
851*a192e900Samaguire 		}
852*a192e900Samaguire 		if ((unsigned)cc <
853*a192e900Samaguire 		    ICMP_MINLEN + rap->icmp_num_addrs * rap->icmp_wpa * 4) {
854*a192e900Samaguire 			if (verbose)
855*a192e900Samaguire 				logtrace("ICMP %s from %s: Too short %d, %d\n",
856*a192e900Samaguire 					pr_type((int)rap->icmp_type),
857*a192e900Samaguire 					pr_name(from->sin_addr),
858*a192e900Samaguire 					cc,
859*a192e900Samaguire 					ICMP_MINLEN +
860*a192e900Samaguire 					rap->icmp_num_addrs *
861*a192e900Samaguire 					rap->icmp_wpa * 4);
862*a192e900Samaguire 			return;
863*a192e900Samaguire 		}
864*a192e900Samaguire 		rap->icmp_lifetime = ntohs(rap->icmp_lifetime);
865*a192e900Samaguire 		if ((rap->icmp_lifetime < 4 && rap->icmp_lifetime != 0) ||
866*a192e900Samaguire 		    rap->icmp_lifetime > 9000) {
867*a192e900Samaguire 			if (verbose)
868*a192e900Samaguire 			    logtrace("ICMP %s from %s: Invalid lifetime %d\n",
869*a192e900Samaguire 					pr_type((int)rap->icmp_type),
870*a192e900Samaguire 					pr_name(from->sin_addr),
871*a192e900Samaguire 					rap->icmp_lifetime);
872*a192e900Samaguire 			return;
873*a192e900Samaguire 		}
874*a192e900Samaguire 		if (verbose)
875*a192e900Samaguire 			logtrace("ICMP %s from %s, lifetime %d\n",
876*a192e900Samaguire 				pr_type((int)rap->icmp_type),
877*a192e900Samaguire 				pr_name(from->sin_addr),
878*a192e900Samaguire 				rap->icmp_lifetime);
879*a192e900Samaguire 
880*a192e900Samaguire 		/*
881*a192e900Samaguire 		 * Check that at least one router address is a neighbor
882*a192e900Samaguire 		 * on the arriving link.
883*a192e900Samaguire 		 */
884*a192e900Samaguire 		for (i = 0; (unsigned)i < rap->icmp_num_addrs; i++) {
885*a192e900Samaguire 			struct in_addr ina;
886*a192e900Samaguire 			ap = (struct icmp_ra_addr *)
887*a192e900Samaguire 				ALIGN(buf + hlen + ICMP_MINLEN +
888*a192e900Samaguire 					i * rap->icmp_wpa * 4);
889*a192e900Samaguire 			ap->preference = ntohl(ap->preference);
890*a192e900Samaguire 			ina.s_addr = ap->addr;
891*a192e900Samaguire 			if (verbose)
892*a192e900Samaguire 				logtrace("\taddress %s, preference 0x%x\n",
893*a192e900Samaguire 					pr_name(ina),
894*a192e900Samaguire 					ap->preference);
895*a192e900Samaguire 			if (!responder) {
896*a192e900Samaguire 				if (find_directly_connected_logint(ina, NULL) !=
897*a192e900Samaguire 				    NULL) {
898*a192e900Samaguire 					record_router(ina,
899*a192e900Samaguire 					    (long)ap->preference,
900*a192e900Samaguire 					    rap->icmp_lifetime);
901*a192e900Samaguire 				}
902*a192e900Samaguire 			}
903*a192e900Samaguire 		}
904*a192e900Samaguire 		nreceived++;
905*a192e900Samaguire 		if (!forever) {
906*a192e900Samaguire 			(void) alarm(0);
907*a192e900Samaguire 			do_fork();
908*a192e900Samaguire 			forever = 1;
909*a192e900Samaguire 			(void) alarm(TIMER_INTERVAL);
910*a192e900Samaguire 		}
911*a192e900Samaguire 		break;
912*a192e900Samaguire 	}
913*a192e900Samaguire 
914*a192e900Samaguire 	case ICMP_ROUTERSOLICIT: {
915*a192e900Samaguire 		struct sockaddr_in sin;
916*a192e900Samaguire 
917*a192e900Samaguire 		if (!responder)
918*a192e900Samaguire 			break;
919*a192e900Samaguire 
920*a192e900Samaguire 		/* TBD verify that the link is multicast or broadcast */
921*a192e900Samaguire 		/* XXX Find out the link it came in over? */
922*a192e900Samaguire #ifdef notdef
923*a192e900Samaguire 		if (debug) {
924*a192e900Samaguire 			logdebug("ROUTER_SOLICITATION: \n");
925*a192e900Samaguire 			pr_hex(buf+hlen, cc);
926*a192e900Samaguire 		}
927*a192e900Samaguire #endif /* notdef */
928*a192e900Samaguire 		if (in_cksum((ushort_t *)ALIGN(buf+hlen), cc)) {
929*a192e900Samaguire 			if (verbose)
930*a192e900Samaguire 				logtrace("ICMP %s from %s: Bad checksum\n",
931*a192e900Samaguire 					pr_type((int)icp->icmp_type),
932*a192e900Samaguire 					pr_name(from->sin_addr));
933*a192e900Samaguire 			return;
934*a192e900Samaguire 		}
935*a192e900Samaguire 		if (icp->icmp_code != 0) {
936*a192e900Samaguire 			if (verbose)
937*a192e900Samaguire 				logtrace("ICMP %s from %s: Code = %d\n",
938*a192e900Samaguire 					pr_type((int)icp->icmp_type),
939*a192e900Samaguire 					pr_name(from->sin_addr),
940*a192e900Samaguire 					icp->icmp_code);
941*a192e900Samaguire 			return;
942*a192e900Samaguire 		}
943*a192e900Samaguire 
944*a192e900Samaguire 		if (cc < ICMP_MINLEN) {
945*a192e900Samaguire 			if (verbose)
946*a192e900Samaguire 				logtrace("ICMP %s from %s: Too short %d, %d\n",
947*a192e900Samaguire 					pr_type((int)icp->icmp_type),
948*a192e900Samaguire 					pr_name(from->sin_addr),
949*a192e900Samaguire 					cc,
950*a192e900Samaguire 					ICMP_MINLEN);
951*a192e900Samaguire 			return;
952*a192e900Samaguire 		}
953*a192e900Samaguire 
954*a192e900Samaguire 		if (verbose)
955*a192e900Samaguire 			logtrace("ICMP %s from %s\n",
956*a192e900Samaguire 				pr_type((int)icp->icmp_type),
957*a192e900Samaguire 				pr_name(from->sin_addr));
958*a192e900Samaguire 
959*a192e900Samaguire 		if (!responder)
960*a192e900Samaguire 			break;
961*a192e900Samaguire 
962*a192e900Samaguire 		/*
963*a192e900Samaguire 		 * Check that ip_src is either a neighbor
964*a192e900Samaguire 		 * on the arriving link or 0.
965*a192e900Samaguire 		 */
966*a192e900Samaguire 		sin.sin_family = AF_INET;
967*a192e900Samaguire 		if (ip->ip_src.s_addr == 0) {
968*a192e900Samaguire 			/*
969*a192e900Samaguire 			 * If it was sent to the broadcast address we respond
970*a192e900Samaguire 			 * to the broadcast address.
971*a192e900Samaguire 			 */
972*a192e900Samaguire 			if (IN_CLASSD(ntohl(ip->ip_dst.s_addr))) {
973*a192e900Samaguire 				sin.sin_addr.s_addr =
974*a192e900Samaguire 				    htonl(INADDR_ALLHOSTS_GROUP);
975*a192e900Samaguire 			} else
976*a192e900Samaguire 				sin.sin_addr.s_addr = htonl(INADDR_BROADCAST);
977*a192e900Samaguire 			/* Restart the timer when we broadcast */
978*a192e900Samaguire 			left_until_advertise = min_adv_int +
979*a192e900Samaguire 				((max_adv_int - min_adv_int)
980*a192e900Samaguire 				 * (random() % 1000)/1000);
981*a192e900Samaguire 		} else {
982*a192e900Samaguire 			if (li == NULL) {
983*a192e900Samaguire 				if (verbose)
984*a192e900Samaguire 					logtrace("ICMP %s from %s: %s\n",
985*a192e900Samaguire 						pr_type((int)icp->icmp_type),
986*a192e900Samaguire 						pr_name(from->sin_addr),
987*a192e900Samaguire 					"source not directly connected");
988*a192e900Samaguire 				break;
989*a192e900Samaguire 			}
990*a192e900Samaguire 			sin.sin_addr.s_addr = ip->ip_src.s_addr;
991*a192e900Samaguire 		}
992*a192e900Samaguire 		nreceived++;
993*a192e900Samaguire 		ntransmitted++;
994*a192e900Samaguire 		advertise(&sin);
995*a192e900Samaguire 		break;
996*a192e900Samaguire 	}
997*a192e900Samaguire 	}
998*a192e900Samaguire }
999*a192e900Samaguire 
1000*a192e900Samaguire 
1001*a192e900Samaguire /*
1002*a192e900Samaguire  *			I N _ C K S U M
1003*a192e900Samaguire  *
1004*a192e900Samaguire  * Checksum routine for Internet Protocol family headers (C Version)
1005*a192e900Samaguire  *
1006*a192e900Samaguire  */
1007*a192e900Samaguire int
1008*a192e900Samaguire in_cksum(ushort_t *addr, int len)
1009*a192e900Samaguire {
1010*a192e900Samaguire 	register int nleft = len;
1011*a192e900Samaguire 	register ushort_t *w = addr;
1012*a192e900Samaguire 	register ushort_t answer;
1013*a192e900Samaguire 	ushort_t odd_byte = 0;
1014*a192e900Samaguire 	register int sum = 0;
1015*a192e900Samaguire 
1016*a192e900Samaguire 	/*
1017*a192e900Samaguire 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
1018*a192e900Samaguire 	 *  we add sequential 16 bit words to it, and at the end, fold
1019*a192e900Samaguire 	 *  back all the carry bits from the top 16 bits into the lower
1020*a192e900Samaguire 	 *  16 bits.
1021*a192e900Samaguire 	 */
1022*a192e900Samaguire 	while (nleft > 1)  {
1023*a192e900Samaguire 		sum += *w++;
1024*a192e900Samaguire 		nleft -= 2;
1025*a192e900Samaguire 	}
1026*a192e900Samaguire 
1027*a192e900Samaguire 	/* mop up an odd byte, if necessary */
1028*a192e900Samaguire 	if (nleft == 1) {
1029*a192e900Samaguire 		*(uchar_t *)(&odd_byte) = *(uchar_t *)w;
1030*a192e900Samaguire 		sum += odd_byte;
1031*a192e900Samaguire 	}
1032*a192e900Samaguire 
1033*a192e900Samaguire 	/*
1034*a192e900Samaguire 	 * add back carry outs from top 16 bits to low 16 bits
1035*a192e900Samaguire 	 */
1036*a192e900Samaguire 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
1037*a192e900Samaguire 	sum += (sum >> 16);			/* add carry */
1038*a192e900Samaguire 	answer = ~sum;				/* truncate to 16 bits */
1039*a192e900Samaguire 	return (answer);
1040*a192e900Samaguire }
1041*a192e900Samaguire 
1042*a192e900Samaguire /*
1043*a192e900Samaguire  *			F I N I S H
1044*a192e900Samaguire  *
1045*a192e900Samaguire  * Print out statistics, and give up.
1046*a192e900Samaguire  * Heavily buffered stdio is used here, so that all the statistics
1047*a192e900Samaguire  * will be written with 1 sys-write call.  This is nice when more
1048*a192e900Samaguire  * than one copy of the program is running on a terminal;  it prevents
1049*a192e900Samaguire  * the statistics output from becoming intermingled.
1050*a192e900Samaguire  */
1051*a192e900Samaguire static void
1052*a192e900Samaguire finish(void)
1053*a192e900Samaguire {
1054*a192e900Samaguire 	if (responder) {
1055*a192e900Samaguire 		/*
1056*a192e900Samaguire 		 * Send out a packet with a preference so that all
1057*a192e900Samaguire 		 * hosts will know that we are dead.
1058*a192e900Samaguire 		 */
1059*a192e900Samaguire 		logerr("terminated\n");
1060*a192e900Samaguire 		force_preference(IGNORE_PREFERENCE);
1061*a192e900Samaguire 		ntransmitted++;
1062*a192e900Samaguire 		advertise(&whereto);
1063*a192e900Samaguire 	}
1064*a192e900Samaguire 	if (verbose) {
1065*a192e900Samaguire 		logtrace("\n----%s rdisc Statistics----\n", sendaddress);
1066*a192e900Samaguire 		logtrace("%d packets transmitted, ", ntransmitted);
1067*a192e900Samaguire 		logtrace("%d packets received, ", nreceived);
1068*a192e900Samaguire 		logtrace("\n");
1069*a192e900Samaguire 	}
1070*a192e900Samaguire 	(void) fflush(stdout);
1071*a192e900Samaguire 	exit(0);
1072*a192e900Samaguire }
1073*a192e900Samaguire 
1074*a192e900Samaguire #include <ctype.h>
1075*a192e900Samaguire 
1076*a192e900Samaguire #ifdef notdef
1077*a192e900Samaguire int
1078*a192e900Samaguire pr_hex(unsigned char *data, int len)
1079*a192e900Samaguire {
1080*a192e900Samaguire 	FILE *out;
1081*a192e900Samaguire 
1082*a192e900Samaguire 	out = stdout;
1083*a192e900Samaguire 
1084*a192e900Samaguire 	while (len) {
1085*a192e900Samaguire 		register int i;
1086*a192e900Samaguire 		char charstring[17];
1087*a192e900Samaguire 
1088*a192e900Samaguire 		(void) strcpy(charstring, "                "); /* 16 spaces */
1089*a192e900Samaguire 		for (i = 0; i < 16; i++) {
1090*a192e900Samaguire 			/*
1091*a192e900Samaguire 			 * output the bytes one at a time,
1092*a192e900Samaguire 			 * not going past "len" bytes
1093*a192e900Samaguire 			 */
1094*a192e900Samaguire 			if (len) {
1095*a192e900Samaguire 				char ch = *data & 0x7f; /* strip parity */
1096*a192e900Samaguire 				if (!isprint((uchar_t)ch))
1097*a192e900Samaguire 					ch = ' '; /* ensure printable */
1098*a192e900Samaguire 				charstring[i] = ch;
1099*a192e900Samaguire 				(void) fprintf(out, "%02x ", *data++);
1100*a192e900Samaguire 				len--;
1101*a192e900Samaguire 			} else
1102*a192e900Samaguire 				(void) fprintf(out, "   ");
1103*a192e900Samaguire 			if (i == 7)
1104*a192e900Samaguire 				(void) fprintf(out, "   ");
1105*a192e900Samaguire 		}
1106*a192e900Samaguire 
1107*a192e900Samaguire 		(void) fprintf(out, "    *%s*\n", charstring);
1108*a192e900Samaguire 	}
1109*a192e900Samaguire }
1110*a192e900Samaguire #endif /* notdef */
1111*a192e900Samaguire 
1112*a192e900Samaguire static int
1113*a192e900Samaguire isbroadcast(struct sockaddr_in *sin)
1114*a192e900Samaguire {
1115*a192e900Samaguire 	return (sin->sin_addr.s_addr == htonl(INADDR_BROADCAST));
1116*a192e900Samaguire }
1117*a192e900Samaguire 
1118*a192e900Samaguire static int
1119*a192e900Samaguire ismulticast(struct sockaddr_in *sin)
1120*a192e900Samaguire {
1121*a192e900Samaguire 	return (IN_CLASSD(ntohl(sin->sin_addr.s_addr)));
1122*a192e900Samaguire }
1123*a192e900Samaguire 
1124*a192e900Samaguire /* From libc/rpc/pmap_rmt.c */
1125*a192e900Samaguire 
1126*a192e900Samaguire 
1127*a192e900Samaguire /* Only send once per physical interface */
1128*a192e900Samaguire static int
1129*a192e900Samaguire sendbcast(int s, char *packet, int packetlen)
1130*a192e900Samaguire {
1131*a192e900Samaguire 	struct phyint *pi;
1132*a192e900Samaguire 	struct logint *li;
1133*a192e900Samaguire 	boolean_t bcast;
1134*a192e900Samaguire 	int cc;
1135*a192e900Samaguire 
1136*a192e900Samaguire 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1137*a192e900Samaguire 		bcast = B_FALSE;
1138*a192e900Samaguire 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1139*a192e900Samaguire 			if (li->li_state & ST_DELETED)
1140*a192e900Samaguire 				continue;
1141*a192e900Samaguire 
1142*a192e900Samaguire 			if (li->li_flags & IFF_BROADCAST) {
1143*a192e900Samaguire 				bcast = B_TRUE;
1144*a192e900Samaguire 				break;
1145*a192e900Samaguire 			}
1146*a192e900Samaguire 		}
1147*a192e900Samaguire 		if (!bcast)
1148*a192e900Samaguire 			continue;
1149*a192e900Samaguire 		cc = sendbcastif(s, packet, packetlen, li);
1150*a192e900Samaguire 		if (cc != packetlen) {
1151*a192e900Samaguire 			return (cc);
1152*a192e900Samaguire 		}
1153*a192e900Samaguire 	}
1154*a192e900Samaguire 	return (packetlen);
1155*a192e900Samaguire }
1156*a192e900Samaguire 
1157*a192e900Samaguire static int
1158*a192e900Samaguire sendbcastif(int s, char *packet, int packetlen, struct logint *li)
1159*a192e900Samaguire {
1160*a192e900Samaguire 	int cc;
1161*a192e900Samaguire 	struct sockaddr_in baddr;
1162*a192e900Samaguire 	struct icmp *icp = (struct icmp *)ALIGN(packet);
1163*a192e900Samaguire 
1164*a192e900Samaguire 	baddr.sin_family = AF_INET;
1165*a192e900Samaguire 
1166*a192e900Samaguire 	if ((li->li_flags & IFF_BROADCAST) == 0) {
1167*a192e900Samaguire 		if (verbose) {
1168*a192e900Samaguire 			logtrace("Suppressing sending %s on %s "
1169*a192e900Samaguire 			    "(interface is not broadcast capable)\n",
1170*a192e900Samaguire 			    pr_type((int)icp->icmp_type), li->li_name);
1171*a192e900Samaguire 		}
1172*a192e900Samaguire 		return (packetlen);
1173*a192e900Samaguire 	}
1174*a192e900Samaguire 	if (li->li_flags & IFF_NORTEXCH) {
1175*a192e900Samaguire 		if (verbose) {
1176*a192e900Samaguire 			logtrace("Suppressing sending %s on %s "
1177*a192e900Samaguire 			    "(no route exchange on interface)\n",
1178*a192e900Samaguire 			    pr_type((int)icp->icmp_type), li->li_name);
1179*a192e900Samaguire 		}
1180*a192e900Samaguire 		return (packetlen);
1181*a192e900Samaguire 	}
1182*a192e900Samaguire 
1183*a192e900Samaguire 	baddr.sin_addr = li->li_bcastaddr;
1184*a192e900Samaguire 	if (debug)
1185*a192e900Samaguire 		logdebug("Broadcast to %s\n",
1186*a192e900Samaguire 			pr_name(baddr.sin_addr));
1187*a192e900Samaguire 	cc = sendto(s, packet, packetlen, 0,
1188*a192e900Samaguire 	    (struct sockaddr *)&baddr, sizeof (struct sockaddr));
1189*a192e900Samaguire 	if (cc != packetlen) {
1190*a192e900Samaguire 		logperror("sendbcast: sendto");
1191*a192e900Samaguire 		logerr("Cannot send broadcast packet to %s\n",
1192*a192e900Samaguire 			pr_name(baddr.sin_addr));
1193*a192e900Samaguire 	}
1194*a192e900Samaguire 	return (cc);
1195*a192e900Samaguire }
1196*a192e900Samaguire 
1197*a192e900Samaguire static int
1198*a192e900Samaguire sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *sin)
1199*a192e900Samaguire {
1200*a192e900Samaguire 	struct phyint *pi;
1201*a192e900Samaguire 	struct logint *li;
1202*a192e900Samaguire 	boolean_t mcast;
1203*a192e900Samaguire 	int cc;
1204*a192e900Samaguire 
1205*a192e900Samaguire 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1206*a192e900Samaguire 		mcast = B_FALSE;
1207*a192e900Samaguire 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1208*a192e900Samaguire 			if (li->li_state & ST_DELETED)
1209*a192e900Samaguire 				continue;
1210*a192e900Samaguire 
1211*a192e900Samaguire 			if (li->li_flags & IFF_MULTICAST) {
1212*a192e900Samaguire 				mcast = B_TRUE;
1213*a192e900Samaguire 				break;
1214*a192e900Samaguire 			}
1215*a192e900Samaguire 		}
1216*a192e900Samaguire 		if (!mcast)
1217*a192e900Samaguire 			continue;
1218*a192e900Samaguire 		cc = sendmcastif(s, packet, packetlen, sin, li);
1219*a192e900Samaguire 		if (cc != packetlen) {
1220*a192e900Samaguire 			return (cc);
1221*a192e900Samaguire 		}
1222*a192e900Samaguire 	}
1223*a192e900Samaguire 	return (packetlen);
1224*a192e900Samaguire }
1225*a192e900Samaguire 
1226*a192e900Samaguire static int
1227*a192e900Samaguire sendmcastif(int s, char *packet, int packetlen, struct sockaddr_in *sin,
1228*a192e900Samaguire     struct logint *li)
1229*a192e900Samaguire {
1230*a192e900Samaguire 	int cc;
1231*a192e900Samaguire 	struct sockaddr_in ifaddr;
1232*a192e900Samaguire 	struct icmp *icp = (struct icmp *)ALIGN(packet);
1233*a192e900Samaguire 
1234*a192e900Samaguire 	ifaddr.sin_family = AF_INET;
1235*a192e900Samaguire 
1236*a192e900Samaguire 	if ((li->li_flags & IFF_MULTICAST) == 0) {
1237*a192e900Samaguire 		if (verbose) {
1238*a192e900Samaguire 			logtrace("Suppressing sending %s on %s "
1239*a192e900Samaguire 			    "(interface is not multicast capable)\n",
1240*a192e900Samaguire 			    pr_type((int)icp->icmp_type), li->li_name);
1241*a192e900Samaguire 		}
1242*a192e900Samaguire 		return (packetlen);
1243*a192e900Samaguire 	}
1244*a192e900Samaguire 	if (li->li_flags & IFF_NORTEXCH) {
1245*a192e900Samaguire 		if (verbose) {
1246*a192e900Samaguire 			logtrace("Suppressing sending %s on %s "
1247*a192e900Samaguire 			    "(no route exchange on interface)\n",
1248*a192e900Samaguire 			    pr_type((int)icp->icmp_type), li->li_name);
1249*a192e900Samaguire 		}
1250*a192e900Samaguire 		return (packetlen);
1251*a192e900Samaguire 	}
1252*a192e900Samaguire 
1253*a192e900Samaguire 	ifaddr.sin_addr = li->li_address;
1254*a192e900Samaguire 	if (debug)
1255*a192e900Samaguire 		logdebug("Multicast to interface %s\n",
1256*a192e900Samaguire 			pr_name(ifaddr.sin_addr));
1257*a192e900Samaguire 	if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
1258*a192e900Samaguire 	    (char *)&ifaddr.sin_addr,
1259*a192e900Samaguire 	    sizeof (ifaddr.sin_addr)) < 0) {
1260*a192e900Samaguire 		logperror("setsockopt (IP_MULTICAST_IF)");
1261*a192e900Samaguire 		logerr("Cannot send multicast packet over interface %s\n",
1262*a192e900Samaguire 			pr_name(ifaddr.sin_addr));
1263*a192e900Samaguire 		return (-1);
1264*a192e900Samaguire 	}
1265*a192e900Samaguire 	cc = sendto(s, packet, packetlen, 0,
1266*a192e900Samaguire 	    (struct sockaddr *)sin, sizeof (struct sockaddr));
1267*a192e900Samaguire 	if (cc != packetlen) {
1268*a192e900Samaguire 		logperror("sendmcast: sendto");
1269*a192e900Samaguire 		logerr("Cannot send multicast packet over interface %s\n",
1270*a192e900Samaguire 			pr_name(ifaddr.sin_addr));
1271*a192e900Samaguire 	}
1272*a192e900Samaguire 	return (cc);
1273*a192e900Samaguire }
1274*a192e900Samaguire 
1275*a192e900Samaguire static void
1276*a192e900Samaguire reinitifs(void)
1277*a192e900Samaguire {
1278*a192e900Samaguire 	(void) initifs(s, &g_joinaddr, g_preference);
1279*a192e900Samaguire }
1280*a192e900Samaguire 
1281*a192e900Samaguire static void
1282*a192e900Samaguire force_preference(int preference)
1283*a192e900Samaguire {
1284*a192e900Samaguire 	struct phyint *pi;
1285*a192e900Samaguire 	struct logint *li;
1286*a192e900Samaguire 
1287*a192e900Samaguire 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1288*a192e900Samaguire 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1289*a192e900Samaguire 			if (li->li_state & ST_DELETED)
1290*a192e900Samaguire 				continue;
1291*a192e900Samaguire 
1292*a192e900Samaguire 			li->li_preference = preference;
1293*a192e900Samaguire 		}
1294*a192e900Samaguire 	}
1295*a192e900Samaguire }
1296*a192e900Samaguire 
1297*a192e900Samaguire /*
1298*a192e900Samaguire  * Returns -1 on failure.
1299*a192e900Samaguire  */
1300*a192e900Samaguire static int
1301*a192e900Samaguire initifs(int s, struct sockaddr_in *joinaddr, int preference)
1302*a192e900Samaguire {
1303*a192e900Samaguire 	struct ifconf ifc;
1304*a192e900Samaguire 	struct ifreq ifreq, *ifr;
1305*a192e900Samaguire 	struct lifreq lifreq;
1306*a192e900Samaguire 	int n;
1307*a192e900Samaguire 	char *buf;
1308*a192e900Samaguire 	int numifs;
1309*a192e900Samaguire 	unsigned bufsize;
1310*a192e900Samaguire 	struct phyint *pi;
1311*a192e900Samaguire 	struct logint *li;
1312*a192e900Samaguire 	int num_deletions;
1313*a192e900Samaguire 	char phyintname[IFNAMSIZ];
1314*a192e900Samaguire 	char *cp;
1315*a192e900Samaguire 	int old_num_usable_interfaces = num_usable_interfaces;
1316*a192e900Samaguire 
1317*a192e900Samaguire 	/*
1318*a192e900Samaguire 	 * Mark all interfaces so that we can determine which ones
1319*a192e900Samaguire 	 * have gone away.
1320*a192e900Samaguire 	 */
1321*a192e900Samaguire 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1322*a192e900Samaguire 		pi->pi_state |= ST_MARKED;
1323*a192e900Samaguire 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1324*a192e900Samaguire 			li->li_state |= ST_MARKED;
1325*a192e900Samaguire 		}
1326*a192e900Samaguire 	}
1327*a192e900Samaguire 
1328*a192e900Samaguire 	if (sock < 0) {
1329*a192e900Samaguire 		sock = socket(AF_INET, SOCK_DGRAM, 0);
1330*a192e900Samaguire 		if (sock < 0) {
1331*a192e900Samaguire 			logperror("initifs: socket");
1332*a192e900Samaguire 			return (-1);
1333*a192e900Samaguire 		}
1334*a192e900Samaguire 	}
1335*a192e900Samaguire #ifdef SIOCGIFNUM
1336*a192e900Samaguire 	if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) {
1337*a192e900Samaguire 		logperror("initifs: SIOCGIFNUM");
1338*a192e900Samaguire 		return (-1);
1339*a192e900Samaguire 	}
1340*a192e900Samaguire #else
1341*a192e900Samaguire 	numifs = MAXIFS;
1342*a192e900Samaguire #endif
1343*a192e900Samaguire 	bufsize = numifs * sizeof (struct ifreq);
1344*a192e900Samaguire 	buf = (char *)malloc(bufsize);
1345*a192e900Samaguire 	if (buf == NULL) {
1346*a192e900Samaguire 		logerr("out of memory\n");
1347*a192e900Samaguire 		(void) close(sock);
1348*a192e900Samaguire 		sock = -1;
1349*a192e900Samaguire 		return (-1);
1350*a192e900Samaguire 	}
1351*a192e900Samaguire 	ifc.ifc_len = bufsize;
1352*a192e900Samaguire 	ifc.ifc_buf = buf;
1353*a192e900Samaguire 	if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1354*a192e900Samaguire 		logperror("initifs: ioctl (get interface configuration)");
1355*a192e900Samaguire 		(void) close(sock);
1356*a192e900Samaguire 		sock = -1;
1357*a192e900Samaguire 		(void) free(buf);
1358*a192e900Samaguire 		return (-1);
1359*a192e900Samaguire 	}
1360*a192e900Samaguire 	ifr = ifc.ifc_req;
1361*a192e900Samaguire 	for (n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
1362*a192e900Samaguire 		ifreq = *ifr;
1363*a192e900Samaguire 		/*
1364*a192e900Samaguire 		 * We need to use new interface ioctls to get 64-bit flags.
1365*a192e900Samaguire 		 */
1366*a192e900Samaguire 		(void) strncpy(lifreq.lifr_name, ifr->ifr_name,
1367*a192e900Samaguire 		    sizeof (ifr->ifr_name));
1368*a192e900Samaguire 		if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
1369*a192e900Samaguire 			logperror("initifs: ioctl (get interface flags)");
1370*a192e900Samaguire 			continue;
1371*a192e900Samaguire 		}
1372*a192e900Samaguire 		if (ifr->ifr_addr.sa_family != AF_INET)
1373*a192e900Samaguire 			continue;
1374*a192e900Samaguire 		if ((lifreq.lifr_flags & IFF_UP) == 0)
1375*a192e900Samaguire 			continue;
1376*a192e900Samaguire 		if (lifreq.lifr_flags & IFF_LOOPBACK)
1377*a192e900Samaguire 			continue;
1378*a192e900Samaguire 		if ((lifreq.lifr_flags & (IFF_MULTICAST | IFF_BROADCAST)) == 0)
1379*a192e900Samaguire 			continue;
1380*a192e900Samaguire 
1381*a192e900Samaguire 		/* Create the physical name by truncating at the ':' */
1382*a192e900Samaguire 		strncpy(phyintname, ifreq.ifr_name, sizeof (phyintname));
1383*a192e900Samaguire 		if ((cp = strchr(phyintname, ':')) != NULL)
1384*a192e900Samaguire 			*cp = '\0';
1385*a192e900Samaguire 
1386*a192e900Samaguire 		pi = find_phyint(phyintname);
1387*a192e900Samaguire 		if (pi == NULL) {
1388*a192e900Samaguire 			pi = add_phyint(phyintname);
1389*a192e900Samaguire 			if (pi == NULL) {
1390*a192e900Samaguire 				logerr("out of memory\n");
1391*a192e900Samaguire 				(void) close(sock);
1392*a192e900Samaguire 				sock = -1;
1393*a192e900Samaguire 				(void) free(buf);
1394*a192e900Samaguire 				return (-1);
1395*a192e900Samaguire 			}
1396*a192e900Samaguire 		}
1397*a192e900Samaguire 		pi->pi_state &= ~ST_MARKED;
1398*a192e900Samaguire 
1399*a192e900Samaguire 		li = find_logint(pi, ifreq.ifr_name);
1400*a192e900Samaguire 		if (li != NULL) {
1401*a192e900Samaguire 			/*
1402*a192e900Samaguire 			 * Detect significant changes.
1403*a192e900Samaguire 			 * We treat netmask changes as insignificant but all
1404*a192e900Samaguire 			 * other changes cause a delete plus add of the
1405*a192e900Samaguire 			 * logical interface.
1406*a192e900Samaguire 			 * Note: if the flags and localaddr are unchanged
1407*a192e900Samaguire 			 * then nothing but the netmask and the broadcast
1408*a192e900Samaguire 			 * address could have changed since the other addresses
1409*a192e900Samaguire 			 * are derived from the flags and the localaddr.
1410*a192e900Samaguire 			 */
1411*a192e900Samaguire 			struct logint newli;
1412*a192e900Samaguire 
1413*a192e900Samaguire 			if (!getconfig(sock, lifreq.lifr_flags, &ifr->ifr_addr,
1414*a192e900Samaguire 			    &ifreq, &newli)) {
1415*a192e900Samaguire 				free_logint(li);
1416*a192e900Samaguire 				continue;
1417*a192e900Samaguire 			}
1418*a192e900Samaguire 
1419*a192e900Samaguire 			if (newli.li_flags != li->li_flags ||
1420*a192e900Samaguire 			    newli.li_localaddr.s_addr !=
1421*a192e900Samaguire 			    li->li_localaddr.s_addr || newli.li_index !=
1422*a192e900Samaguire 			    li->li_index) {
1423*a192e900Samaguire 				/* Treat as an interface deletion + addition */
1424*a192e900Samaguire 				li->li_state |= ST_DELETED;
1425*a192e900Samaguire 				deleted_logint(li, &newli, s, joinaddr);
1426*a192e900Samaguire 				free_logint(li);
1427*a192e900Samaguire 				li = NULL;	/* li recreated below */
1428*a192e900Samaguire 			} else {
1429*a192e900Samaguire 				/*
1430*a192e900Samaguire 				 * No significant changes.
1431*a192e900Samaguire 				 * Just update the netmask, and broadcast.
1432*a192e900Samaguire 				 */
1433*a192e900Samaguire 				li->li_netmask = newli.li_netmask;
1434*a192e900Samaguire 				li->li_bcastaddr = newli.li_bcastaddr;
1435*a192e900Samaguire 			}
1436*a192e900Samaguire 		}
1437*a192e900Samaguire 		if (li == NULL) {
1438*a192e900Samaguire 			li = add_logint(pi, ifreq.ifr_name);
1439*a192e900Samaguire 			if (li == NULL) {
1440*a192e900Samaguire 				logerr("out of memory\n");
1441*a192e900Samaguire 				(void) close(sock);
1442*a192e900Samaguire 				sock = -1;
1443*a192e900Samaguire 				(void) free(buf);
1444*a192e900Samaguire 				return (-1);
1445*a192e900Samaguire 			}
1446*a192e900Samaguire 
1447*a192e900Samaguire 			/* init li */
1448*a192e900Samaguire 			if (!getconfig(sock, lifreq.lifr_flags, &ifr->ifr_addr,
1449*a192e900Samaguire 			    &ifreq, li)) {
1450*a192e900Samaguire 				free_logint(li);
1451*a192e900Samaguire 				continue;
1452*a192e900Samaguire 			}
1453*a192e900Samaguire 			li->li_preference = preference;
1454*a192e900Samaguire 			added_logint(li, s, joinaddr);
1455*a192e900Samaguire 		}
1456*a192e900Samaguire 		li->li_state &= ~ST_MARKED;
1457*a192e900Samaguire 	}
1458*a192e900Samaguire 	(void) free(buf);
1459*a192e900Samaguire 
1460*a192e900Samaguire 	/*
1461*a192e900Samaguire 	 * Determine which interfaces have gone away.
1462*a192e900Samaguire 	 * The deletion is done in three phases:
1463*a192e900Samaguire 	 * 1. Mark ST_DELETED
1464*a192e900Samaguire 	 * 2. Inform using the deleted_* function.
1465*a192e900Samaguire 	 * 3. Unlink and free the actual memory.
1466*a192e900Samaguire 	 * Note that for #3 the physical interface must be deleted after
1467*a192e900Samaguire 	 * the logical ones.
1468*a192e900Samaguire 	 * Also count the number of physical interfaces.
1469*a192e900Samaguire 	 */
1470*a192e900Samaguire 	num_usable_interfaces = 0;
1471*a192e900Samaguire 	num_deletions = 0;
1472*a192e900Samaguire 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1473*a192e900Samaguire 		if (pi->pi_state & ST_MARKED) {
1474*a192e900Samaguire 			num_deletions++;
1475*a192e900Samaguire 			pi->pi_state |= ST_DELETED;
1476*a192e900Samaguire 		}
1477*a192e900Samaguire 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1478*a192e900Samaguire 			if (li->li_state & ST_MARKED) {
1479*a192e900Samaguire 				num_deletions++;
1480*a192e900Samaguire 				li->li_state |= ST_DELETED;
1481*a192e900Samaguire 			}
1482*a192e900Samaguire 		}
1483*a192e900Samaguire 		if (!(pi->pi_state & ST_DELETED))
1484*a192e900Samaguire 			num_usable_interfaces++;
1485*a192e900Samaguire 	}
1486*a192e900Samaguire 	if (num_deletions != 0) {
1487*a192e900Samaguire 		struct phyint *nextpi;
1488*a192e900Samaguire 		struct logint *nextli;
1489*a192e900Samaguire 
1490*a192e900Samaguire 		for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1491*a192e900Samaguire 			if (pi->pi_state & ST_DELETED) {
1492*a192e900Samaguire 				/*
1493*a192e900Samaguire 				 * By deleting the physical interface pi, all of
1494*a192e900Samaguire 				 * the corresponding logical interfaces will
1495*a192e900Samaguire 				 * also be deleted so there is no need to delete
1496*a192e900Samaguire 				 * them individually.
1497*a192e900Samaguire 				 */
1498*a192e900Samaguire 				deleted_phyint(pi, s, joinaddr);
1499*a192e900Samaguire 			} else {
1500*a192e900Samaguire 				for (li = pi->pi_logical_first; li != NULL;
1501*a192e900Samaguire 				    li = li->li_next) {
1502*a192e900Samaguire 					if (li->li_state & ST_DELETED) {
1503*a192e900Samaguire 						deleted_logint(li, NULL, s,
1504*a192e900Samaguire 						    joinaddr);
1505*a192e900Samaguire 					}
1506*a192e900Samaguire 				}
1507*a192e900Samaguire 			}
1508*a192e900Samaguire 		}
1509*a192e900Samaguire 		/* Do the actual linked list update + free */
1510*a192e900Samaguire 		for (pi = phyint; pi != NULL; pi = nextpi) {
1511*a192e900Samaguire 			nextpi = pi->pi_next;
1512*a192e900Samaguire 			for (li = pi->pi_logical_first; li != NULL;
1513*a192e900Samaguire 			    li = nextli) {
1514*a192e900Samaguire 				nextli = li->li_next;
1515*a192e900Samaguire 				if (li->li_state & ST_DELETED)
1516*a192e900Samaguire 					free_logint(li);
1517*a192e900Samaguire 			}
1518*a192e900Samaguire 			if (pi->pi_state & ST_DELETED)
1519*a192e900Samaguire 				free_phyint(pi);
1520*a192e900Samaguire 		}
1521*a192e900Samaguire 	}
1522*a192e900Samaguire 	/*
1523*a192e900Samaguire 	 * When the set of available interfaces goes from zero to
1524*a192e900Samaguire 	 * non-zero we restart solicitations if '-s' was specified.
1525*a192e900Samaguire 	 */
1526*a192e900Samaguire 	if (old_num_usable_interfaces == 0 && num_usable_interfaces > 0 &&
1527*a192e900Samaguire 	    start_solicit && !solicit) {
1528*a192e900Samaguire 		if (debug)
1529*a192e900Samaguire 			logdebug("switching to solicitations: num if %d\n",
1530*a192e900Samaguire 			    num_usable_interfaces);
1531*a192e900Samaguire 		solicit = start_solicit;
1532*a192e900Samaguire 		ntransmitted = 0;
1533*a192e900Samaguire 		ntransmitted++;
1534*a192e900Samaguire 		solicitor(&whereto);
1535*a192e900Samaguire 	}
1536*a192e900Samaguire 	return (0);
1537*a192e900Samaguire }
1538*a192e900Samaguire 
1539*a192e900Samaguire static boolean_t
1540*a192e900Samaguire getconfig(int sock, uint64_t if_flags, struct sockaddr *addr,
1541*a192e900Samaguire     struct ifreq *ifr, struct logint *li)
1542*a192e900Samaguire {
1543*a192e900Samaguire 	struct ifreq ifreq;
1544*a192e900Samaguire 	struct sockaddr_in *sin;
1545*a192e900Samaguire 	struct lifreq lifreq;
1546*a192e900Samaguire 
1547*a192e900Samaguire 	ifreq = *ifr;	/* Copy name etc */
1548*a192e900Samaguire 
1549*a192e900Samaguire 	li->li_flags = if_flags;
1550*a192e900Samaguire 	sin = (struct sockaddr_in *)ALIGN(addr);
1551*a192e900Samaguire 	li->li_localaddr = sin->sin_addr;
1552*a192e900Samaguire 
1553*a192e900Samaguire 	(void) strlcpy(lifreq.lifr_name, ifr->ifr_name,
1554*a192e900Samaguire 	    sizeof (lifreq.lifr_name));
1555*a192e900Samaguire 	if (ioctl(sock, SIOCGLIFINDEX, &lifreq) < 0) {
1556*a192e900Samaguire 		logperror("initifs: ioctl (get if index)");
1557*a192e900Samaguire 		/* Continue with 0; a safe value never used for interfaces */
1558*a192e900Samaguire 		li->li_index = 0;
1559*a192e900Samaguire 	} else {
1560*a192e900Samaguire 		li->li_index = lifreq.lifr_index;
1561*a192e900Samaguire 	}
1562*a192e900Samaguire 
1563*a192e900Samaguire 	if (if_flags & IFF_POINTOPOINT) {
1564*a192e900Samaguire 		li->li_netmask.s_addr = (unsigned long)0xffffffff;
1565*a192e900Samaguire 		if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
1566*a192e900Samaguire 			logperror("initifs: ioctl (get dest addr)");
1567*a192e900Samaguire 			return (B_FALSE);
1568*a192e900Samaguire 		}
1569*a192e900Samaguire 		/* A pt-pt link is identified by the remote address */
1570*a192e900Samaguire 		sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr);
1571*a192e900Samaguire 		li->li_address = sin->sin_addr;
1572*a192e900Samaguire 		li->li_remoteaddr = sin->sin_addr;
1573*a192e900Samaguire 		/* Simulate broadcast for pt-pt */
1574*a192e900Samaguire 		li->li_bcastaddr = sin->sin_addr;
1575*a192e900Samaguire 		li->li_flags |= IFF_BROADCAST;
1576*a192e900Samaguire 	} else {
1577*a192e900Samaguire 		/*
1578*a192e900Samaguire 		 * Non pt-pt links are identified by the local
1579*a192e900Samaguire 		 * address
1580*a192e900Samaguire 		 */
1581*a192e900Samaguire 		li->li_address = li->li_localaddr;
1582*a192e900Samaguire 		li->li_remoteaddr = li->li_address;
1583*a192e900Samaguire 		if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
1584*a192e900Samaguire 			logperror("initifs: ioctl (get netmask)");
1585*a192e900Samaguire 			return (B_FALSE);
1586*a192e900Samaguire 		}
1587*a192e900Samaguire 		sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr);
1588*a192e900Samaguire 		li->li_netmask = sin->sin_addr;
1589*a192e900Samaguire 		if (if_flags & IFF_BROADCAST) {
1590*a192e900Samaguire 			if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
1591*a192e900Samaguire 				logperror(
1592*a192e900Samaguire 				    "initifs: ioctl (get broadcast address)");
1593*a192e900Samaguire 				return (B_FALSE);
1594*a192e900Samaguire 			}
1595*a192e900Samaguire 			sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr);
1596*a192e900Samaguire 			li->li_bcastaddr = sin->sin_addr;
1597*a192e900Samaguire 		}
1598*a192e900Samaguire 	}
1599*a192e900Samaguire 	return (B_TRUE);
1600*a192e900Samaguire }
1601*a192e900Samaguire 
1602*a192e900Samaguire 
1603*a192e900Samaguire static int
1604*a192e900Samaguire support_multicast(void)
1605*a192e900Samaguire {
1606*a192e900Samaguire 	int sock;
1607*a192e900Samaguire 	uchar_t ttl = 1;
1608*a192e900Samaguire 
1609*a192e900Samaguire 	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1610*a192e900Samaguire 	if (sock < 0) {
1611*a192e900Samaguire 		logperror("support_multicast: socket");
1612*a192e900Samaguire 		return (0);
1613*a192e900Samaguire 	}
1614*a192e900Samaguire 
1615*a192e900Samaguire 	if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
1616*a192e900Samaguire 	    (char *)&ttl, sizeof (ttl)) < 0) {
1617*a192e900Samaguire 		(void) close(sock);
1618*a192e900Samaguire 		return (0);
1619*a192e900Samaguire 	}
1620*a192e900Samaguire 	(void) close(sock);
1621*a192e900Samaguire 	return (1);
1622*a192e900Samaguire }
1623*a192e900Samaguire 
1624*a192e900Samaguire /*
1625*a192e900Samaguire  * For a given destination address, find the logical interface to use.
1626*a192e900Samaguire  * If opi is NULL check all interfaces. Otherwise just match against
1627*a192e900Samaguire  * the specified physical interface.
1628*a192e900Samaguire  * Return logical interface if there's a match, NULL otherwise.
1629*a192e900Samaguire  */
1630*a192e900Samaguire static struct logint *
1631*a192e900Samaguire find_directly_connected_logint(struct in_addr in, struct phyint *opi)
1632*a192e900Samaguire {
1633*a192e900Samaguire 	struct phyint *pi;
1634*a192e900Samaguire 	struct logint *li;
1635*a192e900Samaguire 
1636*a192e900Samaguire 	if (opi == NULL)
1637*a192e900Samaguire 		pi = phyint;
1638*a192e900Samaguire 	else
1639*a192e900Samaguire 		pi = opi;
1640*a192e900Samaguire 
1641*a192e900Samaguire 	for (; pi != NULL; pi = pi->pi_next) {
1642*a192e900Samaguire 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1643*a192e900Samaguire 			if (li->li_state & ST_DELETED)
1644*a192e900Samaguire 				continue;
1645*a192e900Samaguire 
1646*a192e900Samaguire 			/* Check that the subnetwork numbers match */
1647*a192e900Samaguire 			if ((in.s_addr & li->li_netmask.s_addr) ==
1648*a192e900Samaguire 			    (li->li_remoteaddr.s_addr &
1649*a192e900Samaguire 			    li->li_netmask.s_addr))
1650*a192e900Samaguire 				return (li);
1651*a192e900Samaguire 		}
1652*a192e900Samaguire 		if (opi != NULL)
1653*a192e900Samaguire 			break;
1654*a192e900Samaguire 	}
1655*a192e900Samaguire 	return (NULL);
1656*a192e900Samaguire }
1657*a192e900Samaguire 
1658*a192e900Samaguire /*
1659*a192e900Samaguire  * INTERFACES - physical and logical identified by name
1660*a192e900Samaguire  */
1661*a192e900Samaguire 
1662*a192e900Samaguire 
1663*a192e900Samaguire static void
1664*a192e900Samaguire report_interfaces(void)
1665*a192e900Samaguire {
1666*a192e900Samaguire 	struct phyint *pi;
1667*a192e900Samaguire 	struct logint *li;
1668*a192e900Samaguire 
1669*a192e900Samaguire 	logdebug("\nInterfaces:\n\n");
1670*a192e900Samaguire 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1671*a192e900Samaguire 		logdebug("Phyint %s state 0x%x\n",
1672*a192e900Samaguire 		    pi->pi_name, pi->pi_state);
1673*a192e900Samaguire 		for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1674*a192e900Samaguire 			logdebug("IF %s state 0x%x, flags 0x%x, addr %s\n",
1675*a192e900Samaguire 			    li->li_name, li->li_state, li->li_flags,
1676*a192e900Samaguire 			    pr_name(li->li_address));
1677*a192e900Samaguire 			logdebug("\tlocal %s pref 0x%x ",
1678*a192e900Samaguire 			    pr_name(li->li_localaddr), li->li_preference);
1679*a192e900Samaguire 			logdebug("bcast %s\n",
1680*a192e900Samaguire 			    pr_name(li->li_bcastaddr));
1681*a192e900Samaguire 			logdebug("\tremote %s ",
1682*a192e900Samaguire 			    pr_name(li->li_remoteaddr));
1683*a192e900Samaguire 			logdebug("netmask %s\n",
1684*a192e900Samaguire 			    pr_name(li->li_netmask));
1685*a192e900Samaguire 		}
1686*a192e900Samaguire 	}
1687*a192e900Samaguire }
1688*a192e900Samaguire 
1689*a192e900Samaguire static struct phyint *
1690*a192e900Samaguire find_phyint(char *name)
1691*a192e900Samaguire {
1692*a192e900Samaguire 	struct phyint *pi;
1693*a192e900Samaguire 
1694*a192e900Samaguire 	for (pi = phyint; pi != NULL; pi = pi->pi_next) {
1695*a192e900Samaguire 		if (strcmp(pi->pi_name, name) == 0)
1696*a192e900Samaguire 			return (pi);
1697*a192e900Samaguire 	}
1698*a192e900Samaguire 	return (NULL);
1699*a192e900Samaguire }
1700*a192e900Samaguire 
1701*a192e900Samaguire /* Assumes that the entry does not exist - caller must use find_* */
1702*a192e900Samaguire static struct phyint *
1703*a192e900Samaguire add_phyint(char *name)
1704*a192e900Samaguire {
1705*a192e900Samaguire 	struct phyint *pi;
1706*a192e900Samaguire 
1707*a192e900Samaguire 	pi = malloc(sizeof (*pi));
1708*a192e900Samaguire 	if (pi == NULL)
1709*a192e900Samaguire 		return (NULL);
1710*a192e900Samaguire 	bzero((char *)pi, sizeof (*pi));
1711*a192e900Samaguire 
1712*a192e900Samaguire 	strncpy(pi->pi_name, name, sizeof (pi->pi_name));
1713*a192e900Samaguire 	/* Link into list */
1714*a192e900Samaguire 	pi->pi_next = phyint;
1715*a192e900Samaguire 	pi->pi_prev = NULL;
1716*a192e900Samaguire 	if (phyint != NULL)
1717*a192e900Samaguire 		phyint->pi_prev = pi;
1718*a192e900Samaguire 	phyint = pi;
1719*a192e900Samaguire 	return (pi);
1720*a192e900Samaguire }
1721*a192e900Samaguire 
1722*a192e900Samaguire static void
1723*a192e900Samaguire free_phyint(struct phyint *pi)
1724*a192e900Samaguire {
1725*a192e900Samaguire 	assert(pi->pi_logical_first == NULL);
1726*a192e900Samaguire 	assert(pi->pi_logical_last == NULL);
1727*a192e900Samaguire 
1728*a192e900Samaguire 	if (pi->pi_prev == NULL) {
1729*a192e900Samaguire 		/* Delete first */
1730*a192e900Samaguire 		assert(phyint == pi);
1731*a192e900Samaguire 		phyint = pi->pi_next;
1732*a192e900Samaguire 	} else {
1733*a192e900Samaguire 		assert(pi->pi_prev->pi_next == pi);
1734*a192e900Samaguire 		pi->pi_prev->pi_next = pi->pi_next;
1735*a192e900Samaguire 	}
1736*a192e900Samaguire 	if (pi->pi_next != NULL) {
1737*a192e900Samaguire 		assert(pi->pi_next->pi_prev == pi);
1738*a192e900Samaguire 		pi->pi_next->pi_prev = pi->pi_prev;
1739*a192e900Samaguire 	}
1740*a192e900Samaguire 	free(pi);
1741*a192e900Samaguire }
1742*a192e900Samaguire 
1743*a192e900Samaguire static struct logint *
1744*a192e900Samaguire find_logint(struct phyint *pi, char *name)
1745*a192e900Samaguire {
1746*a192e900Samaguire 	struct logint *li;
1747*a192e900Samaguire 
1748*a192e900Samaguire 	for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1749*a192e900Samaguire 		if (strcmp(li->li_name, name) == 0)
1750*a192e900Samaguire 			return (li);
1751*a192e900Samaguire 	}
1752*a192e900Samaguire 	return (NULL);
1753*a192e900Samaguire }
1754*a192e900Samaguire 
1755*a192e900Samaguire /*
1756*a192e900Samaguire  * Assumes that the entry does not exist - caller must use find_*
1757*a192e900Samaguire  * Tail insertion.
1758*a192e900Samaguire  */
1759*a192e900Samaguire static struct logint *
1760*a192e900Samaguire add_logint(struct phyint *pi, char *name)
1761*a192e900Samaguire {
1762*a192e900Samaguire 	struct logint *li;
1763*a192e900Samaguire 
1764*a192e900Samaguire 	li = malloc(sizeof (*li));
1765*a192e900Samaguire 	if (li == NULL)
1766*a192e900Samaguire 		return (NULL);
1767*a192e900Samaguire 	bzero((char *)li, sizeof (*li));
1768*a192e900Samaguire 
1769*a192e900Samaguire 	strncpy(li->li_name, name, sizeof (li->li_name));
1770*a192e900Samaguire 	/* Link into list */
1771*a192e900Samaguire 	li->li_prev = pi->pi_logical_last;
1772*a192e900Samaguire 	if (pi->pi_logical_last == NULL) {
1773*a192e900Samaguire 		/* First one */
1774*a192e900Samaguire 		assert(pi->pi_logical_first == NULL);
1775*a192e900Samaguire 		pi->pi_logical_first = li;
1776*a192e900Samaguire 	} else {
1777*a192e900Samaguire 		pi->pi_logical_last->li_next = li;
1778*a192e900Samaguire 	}
1779*a192e900Samaguire 	li->li_next = NULL;
1780*a192e900Samaguire 	li->li_physical = pi;
1781*a192e900Samaguire 	pi->pi_logical_last = li;
1782*a192e900Samaguire 	return (li);
1783*a192e900Samaguire 
1784*a192e900Samaguire }
1785*a192e900Samaguire 
1786*a192e900Samaguire static void
1787*a192e900Samaguire free_logint(struct logint *li)
1788*a192e900Samaguire {
1789*a192e900Samaguire 	struct phyint *pi;
1790*a192e900Samaguire 
1791*a192e900Samaguire 	pi = li->li_physical;
1792*a192e900Samaguire 	if (li->li_prev == NULL) {
1793*a192e900Samaguire 		/* Delete first */
1794*a192e900Samaguire 		assert(pi->pi_logical_first == li);
1795*a192e900Samaguire 		pi->pi_logical_first = li->li_next;
1796*a192e900Samaguire 	} else {
1797*a192e900Samaguire 		assert(li->li_prev->li_next == li);
1798*a192e900Samaguire 		li->li_prev->li_next = li->li_next;
1799*a192e900Samaguire 	}
1800*a192e900Samaguire 	if (li->li_next == NULL) {
1801*a192e900Samaguire 		/* Delete last */
1802*a192e900Samaguire 		assert(pi->pi_logical_last == li);
1803*a192e900Samaguire 		pi->pi_logical_last = li->li_prev;
1804*a192e900Samaguire 	} else {
1805*a192e900Samaguire 		assert(li->li_next->li_prev == li);
1806*a192e900Samaguire 		li->li_next->li_prev = li->li_prev;
1807*a192e900Samaguire 	}
1808*a192e900Samaguire 	free(li);
1809*a192e900Samaguire }
1810*a192e900Samaguire 
1811*a192e900Samaguire 
1812*a192e900Samaguire /* Tell all the logical interfaces that they are going away */
1813*a192e900Samaguire static void
1814*a192e900Samaguire deleted_phyint(struct phyint *pi, int s,
1815*a192e900Samaguire     struct sockaddr_in *joinaddr)
1816*a192e900Samaguire {
1817*a192e900Samaguire 	struct logint *li;
1818*a192e900Samaguire 
1819*a192e900Samaguire 	if (debug)
1820*a192e900Samaguire 		logdebug("Deleting physical interface %s\n", pi->pi_name);
1821*a192e900Samaguire 
1822*a192e900Samaguire 	for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1823*a192e900Samaguire 		li->li_state |= ST_DELETED;
1824*a192e900Samaguire 	}
1825*a192e900Samaguire 	for (li = pi->pi_logical_first; li != NULL; li = li->li_next) {
1826*a192e900Samaguire 		deleted_logint(li, NULL, s, joinaddr);
1827*a192e900Samaguire 	}
1828*a192e900Samaguire }
1829*a192e900Samaguire 
1830*a192e900Samaguire /*
1831*a192e900Samaguire  * Join the multicast address if no other logical interface has done
1832*a192e900Samaguire  * so for this physical interface.
1833*a192e900Samaguire  */
1834*a192e900Samaguire static void
1835*a192e900Samaguire added_logint(struct logint *li, int s,
1836*a192e900Samaguire     struct sockaddr_in *joinaddr)
1837*a192e900Samaguire {
1838*a192e900Samaguire 	if (debug)
1839*a192e900Samaguire 		logdebug("Adding logical interface %s\n", li->li_name);
1840*a192e900Samaguire 
1841*a192e900Samaguire 	if ((!(li->li_physical->pi_state & ST_JOINED)) &&
1842*a192e900Samaguire 	    (!isbroadcast(joinaddr))) {
1843*a192e900Samaguire 		struct ip_mreq mreq;
1844*a192e900Samaguire 
1845*a192e900Samaguire 		mreq.imr_multiaddr = joinaddr->sin_addr;
1846*a192e900Samaguire 		mreq.imr_interface = li->li_address;
1847*a192e900Samaguire 
1848*a192e900Samaguire 		if (debug)
1849*a192e900Samaguire 			logdebug("Joining MC on interface %s\n", li->li_name);
1850*a192e900Samaguire 
1851*a192e900Samaguire 		if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1852*a192e900Samaguire 		    (char *)&mreq, sizeof (mreq)) < 0) {
1853*a192e900Samaguire 			logperror("setsockopt (IP_ADD_MEMBERSHIP)");
1854*a192e900Samaguire 		} else {
1855*a192e900Samaguire 			li->li_physical->pi_state |= ST_JOINED;
1856*a192e900Samaguire 			li->li_state |= ST_JOINED;
1857*a192e900Samaguire 		}
1858*a192e900Samaguire 	}
1859*a192e900Samaguire }
1860*a192e900Samaguire 
1861*a192e900Samaguire /*
1862*a192e900Samaguire  * Leave the multicast address if this logical interface joined it.
1863*a192e900Samaguire  * Look for a replacement logical interface for the same physical interface.
1864*a192e900Samaguire  * Remove any routes which are no longer reachable.
1865*a192e900Samaguire  *
1866*a192e900Samaguire  * If newli is non-NULL, then it is likely that the address of a logical
1867*a192e900Samaguire  * interface has changed.  In this case, the membership should be dropped using
1868*a192e900Samaguire  * the new address of the interface in question.
1869*a192e900Samaguire  *
1870*a192e900Samaguire  * XXX When a physical interface is being deleted by deleted_phyint(), this
1871*a192e900Samaguire  * routine will be called for each logical interface associated with the
1872*a192e900Samaguire  * physical one.  This should be made more efficient as there is no point in
1873*a192e900Samaguire  * searching for an alternate logical interface to add group membership to as
1874*a192e900Samaguire  * they all are marked ST_DELETED.
1875*a192e900Samaguire  */
1876*a192e900Samaguire static void
1877*a192e900Samaguire deleted_logint(struct logint *li, struct logint *newli, int s,
1878*a192e900Samaguire     struct sockaddr_in *joinaddr)
1879*a192e900Samaguire {
1880*a192e900Samaguire 	struct phyint *pi;
1881*a192e900Samaguire 	struct logint *oli;
1882*a192e900Samaguire 
1883*a192e900Samaguire 	if (debug)
1884*a192e900Samaguire 		logdebug("Deleting logical interface %s\n", li->li_name);
1885*a192e900Samaguire 
1886*a192e900Samaguire 	assert(li->li_state & ST_DELETED);
1887*a192e900Samaguire 
1888*a192e900Samaguire 	if (li->li_state & ST_JOINED) {
1889*a192e900Samaguire 		struct ip_mreq mreq;
1890*a192e900Samaguire 
1891*a192e900Samaguire 		pi = li->li_physical;
1892*a192e900Samaguire 		assert(pi->pi_state & ST_JOINED);
1893*a192e900Samaguire 		assert(!isbroadcast(joinaddr));
1894*a192e900Samaguire 
1895*a192e900Samaguire 		mreq.imr_multiaddr = joinaddr->sin_addr;
1896*a192e900Samaguire 		if (newli != NULL)
1897*a192e900Samaguire 			mreq.imr_interface = newli->li_address;
1898*a192e900Samaguire 		else
1899*a192e900Samaguire 			mreq.imr_interface = li->li_address;
1900*a192e900Samaguire 
1901*a192e900Samaguire 		if (debug)
1902*a192e900Samaguire 			logdebug("Leaving MC on interface %s\n", li->li_name);
1903*a192e900Samaguire 
1904*a192e900Samaguire 		if (setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP,
1905*a192e900Samaguire 		    (char *)&mreq, sizeof (mreq)) < 0) {
1906*a192e900Samaguire 			/*
1907*a192e900Samaguire 			 * EADDRNOTAVAIL will be returned if the interface has
1908*a192e900Samaguire 			 * been unplumbed or if the interface no longer has
1909*a192e900Samaguire 			 * IFF_MULTICAST set.  The former is the common case
1910*a192e900Samaguire 			 * while the latter is rare so don't log the error
1911*a192e900Samaguire 			 * unless some other error was returned or if debug is
1912*a192e900Samaguire 			 * set.
1913*a192e900Samaguire 			 */
1914*a192e900Samaguire 			if (errno != EADDRNOTAVAIL) {
1915*a192e900Samaguire 				logperror("setsockopt (IP_DROP_MEMBERSHIP)");
1916*a192e900Samaguire 			} else if (debug) {
1917*a192e900Samaguire 				logdebug("%s: %s\n",
1918*a192e900Samaguire 				    "setsockopt (IP_DROP_MEMBERSHIP)",
1919*a192e900Samaguire 				    strerror(errno));
1920*a192e900Samaguire 			}
1921*a192e900Samaguire 		}
1922*a192e900Samaguire 		li->li_physical->pi_state &= ~ST_JOINED;
1923*a192e900Samaguire 		li->li_state &= ~ST_JOINED;
1924*a192e900Samaguire 
1925*a192e900Samaguire 		/* Is there another interface that can join? */
1926*a192e900Samaguire 		for (oli = pi->pi_logical_first; oli != NULL;
1927*a192e900Samaguire 		    oli = oli->li_next) {
1928*a192e900Samaguire 			if (oli->li_state & ST_DELETED)
1929*a192e900Samaguire 				continue;
1930*a192e900Samaguire 
1931*a192e900Samaguire 			mreq.imr_multiaddr = joinaddr->sin_addr;
1932*a192e900Samaguire 			mreq.imr_interface = oli->li_address;
1933*a192e900Samaguire 
1934*a192e900Samaguire 			if (debug)
1935*a192e900Samaguire 				logdebug("Joining MC on interface %s\n",
1936*a192e900Samaguire 				    oli->li_name);
1937*a192e900Samaguire 
1938*a192e900Samaguire 			if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1939*a192e900Samaguire 				(char *)&mreq, sizeof (mreq)) < 0) {
1940*a192e900Samaguire 				logperror("setsockopt (IP_ADD_MEMBERSHIP)");
1941*a192e900Samaguire 			} else {
1942*a192e900Samaguire 				pi->pi_state |= ST_JOINED;
1943*a192e900Samaguire 				oli->li_state |= ST_JOINED;
1944*a192e900Samaguire 				break;
1945*a192e900Samaguire 			}
1946*a192e900Samaguire 		}
1947*a192e900Samaguire 	}
1948*a192e900Samaguire 
1949*a192e900Samaguire 	flush_unreachable_routers();
1950*a192e900Samaguire }
1951*a192e900Samaguire 
1952*a192e900Samaguire 
1953*a192e900Samaguire 
1954*a192e900Samaguire /*
1955*a192e900Samaguire  * TABLES
1956*a192e900Samaguire  */
1957*a192e900Samaguire struct table {
1958*a192e900Samaguire 	struct in_addr	router;
1959*a192e900Samaguire 	int		preference;
1960*a192e900Samaguire 	int		remaining_time;
1961*a192e900Samaguire 	int		in_kernel;
1962*a192e900Samaguire 	struct table	*next;
1963*a192e900Samaguire };
1964*a192e900Samaguire 
1965*a192e900Samaguire struct table *table;
1966*a192e900Samaguire 
1967*a192e900Samaguire static void
1968*a192e900Samaguire report_routes(void)
1969*a192e900Samaguire {
1970*a192e900Samaguire 	struct table *tp;
1971*a192e900Samaguire 
1972*a192e900Samaguire 	logdebug("\nRoutes:\n\n");
1973*a192e900Samaguire 	tp = table;
1974*a192e900Samaguire 	while (tp) {
1975*a192e900Samaguire 		logdebug("Router %s, pref 0x%x, time %d, %s kernel\n",
1976*a192e900Samaguire 		    pr_name(tp->router), tp->preference,
1977*a192e900Samaguire 		    tp->remaining_time,
1978*a192e900Samaguire 		    (tp->in_kernel ? "in" : "not in"));
1979*a192e900Samaguire 		tp = tp->next;
1980*a192e900Samaguire 	}
1981*a192e900Samaguire }
1982*a192e900Samaguire 
1983*a192e900Samaguire static struct table *
1984*a192e900Samaguire find_router(struct in_addr addr)
1985*a192e900Samaguire {
1986*a192e900Samaguire 	struct table *tp;
1987*a192e900Samaguire 
1988*a192e900Samaguire 	tp = table;
1989*a192e900Samaguire 	while (tp) {
1990*a192e900Samaguire 		if (tp->router.s_addr == addr.s_addr)
1991*a192e900Samaguire 			return (tp);
1992*a192e900Samaguire 		tp = tp->next;
1993*a192e900Samaguire 	}
1994*a192e900Samaguire 	return (NULL);
1995*a192e900Samaguire }
1996*a192e900Samaguire 
1997*a192e900Samaguire static int
1998*a192e900Samaguire max_preference(void)
1999*a192e900Samaguire {
2000*a192e900Samaguire 	struct table *tp;
2001*a192e900Samaguire 	int max = (int)IGNORE_PREFERENCE;
2002*a192e900Samaguire 
2003*a192e900Samaguire 	tp = table;
2004*a192e900Samaguire 	while (tp) {
2005*a192e900Samaguire 		if (tp->preference > max)
2006*a192e900Samaguire 			max = tp->preference;
2007*a192e900Samaguire 		tp = tp->next;
2008*a192e900Samaguire 	}
2009*a192e900Samaguire 	return (max);
2010*a192e900Samaguire }
2011*a192e900Samaguire 
2012*a192e900Samaguire 
2013*a192e900Samaguire /* Note: this might leave the kernel with no default route for a short time. */
2014*a192e900Samaguire static void
2015*a192e900Samaguire age_table(int time)
2016*a192e900Samaguire {
2017*a192e900Samaguire 	struct table **tpp, *tp;
2018*a192e900Samaguire 	int recalculate_max = 0;
2019*a192e900Samaguire 	int max = max_preference();
2020*a192e900Samaguire 
2021*a192e900Samaguire 	tpp = &table;
2022*a192e900Samaguire 	while (*tpp != NULL) {
2023*a192e900Samaguire 		tp = *tpp;
2024*a192e900Samaguire 		tp->remaining_time -= time;
2025*a192e900Samaguire 		if (tp->remaining_time <= 0) {
2026*a192e900Samaguire 			*tpp = tp->next;
2027*a192e900Samaguire 			if (debug) {
2028*a192e900Samaguire 				logdebug("Timed out router %s\n",
2029*a192e900Samaguire 				    pr_name(tp->router));
2030*a192e900Samaguire 			}
2031*a192e900Samaguire 			if (tp->in_kernel)
2032*a192e900Samaguire 				del_route(tp->router);
2033*a192e900Samaguire 			if (best_preference &&
2034*a192e900Samaguire 			    tp->preference == max)
2035*a192e900Samaguire 				recalculate_max++;
2036*a192e900Samaguire 			free((char *)tp);
2037*a192e900Samaguire 		} else {
2038*a192e900Samaguire 			tpp = &tp->next;
2039*a192e900Samaguire 		}
2040*a192e900Samaguire 	}
2041*a192e900Samaguire 	if (recalculate_max) {
2042*a192e900Samaguire 		int max = max_preference();
2043*a192e900Samaguire 
2044*a192e900Samaguire 		if (max != IGNORE_PREFERENCE) {
2045*a192e900Samaguire 			tp = table;
2046*a192e900Samaguire 			while (tp) {
2047*a192e900Samaguire 				if (tp->preference == max && !tp->in_kernel) {
2048*a192e900Samaguire 					add_route(tp->router);
2049*a192e900Samaguire 					tp->in_kernel++;
2050*a192e900Samaguire 				}
2051*a192e900Samaguire 				tp = tp->next;
2052*a192e900Samaguire 			}
2053*a192e900Samaguire 		}
2054*a192e900Samaguire 	}
2055*a192e900Samaguire }
2056*a192e900Samaguire 
2057*a192e900Samaguire /*
2058*a192e900Samaguire  * Remove any routes which are no longer directly connected.
2059*a192e900Samaguire  */
2060*a192e900Samaguire static void
2061*a192e900Samaguire flush_unreachable_routers(void)
2062*a192e900Samaguire {
2063*a192e900Samaguire 	struct table **tpp, *tp;
2064*a192e900Samaguire 	int recalculate_max = 0;
2065*a192e900Samaguire 	int max = max_preference();
2066*a192e900Samaguire 
2067*a192e900Samaguire 	tpp = &table;
2068*a192e900Samaguire 	while (*tpp != NULL) {
2069*a192e900Samaguire 		tp = *tpp;
2070*a192e900Samaguire 		if (find_directly_connected_logint(tp->router, NULL) == NULL) {
2071*a192e900Samaguire 			*tpp = tp->next;
2072*a192e900Samaguire 			if (debug) {
2073*a192e900Samaguire 				logdebug("Unreachable router %s\n",
2074*a192e900Samaguire 				    pr_name(tp->router));
2075*a192e900Samaguire 			}
2076*a192e900Samaguire 			if (tp->in_kernel)
2077*a192e900Samaguire 				del_route(tp->router);
2078*a192e900Samaguire 			if (best_preference &&
2079*a192e900Samaguire 			    tp->preference == max)
2080*a192e900Samaguire 				recalculate_max++;
2081*a192e900Samaguire 			free((char *)tp);
2082*a192e900Samaguire 		} else {
2083*a192e900Samaguire 			tpp = &tp->next;
2084*a192e900Samaguire 		}
2085*a192e900Samaguire 	}
2086*a192e900Samaguire 	if (recalculate_max) {
2087*a192e900Samaguire 		int max = max_preference();
2088*a192e900Samaguire 
2089*a192e900Samaguire 		if (max != IGNORE_PREFERENCE) {
2090*a192e900Samaguire 			tp = table;
2091*a192e900Samaguire 			while (tp) {
2092*a192e900Samaguire 				if (tp->preference == max && !tp->in_kernel) {
2093*a192e900Samaguire 					add_route(tp->router);
2094*a192e900Samaguire 					tp->in_kernel++;
2095*a192e900Samaguire 				}
2096*a192e900Samaguire 				tp = tp->next;
2097*a192e900Samaguire 			}
2098*a192e900Samaguire 		}
2099*a192e900Samaguire 	}
2100*a192e900Samaguire }
2101*a192e900Samaguire 
2102*a192e900Samaguire static void
2103*a192e900Samaguire record_router(struct in_addr router, long preference, int ttl)
2104*a192e900Samaguire {
2105*a192e900Samaguire 	struct table *tp;
2106*a192e900Samaguire 	int old_max = max_preference();
2107*a192e900Samaguire 	int changed_up = 0;	/* max preference could have increased */
2108*a192e900Samaguire 	int changed_down = 0;	/* max preference could have decreased */
2109*a192e900Samaguire 
2110*a192e900Samaguire 	if (debug)
2111*a192e900Samaguire 		logdebug("Recording %s, preference 0x%x\n",
2112*a192e900Samaguire 			pr_name(router),
2113*a192e900Samaguire 			preference);
2114*a192e900Samaguire 	tp = find_router(router);
2115*a192e900Samaguire 	if (tp) {
2116*a192e900Samaguire 		if (tp->preference > preference &&
2117*a192e900Samaguire 		    tp->preference == old_max)
2118*a192e900Samaguire 			changed_down++;
2119*a192e900Samaguire 		else if (preference > tp->preference)
2120*a192e900Samaguire 			changed_up++;
2121*a192e900Samaguire 		tp->preference = preference;
2122*a192e900Samaguire 		tp->remaining_time = ttl;
2123*a192e900Samaguire 	} else {
2124*a192e900Samaguire 		if (preference > old_max)
2125*a192e900Samaguire 			changed_up++;
2126*a192e900Samaguire 		tp = (struct table *)ALIGN(malloc(sizeof (struct table)));
2127*a192e900Samaguire 		if (tp == NULL) {
2128*a192e900Samaguire 			logerr("Out of memory\n");
2129*a192e900Samaguire 			return;
2130*a192e900Samaguire 		}
2131*a192e900Samaguire 		tp->router = router;
2132*a192e900Samaguire 		tp->preference = preference;
2133*a192e900Samaguire 		tp->remaining_time = ttl;
2134*a192e900Samaguire 		tp->in_kernel = 0;
2135*a192e900Samaguire 		tp->next = table;
2136*a192e900Samaguire 		table = tp;
2137*a192e900Samaguire 	}
2138*a192e900Samaguire 	if (!tp->in_kernel &&
2139*a192e900Samaguire 	    (!best_preference || tp->preference == max_preference()) &&
2140*a192e900Samaguire 	    tp->preference != IGNORE_PREFERENCE) {
2141*a192e900Samaguire 		add_route(tp->router);
2142*a192e900Samaguire 		tp->in_kernel++;
2143*a192e900Samaguire 	}
2144*a192e900Samaguire 	if (tp->preference == IGNORE_PREFERENCE && tp->in_kernel) {
2145*a192e900Samaguire 		del_route(tp->router);
2146*a192e900Samaguire 		tp->in_kernel = 0;
2147*a192e900Samaguire 	}
2148*a192e900Samaguire 	if (best_preference && changed_down) {
2149*a192e900Samaguire 		/* Check if we should add routes */
2150*a192e900Samaguire 		int new_max = max_preference();
2151*a192e900Samaguire 		if (new_max != IGNORE_PREFERENCE) {
2152*a192e900Samaguire 			tp = table;
2153*a192e900Samaguire 			while (tp) {
2154*a192e900Samaguire 				if (tp->preference == new_max &&
2155*a192e900Samaguire 				    !tp->in_kernel) {
2156*a192e900Samaguire 					add_route(tp->router);
2157*a192e900Samaguire 					tp->in_kernel++;
2158*a192e900Samaguire 				}
2159*a192e900Samaguire 				tp = tp->next;
2160*a192e900Samaguire 			}
2161*a192e900Samaguire 		}
2162*a192e900Samaguire 	}
2163*a192e900Samaguire 	if (best_preference && (changed_up || changed_down)) {
2164*a192e900Samaguire 		/* Check if we should remove routes already in the kernel */
2165*a192e900Samaguire 		int new_max = max_preference();
2166*a192e900Samaguire 		tp = table;
2167*a192e900Samaguire 		while (tp) {
2168*a192e900Samaguire 			if (tp->preference < new_max && tp->in_kernel) {
2169*a192e900Samaguire 				del_route(tp->router);
2170*a192e900Samaguire 				tp->in_kernel = 0;
2171*a192e900Samaguire 			}
2172*a192e900Samaguire 			tp = tp->next;
2173*a192e900Samaguire 		}
2174*a192e900Samaguire 	}
2175*a192e900Samaguire }
2176*a192e900Samaguire 
2177*a192e900Samaguire 
2178*a192e900Samaguire #include <net/route.h>
2179*a192e900Samaguire 
2180*a192e900Samaguire static void
2181*a192e900Samaguire add_route(struct in_addr addr)
2182*a192e900Samaguire {
2183*a192e900Samaguire 	if (debug)
2184*a192e900Samaguire 		logdebug("Add default route to %s\n", pr_name(addr));
2185*a192e900Samaguire 	rtioctl(addr, SIOCADDRT);
2186*a192e900Samaguire }
2187*a192e900Samaguire 
2188*a192e900Samaguire static void
2189*a192e900Samaguire del_route(struct in_addr addr)
2190*a192e900Samaguire {
2191*a192e900Samaguire 	if (debug)
2192*a192e900Samaguire 		logdebug("Delete default route to %s\n", pr_name(addr));
2193*a192e900Samaguire 	rtioctl(addr, SIOCDELRT);
2194*a192e900Samaguire }
2195*a192e900Samaguire 
2196*a192e900Samaguire static void
2197*a192e900Samaguire rtioctl(struct in_addr addr, int op)
2198*a192e900Samaguire {
2199*a192e900Samaguire 	int sock;
2200*a192e900Samaguire 	struct rtentry rt;
2201*a192e900Samaguire 	struct sockaddr_in *sin;
2202*a192e900Samaguire 	bzero((char *)&rt, sizeof (struct rtentry));
2203*a192e900Samaguire 	rt.rt_dst.sa_family = AF_INET;
2204*a192e900Samaguire 	rt.rt_gateway.sa_family = AF_INET;
2205*a192e900Samaguire 	sin = (struct sockaddr_in *)ALIGN(&rt.rt_gateway);
2206*a192e900Samaguire 	sin->sin_addr = addr;
2207*a192e900Samaguire 	rt.rt_flags = RTF_UP | RTF_GATEWAY;
2208*a192e900Samaguire 
2209*a192e900Samaguire 	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2210*a192e900Samaguire 	if (sock < 0) {
2211*a192e900Samaguire 		logperror("rtioctl: socket");
2212*a192e900Samaguire 		return;
2213*a192e900Samaguire 	}
2214*a192e900Samaguire 	if (ioctl(sock, op, (char *)&rt) < 0) {
2215*a192e900Samaguire 		if (!(op == SIOCADDRT && errno == EEXIST))
2216*a192e900Samaguire 			logperror("ioctl (add/delete route)");
2217*a192e900Samaguire 	}
2218*a192e900Samaguire 	(void) close(sock);
2219*a192e900Samaguire }
2220*a192e900Samaguire 
2221*a192e900Samaguire 
2222*a192e900Samaguire 
2223*a192e900Samaguire /*
2224*a192e900Samaguire  * LOGGER
2225*a192e900Samaguire  */
2226*a192e900Samaguire 
2227*a192e900Samaguire #include <syslog.h>
2228*a192e900Samaguire 
2229*a192e900Samaguire static int logging = 0;
2230*a192e900Samaguire 
2231*a192e900Samaguire static void
2232*a192e900Samaguire initlog(void)
2233*a192e900Samaguire {
2234*a192e900Samaguire 	logging++;
2235*a192e900Samaguire 	openlog("in.rdisc", LOG_PID | LOG_CONS, LOG_DAEMON);
2236*a192e900Samaguire }
2237*a192e900Samaguire 
2238*a192e900Samaguire /* VARARGS1 */
2239*a192e900Samaguire void
2240*a192e900Samaguire logerr(fmt, a, b, c, d, e, f, g, h)
2241*a192e900Samaguire 	char *fmt;
2242*a192e900Samaguire {
2243*a192e900Samaguire 	if (logging)
2244*a192e900Samaguire 		syslog(LOG_ERR, fmt, a, b, c, d, e, f, g, h);
2245*a192e900Samaguire 	else
2246*a192e900Samaguire 		(void) fprintf(stderr, fmt, a, b, c, d, e, f, g, h);
2247*a192e900Samaguire }
2248*a192e900Samaguire 
2249*a192e900Samaguire /* VARARGS1 */
2250*a192e900Samaguire void
2251*a192e900Samaguire logtrace(fmt, a, b, c, d, e, f, g, h)
2252*a192e900Samaguire 	char *fmt;
2253*a192e900Samaguire {
2254*a192e900Samaguire 	if (logging)
2255*a192e900Samaguire 		syslog(LOG_INFO, fmt, a, b, c, d, e, f, g, h);
2256*a192e900Samaguire 	else
2257*a192e900Samaguire 		(void) fprintf(stdout, fmt, a, b, c, d, e, f, g, h);
2258*a192e900Samaguire }
2259*a192e900Samaguire 
2260*a192e900Samaguire /* VARARGS1 */
2261*a192e900Samaguire void
2262*a192e900Samaguire logdebug(fmt, a, b, c, d, e, f, g, h)
2263*a192e900Samaguire 	char *fmt;
2264*a192e900Samaguire {
2265*a192e900Samaguire 	if (logging)
2266*a192e900Samaguire 		syslog(LOG_DEBUG, fmt, a, b, c, d, e, f, g, h);
2267*a192e900Samaguire 	else
2268*a192e900Samaguire 		(void) fprintf(stdout, fmt, a, b, c, d, e, f, g, h);
2269*a192e900Samaguire }
2270*a192e900Samaguire 
2271*a192e900Samaguire void
2272*a192e900Samaguire logperror(str)
2273*a192e900Samaguire 	char *str;
2274*a192e900Samaguire {
2275*a192e900Samaguire 	if (logging)
2276*a192e900Samaguire 		syslog(LOG_ERR, "%s: %s\n", str, strerror(errno));
2277*a192e900Samaguire 	else
2278*a192e900Samaguire 		(void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
2279*a192e900Samaguire }
2280