xref: /aosp_15_r20/external/iputils/rdisc.c (revision bd1f8aeb6080fa6544ec30aeca3eb4da100f359f)
1*bd1f8aebSAndroid Build Coastguard Worker /*
2*bd1f8aebSAndroid Build Coastguard Worker  * Rdisc (this program) was developed by Sun Microsystems, Inc. and is
3*bd1f8aebSAndroid Build Coastguard Worker  * provided for unrestricted use provided that this legend is included on
4*bd1f8aebSAndroid Build Coastguard Worker  * all tape media and as a part of the software program in whole or part.
5*bd1f8aebSAndroid Build Coastguard Worker  * Users may copy or modify Rdisc without charge, and they may freely
6*bd1f8aebSAndroid Build Coastguard Worker  * distribute it.
7*bd1f8aebSAndroid Build Coastguard Worker  *
8*bd1f8aebSAndroid Build Coastguard Worker  * RDISC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
9*bd1f8aebSAndroid Build Coastguard Worker  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
10*bd1f8aebSAndroid Build Coastguard Worker  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
11*bd1f8aebSAndroid Build Coastguard Worker  *
12*bd1f8aebSAndroid Build Coastguard Worker  * Rdisc is provided with no support and without any obligation on the
13*bd1f8aebSAndroid Build Coastguard Worker  * part of Sun Microsystems, Inc. to assist in its use, correction,
14*bd1f8aebSAndroid Build Coastguard Worker  * modification or enhancement.
15*bd1f8aebSAndroid Build Coastguard Worker  *
16*bd1f8aebSAndroid Build Coastguard Worker  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
17*bd1f8aebSAndroid Build Coastguard Worker  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY RDISC
18*bd1f8aebSAndroid Build Coastguard Worker  * OR ANY PART THEREOF.
19*bd1f8aebSAndroid Build Coastguard Worker  *
20*bd1f8aebSAndroid Build Coastguard Worker  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
21*bd1f8aebSAndroid Build Coastguard Worker  * or profits or other special, indirect and consequential damages, even if
22*bd1f8aebSAndroid Build Coastguard Worker  * Sun has been advised of the possibility of such damages.
23*bd1f8aebSAndroid Build Coastguard Worker  *
24*bd1f8aebSAndroid Build Coastguard Worker  * Sun Microsystems, Inc.
25*bd1f8aebSAndroid Build Coastguard Worker  * 2550 Garcia Avenue
26*bd1f8aebSAndroid Build Coastguard Worker  * Mountain View, California  94043
27*bd1f8aebSAndroid Build Coastguard Worker  */
28*bd1f8aebSAndroid Build Coastguard Worker #include <stdio.h>
29*bd1f8aebSAndroid Build Coastguard Worker #include <errno.h>
30*bd1f8aebSAndroid Build Coastguard Worker #include <signal.h>
31*bd1f8aebSAndroid Build Coastguard Worker #include <unistd.h>
32*bd1f8aebSAndroid Build Coastguard Worker #include <stdlib.h>
33*bd1f8aebSAndroid Build Coastguard Worker #include <sys/types.h>
34*bd1f8aebSAndroid Build Coastguard Worker #include <sys/time.h>
35*bd1f8aebSAndroid Build Coastguard Worker /* Do not use "improved" glibc version! */
36*bd1f8aebSAndroid Build Coastguard Worker #include <linux/limits.h>
37*bd1f8aebSAndroid Build Coastguard Worker 
38*bd1f8aebSAndroid Build Coastguard Worker #include <sys/param.h>
39*bd1f8aebSAndroid Build Coastguard Worker #include <sys/socket.h>
40*bd1f8aebSAndroid Build Coastguard Worker #include <sys/file.h>
41*bd1f8aebSAndroid Build Coastguard Worker #include <malloc.h>
42*bd1f8aebSAndroid Build Coastguard Worker 
43*bd1f8aebSAndroid Build Coastguard Worker #include <sys/ioctl.h>
44*bd1f8aebSAndroid Build Coastguard Worker #include <linux/if.h>
45*bd1f8aebSAndroid Build Coastguard Worker #include <linux/route.h>
46*bd1f8aebSAndroid Build Coastguard Worker 
47*bd1f8aebSAndroid Build Coastguard Worker #include <netinet/in.h>
48*bd1f8aebSAndroid Build Coastguard Worker #include <netinet/ip.h>
49*bd1f8aebSAndroid Build Coastguard Worker #include <netinet/ip_icmp.h>
50*bd1f8aebSAndroid Build Coastguard Worker 
51*bd1f8aebSAndroid Build Coastguard Worker /*
52*bd1f8aebSAndroid Build Coastguard Worker  * The next include contains all defs and structures for multicast
53*bd1f8aebSAndroid Build Coastguard Worker  * that are not in SunOS 4.1.x. On a SunOS 4.1.x system none of this code
54*bd1f8aebSAndroid Build Coastguard Worker  * is ever used because it does not support multicast
55*bd1f8aebSAndroid Build Coastguard Worker  * Fraser Gardiner - Sun Microsystems Australia
56*bd1f8aebSAndroid Build Coastguard Worker  */
57*bd1f8aebSAndroid Build Coastguard Worker 
58*bd1f8aebSAndroid Build Coastguard Worker #include <netdb.h>
59*bd1f8aebSAndroid Build Coastguard Worker #include <arpa/inet.h>
60*bd1f8aebSAndroid Build Coastguard Worker 
61*bd1f8aebSAndroid Build Coastguard Worker #include <string.h>
62*bd1f8aebSAndroid Build Coastguard Worker #include <syslog.h>
63*bd1f8aebSAndroid Build Coastguard Worker 
64*bd1f8aebSAndroid Build Coastguard Worker #include "SNAPSHOT.h"
65*bd1f8aebSAndroid Build Coastguard Worker 
66*bd1f8aebSAndroid Build Coastguard Worker struct interface
67*bd1f8aebSAndroid Build Coastguard Worker {
68*bd1f8aebSAndroid Build Coastguard Worker 	struct in_addr 	address;	/* Used to identify the interface */
69*bd1f8aebSAndroid Build Coastguard Worker 	struct in_addr	localaddr;	/* Actual address if the interface */
70*bd1f8aebSAndroid Build Coastguard Worker 	int 		preference;
71*bd1f8aebSAndroid Build Coastguard Worker 	int		flags;
72*bd1f8aebSAndroid Build Coastguard Worker 	struct in_addr	bcastaddr;
73*bd1f8aebSAndroid Build Coastguard Worker 	struct in_addr	remoteaddr;
74*bd1f8aebSAndroid Build Coastguard Worker 	struct in_addr	netmask;
75*bd1f8aebSAndroid Build Coastguard Worker 	int		ifindex;
76*bd1f8aebSAndroid Build Coastguard Worker 	char		name[IFNAMSIZ];
77*bd1f8aebSAndroid Build Coastguard Worker };
78*bd1f8aebSAndroid Build Coastguard Worker 
79*bd1f8aebSAndroid Build Coastguard Worker /*
80*bd1f8aebSAndroid Build Coastguard Worker  * TBD
81*bd1f8aebSAndroid Build Coastguard Worker  *	Use 255.255.255.255 for broadcasts - not the interface broadcast
82*bd1f8aebSAndroid Build Coastguard Worker  *	address.
83*bd1f8aebSAndroid Build Coastguard Worker  */
84*bd1f8aebSAndroid Build Coastguard Worker 
85*bd1f8aebSAndroid Build Coastguard Worker #define ALLIGN(ptr)	(ptr)
86*bd1f8aebSAndroid Build Coastguard Worker 
87*bd1f8aebSAndroid Build Coastguard Worker static int join(int sock, struct sockaddr_in *sin);
88*bd1f8aebSAndroid Build Coastguard Worker static void solicitor(struct sockaddr_in *);
89*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
90*bd1f8aebSAndroid Build Coastguard Worker static void advertise(struct sockaddr_in *, int lft);
91*bd1f8aebSAndroid Build Coastguard Worker #endif
92*bd1f8aebSAndroid Build Coastguard Worker static char *pr_name(struct in_addr addr);
93*bd1f8aebSAndroid Build Coastguard Worker static void pr_pack(char *buf, int cc, struct sockaddr_in *from);
94*bd1f8aebSAndroid Build Coastguard Worker static void age_table(int time);
95*bd1f8aebSAndroid Build Coastguard Worker static void record_router(struct in_addr router, int preference, int ttl);
96*bd1f8aebSAndroid Build Coastguard Worker static void add_route(struct in_addr addr);
97*bd1f8aebSAndroid Build Coastguard Worker static void del_route(struct in_addr addr);
98*bd1f8aebSAndroid Build Coastguard Worker static void rtioctl(struct in_addr addr, int op);
99*bd1f8aebSAndroid Build Coastguard Worker static int support_multicast(void);
100*bd1f8aebSAndroid Build Coastguard Worker static int sendbcast(int s, char *packet, int packetlen);
101*bd1f8aebSAndroid Build Coastguard Worker static int sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *);
102*bd1f8aebSAndroid Build Coastguard Worker static int sendbcastif(int s, char *packet, int packetlen, struct interface *ifp);
103*bd1f8aebSAndroid Build Coastguard Worker static int sendmcastif(int s, char *packet, int packetlen, struct sockaddr_in *sin, struct interface *ifp);
104*bd1f8aebSAndroid Build Coastguard Worker static int is_directly_connected(struct in_addr in);
105*bd1f8aebSAndroid Build Coastguard Worker static void initlog(void);
106*bd1f8aebSAndroid Build Coastguard Worker static void discard_table(void);
107*bd1f8aebSAndroid Build Coastguard Worker static void init(void);
108*bd1f8aebSAndroid Build Coastguard Worker 
109*bd1f8aebSAndroid Build Coastguard Worker #define ICMP_ROUTER_ADVERTISEMENT	9
110*bd1f8aebSAndroid Build Coastguard Worker #define ICMP_ROUTER_SOLICITATION	10
111*bd1f8aebSAndroid Build Coastguard Worker 
112*bd1f8aebSAndroid Build Coastguard Worker #define ALL_HOSTS_ADDRESS		"224.0.0.1"
113*bd1f8aebSAndroid Build Coastguard Worker #define ALL_ROUTERS_ADDRESS		"224.0.0.2"
114*bd1f8aebSAndroid Build Coastguard Worker 
115*bd1f8aebSAndroid Build Coastguard Worker #define MAXIFS 32
116*bd1f8aebSAndroid Build Coastguard Worker 
117*bd1f8aebSAndroid Build Coastguard Worker #if !defined(__GLIBC__) || __GLIBC__ < 2
118*bd1f8aebSAndroid Build Coastguard Worker /* For router advertisement */
119*bd1f8aebSAndroid Build Coastguard Worker struct icmp_ra
120*bd1f8aebSAndroid Build Coastguard Worker {
121*bd1f8aebSAndroid Build Coastguard Worker 	u_char	icmp_type;		/* type of message, see below */
122*bd1f8aebSAndroid Build Coastguard Worker 	u_char	icmp_code;		/* type sub code */
123*bd1f8aebSAndroid Build Coastguard Worker 	u_short	icmp_cksum;		/* ones complement cksum of struct */
124*bd1f8aebSAndroid Build Coastguard Worker 	u_char	icmp_num_addrs;
125*bd1f8aebSAndroid Build Coastguard Worker 	u_char	icmp_wpa;		/* Words per address */
126*bd1f8aebSAndroid Build Coastguard Worker 	short 	icmp_lifetime;
127*bd1f8aebSAndroid Build Coastguard Worker };
128*bd1f8aebSAndroid Build Coastguard Worker 
129*bd1f8aebSAndroid Build Coastguard Worker struct icmp_ra_addr
130*bd1f8aebSAndroid Build Coastguard Worker {
131*bd1f8aebSAndroid Build Coastguard Worker 	__u32	ira_addr;
132*bd1f8aebSAndroid Build Coastguard Worker 	__u32	ira_preference;
133*bd1f8aebSAndroid Build Coastguard Worker };
134*bd1f8aebSAndroid Build Coastguard Worker #else
135*bd1f8aebSAndroid Build Coastguard Worker #define icmp_ra icmp
136*bd1f8aebSAndroid Build Coastguard Worker #endif
137*bd1f8aebSAndroid Build Coastguard Worker 
138*bd1f8aebSAndroid Build Coastguard Worker /* Router constants */
139*bd1f8aebSAndroid Build Coastguard Worker #define	MAX_INITIAL_ADVERT_INTERVAL	16
140*bd1f8aebSAndroid Build Coastguard Worker #define	MAX_INITIAL_ADVERTISEMENTS  	3
141*bd1f8aebSAndroid Build Coastguard Worker #define	MAX_RESPONSE_DELAY		2	/* Not used */
142*bd1f8aebSAndroid Build Coastguard Worker 
143*bd1f8aebSAndroid Build Coastguard Worker /* Host constants */
144*bd1f8aebSAndroid Build Coastguard Worker #define MAX_SOLICITATIONS 		3
145*bd1f8aebSAndroid Build Coastguard Worker #define SOLICITATION_INTERVAL 		3
146*bd1f8aebSAndroid Build Coastguard Worker #define MAX_SOLICITATION_DELAY		1	/* Not used */
147*bd1f8aebSAndroid Build Coastguard Worker 
148*bd1f8aebSAndroid Build Coastguard Worker #define INELIGIBLE_PREF			0x80000000	/* Maximum negative */
149*bd1f8aebSAndroid Build Coastguard Worker 
150*bd1f8aebSAndroid Build Coastguard Worker #define MAX_ADV_INT 600
151*bd1f8aebSAndroid Build Coastguard Worker 
152*bd1f8aebSAndroid Build Coastguard Worker /* Statics */
153*bd1f8aebSAndroid Build Coastguard Worker static int num_interfaces;
154*bd1f8aebSAndroid Build Coastguard Worker 
155*bd1f8aebSAndroid Build Coastguard Worker static struct interface *interfaces;
156*bd1f8aebSAndroid Build Coastguard Worker static int interfaces_size;			/* Number of elements in interfaces */
157*bd1f8aebSAndroid Build Coastguard Worker 
158*bd1f8aebSAndroid Build Coastguard Worker 
159*bd1f8aebSAndroid Build Coastguard Worker #define	MAXPACKET	4096	/* max packet size */
160*bd1f8aebSAndroid Build Coastguard Worker 
161*bd1f8aebSAndroid Build Coastguard Worker /* fraser */
162*bd1f8aebSAndroid Build Coastguard Worker int debugfile;
163*bd1f8aebSAndroid Build Coastguard Worker 
164*bd1f8aebSAndroid Build Coastguard Worker const char usage[] =
165*bd1f8aebSAndroid Build Coastguard Worker "Usage:	rdisc [-b] [-d] [-s] [-v] [-f] [-a] [-V] [send_address] [receive_address]\n"
166*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
167*bd1f8aebSAndroid Build Coastguard Worker "       rdisc -r [-b] [-d] [-s] [-v] [-f] [-a] [-V] [-p <preference>] [-T <secs>]\n"
168*bd1f8aebSAndroid Build Coastguard Worker "		 [send_address] [receive_address]\n"
169*bd1f8aebSAndroid Build Coastguard Worker #endif
170*bd1f8aebSAndroid Build Coastguard Worker ;
171*bd1f8aebSAndroid Build Coastguard Worker 
172*bd1f8aebSAndroid Build Coastguard Worker 
173*bd1f8aebSAndroid Build Coastguard Worker int s;			/* Socket file descriptor */
174*bd1f8aebSAndroid Build Coastguard Worker struct sockaddr_in whereto;/* Address to send to */
175*bd1f8aebSAndroid Build Coastguard Worker 
176*bd1f8aebSAndroid Build Coastguard Worker /* Common variables */
177*bd1f8aebSAndroid Build Coastguard Worker int verbose = 0;
178*bd1f8aebSAndroid Build Coastguard Worker int debug = 0;
179*bd1f8aebSAndroid Build Coastguard Worker int trace = 0;
180*bd1f8aebSAndroid Build Coastguard Worker int solicit = 0;
181*bd1f8aebSAndroid Build Coastguard Worker int ntransmitted = 0;
182*bd1f8aebSAndroid Build Coastguard Worker int nreceived = 0;
183*bd1f8aebSAndroid Build Coastguard Worker int forever = 0;	/* Never give up on host. If 0 defer fork until
184*bd1f8aebSAndroid Build Coastguard Worker 			 * first response.
185*bd1f8aebSAndroid Build Coastguard Worker 			 */
186*bd1f8aebSAndroid Build Coastguard Worker 
187*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
188*bd1f8aebSAndroid Build Coastguard Worker /* Router variables */
189*bd1f8aebSAndroid Build Coastguard Worker int responder;
190*bd1f8aebSAndroid Build Coastguard Worker int max_adv_int = MAX_ADV_INT;
191*bd1f8aebSAndroid Build Coastguard Worker int min_adv_int;
192*bd1f8aebSAndroid Build Coastguard Worker int lifetime;
193*bd1f8aebSAndroid Build Coastguard Worker int initial_advert_interval = MAX_INITIAL_ADVERT_INTERVAL;
194*bd1f8aebSAndroid Build Coastguard Worker int initial_advertisements = MAX_INITIAL_ADVERTISEMENTS;
195*bd1f8aebSAndroid Build Coastguard Worker int preference = 0;		/* Setable with -p option */
196*bd1f8aebSAndroid Build Coastguard Worker #endif
197*bd1f8aebSAndroid Build Coastguard Worker 
198*bd1f8aebSAndroid Build Coastguard Worker /* Host variables */
199*bd1f8aebSAndroid Build Coastguard Worker int max_solicitations = MAX_SOLICITATIONS;
200*bd1f8aebSAndroid Build Coastguard Worker unsigned int solicitation_interval = SOLICITATION_INTERVAL;
201*bd1f8aebSAndroid Build Coastguard Worker int best_preference = 1;  	/* Set to record only the router(s) with the
202*bd1f8aebSAndroid Build Coastguard Worker 				   best preference in the kernel. Not set
203*bd1f8aebSAndroid Build Coastguard Worker 				   puts all routes in the kernel. */
204*bd1f8aebSAndroid Build Coastguard Worker 
205*bd1f8aebSAndroid Build Coastguard Worker 
206*bd1f8aebSAndroid Build Coastguard Worker static void graceful_finish(void);
207*bd1f8aebSAndroid Build Coastguard Worker static void finish(void);
208*bd1f8aebSAndroid Build Coastguard Worker static void timer(void);
209*bd1f8aebSAndroid Build Coastguard Worker static void initifs(void);
210*bd1f8aebSAndroid Build Coastguard Worker static u_short in_cksum(u_short *addr, int len);
211*bd1f8aebSAndroid Build Coastguard Worker 
212*bd1f8aebSAndroid Build Coastguard Worker static int logging = 0;
213*bd1f8aebSAndroid Build Coastguard Worker 
214*bd1f8aebSAndroid Build Coastguard Worker #define logerr(fmt...) ({ if (logging) syslog(LOG_ERR, fmt); \
215*bd1f8aebSAndroid Build Coastguard Worker 			  else fprintf(stderr, fmt); })
216*bd1f8aebSAndroid Build Coastguard Worker #define logtrace(fmt...) ({ if (logging) syslog(LOG_INFO, fmt); \
217*bd1f8aebSAndroid Build Coastguard Worker 			  else fprintf(stderr, fmt); })
218*bd1f8aebSAndroid Build Coastguard Worker #define logdebug(fmt...) ({ if (logging) syslog(LOG_DEBUG, fmt); \
219*bd1f8aebSAndroid Build Coastguard Worker 			  else fprintf(stderr, fmt); })
220*bd1f8aebSAndroid Build Coastguard Worker static void logperror(char *str);
221*bd1f8aebSAndroid Build Coastguard Worker 
isbroadcast(struct sockaddr_in * sin)222*bd1f8aebSAndroid Build Coastguard Worker static __inline__ int isbroadcast(struct sockaddr_in *sin)
223*bd1f8aebSAndroid Build Coastguard Worker {
224*bd1f8aebSAndroid Build Coastguard Worker 	return (sin->sin_addr.s_addr == INADDR_BROADCAST);
225*bd1f8aebSAndroid Build Coastguard Worker }
226*bd1f8aebSAndroid Build Coastguard Worker 
ismulticast(struct sockaddr_in * sin)227*bd1f8aebSAndroid Build Coastguard Worker static __inline__ int ismulticast(struct sockaddr_in *sin)
228*bd1f8aebSAndroid Build Coastguard Worker {
229*bd1f8aebSAndroid Build Coastguard Worker 	return IN_CLASSD(ntohl(sin->sin_addr.s_addr));
230*bd1f8aebSAndroid Build Coastguard Worker }
231*bd1f8aebSAndroid Build Coastguard Worker 
prusage(void)232*bd1f8aebSAndroid Build Coastguard Worker static void prusage(void)
233*bd1f8aebSAndroid Build Coastguard Worker {
234*bd1f8aebSAndroid Build Coastguard Worker 	fputs(usage, stderr);
235*bd1f8aebSAndroid Build Coastguard Worker 	exit(1);
236*bd1f8aebSAndroid Build Coastguard Worker }
237*bd1f8aebSAndroid Build Coastguard Worker 
do_fork(void)238*bd1f8aebSAndroid Build Coastguard Worker void do_fork(void)
239*bd1f8aebSAndroid Build Coastguard Worker {
240*bd1f8aebSAndroid Build Coastguard Worker 	int t;
241*bd1f8aebSAndroid Build Coastguard Worker 	pid_t pid;
242*bd1f8aebSAndroid Build Coastguard Worker 	long open_max;
243*bd1f8aebSAndroid Build Coastguard Worker 
244*bd1f8aebSAndroid Build Coastguard Worker 	if (trace)
245*bd1f8aebSAndroid Build Coastguard Worker 		return;
246*bd1f8aebSAndroid Build Coastguard Worker 	if ((open_max = sysconf(_SC_OPEN_MAX)) == -1) {
247*bd1f8aebSAndroid Build Coastguard Worker 		if (errno == 0) {
248*bd1f8aebSAndroid Build Coastguard Worker 			(void) fprintf(stderr, "OPEN_MAX is not supported\n");
249*bd1f8aebSAndroid Build Coastguard Worker 		}
250*bd1f8aebSAndroid Build Coastguard Worker 		else {
251*bd1f8aebSAndroid Build Coastguard Worker 			(void) fprintf(stderr, "sysconf() error\n");
252*bd1f8aebSAndroid Build Coastguard Worker 		}
253*bd1f8aebSAndroid Build Coastguard Worker 		exit(1);
254*bd1f8aebSAndroid Build Coastguard Worker 	}
255*bd1f8aebSAndroid Build Coastguard Worker 
256*bd1f8aebSAndroid Build Coastguard Worker 
257*bd1f8aebSAndroid Build Coastguard Worker 	if ((pid=fork()) != 0)
258*bd1f8aebSAndroid Build Coastguard Worker 		exit(0);
259*bd1f8aebSAndroid Build Coastguard Worker 
260*bd1f8aebSAndroid Build Coastguard Worker 	for (t = 0; t < open_max; t++)
261*bd1f8aebSAndroid Build Coastguard Worker 		if (t != s)
262*bd1f8aebSAndroid Build Coastguard Worker 			close(t);
263*bd1f8aebSAndroid Build Coastguard Worker 
264*bd1f8aebSAndroid Build Coastguard Worker 	setsid();
265*bd1f8aebSAndroid Build Coastguard Worker 	initlog();
266*bd1f8aebSAndroid Build Coastguard Worker }
267*bd1f8aebSAndroid Build Coastguard Worker 
signal_setup(int signo,void (* handler)(void))268*bd1f8aebSAndroid Build Coastguard Worker void signal_setup(int signo, void (*handler)(void))
269*bd1f8aebSAndroid Build Coastguard Worker {
270*bd1f8aebSAndroid Build Coastguard Worker 	struct sigaction sa;
271*bd1f8aebSAndroid Build Coastguard Worker 
272*bd1f8aebSAndroid Build Coastguard Worker 	memset(&sa, 0, sizeof(sa));
273*bd1f8aebSAndroid Build Coastguard Worker 
274*bd1f8aebSAndroid Build Coastguard Worker 	sa.sa_handler = (void (*)(int))handler;
275*bd1f8aebSAndroid Build Coastguard Worker #ifdef SA_INTERRUPT
276*bd1f8aebSAndroid Build Coastguard Worker 	sa.sa_flags = SA_INTERRUPT;
277*bd1f8aebSAndroid Build Coastguard Worker #endif
278*bd1f8aebSAndroid Build Coastguard Worker 	sigaction(signo, &sa, NULL);
279*bd1f8aebSAndroid Build Coastguard Worker }
280*bd1f8aebSAndroid Build Coastguard Worker 
281*bd1f8aebSAndroid Build Coastguard Worker /*
282*bd1f8aebSAndroid Build Coastguard Worker  * 			M A I N
283*bd1f8aebSAndroid Build Coastguard Worker  */
284*bd1f8aebSAndroid Build Coastguard Worker char    *sendaddress, *recvaddress;
285*bd1f8aebSAndroid Build Coastguard Worker 
main(int argc,char ** argv)286*bd1f8aebSAndroid Build Coastguard Worker int main(int argc, char **argv)
287*bd1f8aebSAndroid Build Coastguard Worker {
288*bd1f8aebSAndroid Build Coastguard Worker 	struct sockaddr_in from;
289*bd1f8aebSAndroid Build Coastguard Worker 	char **av = argv;
290*bd1f8aebSAndroid Build Coastguard Worker 	struct sockaddr_in *to = &whereto;
291*bd1f8aebSAndroid Build Coastguard Worker 	struct sockaddr_in joinaddr;
292*bd1f8aebSAndroid Build Coastguard Worker 	sigset_t sset, sset_empty;
293*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
294*bd1f8aebSAndroid Build Coastguard Worker 	int val;
295*bd1f8aebSAndroid Build Coastguard Worker 
296*bd1f8aebSAndroid Build Coastguard Worker 	min_adv_int =( max_adv_int * 3 / 4);
297*bd1f8aebSAndroid Build Coastguard Worker 	lifetime = (3*max_adv_int);
298*bd1f8aebSAndroid Build Coastguard Worker #endif
299*bd1f8aebSAndroid Build Coastguard Worker 
300*bd1f8aebSAndroid Build Coastguard Worker 	argc--, av++;
301*bd1f8aebSAndroid Build Coastguard Worker 	while (argc > 0 && *av[0] == '-') {
302*bd1f8aebSAndroid Build Coastguard Worker 		while (*++av[0]) {
303*bd1f8aebSAndroid Build Coastguard Worker 			switch (*av[0]) {
304*bd1f8aebSAndroid Build Coastguard Worker 			case 'd':
305*bd1f8aebSAndroid Build Coastguard Worker 				debug = 1;
306*bd1f8aebSAndroid Build Coastguard Worker 				break;
307*bd1f8aebSAndroid Build Coastguard Worker 			case 't':
308*bd1f8aebSAndroid Build Coastguard Worker 				trace = 1;
309*bd1f8aebSAndroid Build Coastguard Worker 				break;
310*bd1f8aebSAndroid Build Coastguard Worker 			case 'v':
311*bd1f8aebSAndroid Build Coastguard Worker 				verbose++;
312*bd1f8aebSAndroid Build Coastguard Worker 				break;
313*bd1f8aebSAndroid Build Coastguard Worker 			case 's':
314*bd1f8aebSAndroid Build Coastguard Worker 				solicit = 1;
315*bd1f8aebSAndroid Build Coastguard Worker 				break;
316*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
317*bd1f8aebSAndroid Build Coastguard Worker 			case 'r':
318*bd1f8aebSAndroid Build Coastguard Worker 				responder = 1;
319*bd1f8aebSAndroid Build Coastguard Worker 				break;
320*bd1f8aebSAndroid Build Coastguard Worker #endif
321*bd1f8aebSAndroid Build Coastguard Worker 			case 'a':
322*bd1f8aebSAndroid Build Coastguard Worker 				best_preference = 0;
323*bd1f8aebSAndroid Build Coastguard Worker 				break;
324*bd1f8aebSAndroid Build Coastguard Worker 			case 'b':
325*bd1f8aebSAndroid Build Coastguard Worker 				best_preference = 1;
326*bd1f8aebSAndroid Build Coastguard Worker 				break;
327*bd1f8aebSAndroid Build Coastguard Worker 			case 'f':
328*bd1f8aebSAndroid Build Coastguard Worker 				forever = 1;
329*bd1f8aebSAndroid Build Coastguard Worker 				break;
330*bd1f8aebSAndroid Build Coastguard Worker 			case 'V':
331*bd1f8aebSAndroid Build Coastguard Worker 				printf("rdisc utility, iputils-%s\n", SNAPSHOT);
332*bd1f8aebSAndroid Build Coastguard Worker 				exit(0);
333*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
334*bd1f8aebSAndroid Build Coastguard Worker 			case 'T':
335*bd1f8aebSAndroid Build Coastguard Worker 				argc--, av++;
336*bd1f8aebSAndroid Build Coastguard Worker 				if (argc != 0) {
337*bd1f8aebSAndroid Build Coastguard Worker 					val = strtol(av[0], (char **)NULL, 0);
338*bd1f8aebSAndroid Build Coastguard Worker 					if (val < 4 || val > 1800) {
339*bd1f8aebSAndroid Build Coastguard Worker 						(void) fprintf(stderr,
340*bd1f8aebSAndroid Build Coastguard Worker 							       "Bad Max Advertizement Interval\n");
341*bd1f8aebSAndroid Build Coastguard Worker 						exit(1);
342*bd1f8aebSAndroid Build Coastguard Worker 					}
343*bd1f8aebSAndroid Build Coastguard Worker 					max_adv_int = val;
344*bd1f8aebSAndroid Build Coastguard Worker 					min_adv_int =( max_adv_int * 3 / 4);
345*bd1f8aebSAndroid Build Coastguard Worker 					lifetime = (3*max_adv_int);
346*bd1f8aebSAndroid Build Coastguard Worker 				} else {
347*bd1f8aebSAndroid Build Coastguard Worker 					prusage();
348*bd1f8aebSAndroid Build Coastguard Worker 					/* NOTREACHED*/
349*bd1f8aebSAndroid Build Coastguard Worker 				}
350*bd1f8aebSAndroid Build Coastguard Worker 				goto next;
351*bd1f8aebSAndroid Build Coastguard Worker 			case 'p':
352*bd1f8aebSAndroid Build Coastguard Worker 				argc--, av++;
353*bd1f8aebSAndroid Build Coastguard Worker 				if (argc != 0) {
354*bd1f8aebSAndroid Build Coastguard Worker 					val = strtol(av[0], (char **)NULL, 0);
355*bd1f8aebSAndroid Build Coastguard Worker 					preference = val;
356*bd1f8aebSAndroid Build Coastguard Worker 				} else {
357*bd1f8aebSAndroid Build Coastguard Worker 					prusage();
358*bd1f8aebSAndroid Build Coastguard Worker 					/* NOTREACHED*/
359*bd1f8aebSAndroid Build Coastguard Worker 				}
360*bd1f8aebSAndroid Build Coastguard Worker 				goto next;
361*bd1f8aebSAndroid Build Coastguard Worker #endif
362*bd1f8aebSAndroid Build Coastguard Worker 			default:
363*bd1f8aebSAndroid Build Coastguard Worker 				prusage();
364*bd1f8aebSAndroid Build Coastguard Worker 				/* NOTREACHED*/
365*bd1f8aebSAndroid Build Coastguard Worker 			}
366*bd1f8aebSAndroid Build Coastguard Worker 		}
367*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
368*bd1f8aebSAndroid Build Coastguard Worker next:
369*bd1f8aebSAndroid Build Coastguard Worker #endif
370*bd1f8aebSAndroid Build Coastguard Worker 		argc--, av++;
371*bd1f8aebSAndroid Build Coastguard Worker 	}
372*bd1f8aebSAndroid Build Coastguard Worker 	if( argc < 1)  {
373*bd1f8aebSAndroid Build Coastguard Worker 		if (support_multicast()) {
374*bd1f8aebSAndroid Build Coastguard Worker 			sendaddress = ALL_ROUTERS_ADDRESS;
375*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
376*bd1f8aebSAndroid Build Coastguard Worker 			if (responder)
377*bd1f8aebSAndroid Build Coastguard Worker 				sendaddress = ALL_HOSTS_ADDRESS;
378*bd1f8aebSAndroid Build Coastguard Worker #endif
379*bd1f8aebSAndroid Build Coastguard Worker 		} else
380*bd1f8aebSAndroid Build Coastguard Worker 			sendaddress = "255.255.255.255";
381*bd1f8aebSAndroid Build Coastguard Worker 	} else {
382*bd1f8aebSAndroid Build Coastguard Worker 		sendaddress = av[0];
383*bd1f8aebSAndroid Build Coastguard Worker 		argc--;
384*bd1f8aebSAndroid Build Coastguard Worker 	}
385*bd1f8aebSAndroid Build Coastguard Worker 
386*bd1f8aebSAndroid Build Coastguard Worker 	if (argc < 1) {
387*bd1f8aebSAndroid Build Coastguard Worker 		if (support_multicast()) {
388*bd1f8aebSAndroid Build Coastguard Worker 			recvaddress = ALL_HOSTS_ADDRESS;
389*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
390*bd1f8aebSAndroid Build Coastguard Worker 			if (responder)
391*bd1f8aebSAndroid Build Coastguard Worker 				recvaddress = ALL_ROUTERS_ADDRESS;
392*bd1f8aebSAndroid Build Coastguard Worker #endif
393*bd1f8aebSAndroid Build Coastguard Worker 		} else
394*bd1f8aebSAndroid Build Coastguard Worker 			recvaddress = "255.255.255.255";
395*bd1f8aebSAndroid Build Coastguard Worker 	} else {
396*bd1f8aebSAndroid Build Coastguard Worker 		recvaddress = av[0];
397*bd1f8aebSAndroid Build Coastguard Worker 		argc--;
398*bd1f8aebSAndroid Build Coastguard Worker 	}
399*bd1f8aebSAndroid Build Coastguard Worker 	if (argc != 0) {
400*bd1f8aebSAndroid Build Coastguard Worker 		(void) fprintf(stderr, "Extra parameters\n");
401*bd1f8aebSAndroid Build Coastguard Worker 		prusage();
402*bd1f8aebSAndroid Build Coastguard Worker 		/* NOTREACHED */
403*bd1f8aebSAndroid Build Coastguard Worker 	}
404*bd1f8aebSAndroid Build Coastguard Worker 
405*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
406*bd1f8aebSAndroid Build Coastguard Worker 	if (solicit && responder) {
407*bd1f8aebSAndroid Build Coastguard Worker 		prusage();
408*bd1f8aebSAndroid Build Coastguard Worker 		/* NOTREACHED */
409*bd1f8aebSAndroid Build Coastguard Worker 	}
410*bd1f8aebSAndroid Build Coastguard Worker #endif
411*bd1f8aebSAndroid Build Coastguard Worker 
412*bd1f8aebSAndroid Build Coastguard Worker 	if (!(solicit && !forever)) {
413*bd1f8aebSAndroid Build Coastguard Worker 		do_fork();
414*bd1f8aebSAndroid Build Coastguard Worker /*
415*bd1f8aebSAndroid Build Coastguard Worker  * Added the next line to stop forking a second time
416*bd1f8aebSAndroid Build Coastguard Worker  * Fraser Gardiner - Sun Microsystems Australia
417*bd1f8aebSAndroid Build Coastguard Worker  */
418*bd1f8aebSAndroid Build Coastguard Worker 		forever = 1;
419*bd1f8aebSAndroid Build Coastguard Worker 	}
420*bd1f8aebSAndroid Build Coastguard Worker 
421*bd1f8aebSAndroid Build Coastguard Worker 	memset( (char *)&whereto, 0, sizeof(struct sockaddr_in) );
422*bd1f8aebSAndroid Build Coastguard Worker 	to->sin_family = AF_INET;
423*bd1f8aebSAndroid Build Coastguard Worker 	to->sin_addr.s_addr = inet_addr(sendaddress);
424*bd1f8aebSAndroid Build Coastguard Worker 
425*bd1f8aebSAndroid Build Coastguard Worker 	memset( (char *)&joinaddr, 0, sizeof(struct sockaddr_in) );
426*bd1f8aebSAndroid Build Coastguard Worker 	joinaddr.sin_family = AF_INET;
427*bd1f8aebSAndroid Build Coastguard Worker 	joinaddr.sin_addr.s_addr = inet_addr(recvaddress);
428*bd1f8aebSAndroid Build Coastguard Worker 
429*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
430*bd1f8aebSAndroid Build Coastguard Worker 	if (responder)
431*bd1f8aebSAndroid Build Coastguard Worker 		srandom((int)gethostid());
432*bd1f8aebSAndroid Build Coastguard Worker #endif
433*bd1f8aebSAndroid Build Coastguard Worker 
434*bd1f8aebSAndroid Build Coastguard Worker 	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
435*bd1f8aebSAndroid Build Coastguard Worker 		logperror("socket");
436*bd1f8aebSAndroid Build Coastguard Worker 		exit(5);
437*bd1f8aebSAndroid Build Coastguard Worker 	}
438*bd1f8aebSAndroid Build Coastguard Worker 
439*bd1f8aebSAndroid Build Coastguard Worker 	setlinebuf( stdout );
440*bd1f8aebSAndroid Build Coastguard Worker 
441*bd1f8aebSAndroid Build Coastguard Worker 	signal_setup(SIGINT, finish );
442*bd1f8aebSAndroid Build Coastguard Worker 	signal_setup(SIGTERM, graceful_finish );
443*bd1f8aebSAndroid Build Coastguard Worker 	signal_setup(SIGHUP, initifs );
444*bd1f8aebSAndroid Build Coastguard Worker 	signal_setup(SIGALRM, timer );
445*bd1f8aebSAndroid Build Coastguard Worker 
446*bd1f8aebSAndroid Build Coastguard Worker 	sigemptyset(&sset);
447*bd1f8aebSAndroid Build Coastguard Worker 	sigemptyset(&sset_empty);
448*bd1f8aebSAndroid Build Coastguard Worker 	sigaddset(&sset, SIGALRM);
449*bd1f8aebSAndroid Build Coastguard Worker 	sigaddset(&sset, SIGHUP);
450*bd1f8aebSAndroid Build Coastguard Worker 	sigaddset(&sset, SIGTERM);
451*bd1f8aebSAndroid Build Coastguard Worker 	sigaddset(&sset, SIGINT);
452*bd1f8aebSAndroid Build Coastguard Worker 
453*bd1f8aebSAndroid Build Coastguard Worker 	init();
454*bd1f8aebSAndroid Build Coastguard Worker 	if (join(s, &joinaddr) < 0) {
455*bd1f8aebSAndroid Build Coastguard Worker 		logerr("Failed joining addresses\n");
456*bd1f8aebSAndroid Build Coastguard Worker 		exit (2);
457*bd1f8aebSAndroid Build Coastguard Worker 	}
458*bd1f8aebSAndroid Build Coastguard Worker 
459*bd1f8aebSAndroid Build Coastguard Worker 	timer();	/* start things going */
460*bd1f8aebSAndroid Build Coastguard Worker 
461*bd1f8aebSAndroid Build Coastguard Worker 	for (;;) {
462*bd1f8aebSAndroid Build Coastguard Worker 		u_char	packet[MAXPACKET];
463*bd1f8aebSAndroid Build Coastguard Worker 		int len = sizeof (packet);
464*bd1f8aebSAndroid Build Coastguard Worker 		socklen_t fromlen = sizeof (from);
465*bd1f8aebSAndroid Build Coastguard Worker 		int cc;
466*bd1f8aebSAndroid Build Coastguard Worker 
467*bd1f8aebSAndroid Build Coastguard Worker 		cc=recvfrom(s, (char *)packet, len, 0,
468*bd1f8aebSAndroid Build Coastguard Worker 			    (struct sockaddr *)&from, &fromlen);
469*bd1f8aebSAndroid Build Coastguard Worker 		if (cc<0) {
470*bd1f8aebSAndroid Build Coastguard Worker 			if (errno == EINTR)
471*bd1f8aebSAndroid Build Coastguard Worker 				continue;
472*bd1f8aebSAndroid Build Coastguard Worker 			logperror("recvfrom");
473*bd1f8aebSAndroid Build Coastguard Worker 			continue;
474*bd1f8aebSAndroid Build Coastguard Worker 		}
475*bd1f8aebSAndroid Build Coastguard Worker 
476*bd1f8aebSAndroid Build Coastguard Worker 		sigprocmask(SIG_SETMASK, &sset, NULL);
477*bd1f8aebSAndroid Build Coastguard Worker 		pr_pack( (char *)packet, cc, &from );
478*bd1f8aebSAndroid Build Coastguard Worker 		sigprocmask(SIG_SETMASK, &sset_empty, NULL);
479*bd1f8aebSAndroid Build Coastguard Worker 	}
480*bd1f8aebSAndroid Build Coastguard Worker 	/*NOTREACHED*/
481*bd1f8aebSAndroid Build Coastguard Worker }
482*bd1f8aebSAndroid Build Coastguard Worker 
483*bd1f8aebSAndroid Build Coastguard Worker #define TIMER_INTERVAL 	3
484*bd1f8aebSAndroid Build Coastguard Worker #define GETIFCONF_TIMER	30
485*bd1f8aebSAndroid Build Coastguard Worker 
486*bd1f8aebSAndroid Build Coastguard Worker static int left_until_advertise;
487*bd1f8aebSAndroid Build Coastguard Worker 
488*bd1f8aebSAndroid Build Coastguard Worker /* Called every TIMER_INTERVAL */
timer()489*bd1f8aebSAndroid Build Coastguard Worker void timer()
490*bd1f8aebSAndroid Build Coastguard Worker {
491*bd1f8aebSAndroid Build Coastguard Worker 	static int time;
492*bd1f8aebSAndroid Build Coastguard Worker 	static int left_until_getifconf;
493*bd1f8aebSAndroid Build Coastguard Worker 	static int left_until_solicit;
494*bd1f8aebSAndroid Build Coastguard Worker 
495*bd1f8aebSAndroid Build Coastguard Worker 
496*bd1f8aebSAndroid Build Coastguard Worker 	time += TIMER_INTERVAL;
497*bd1f8aebSAndroid Build Coastguard Worker 
498*bd1f8aebSAndroid Build Coastguard Worker 	left_until_getifconf -= TIMER_INTERVAL;
499*bd1f8aebSAndroid Build Coastguard Worker 	left_until_advertise -= TIMER_INTERVAL;
500*bd1f8aebSAndroid Build Coastguard Worker 	left_until_solicit -= TIMER_INTERVAL;
501*bd1f8aebSAndroid Build Coastguard Worker 
502*bd1f8aebSAndroid Build Coastguard Worker 	if (left_until_getifconf < 0) {
503*bd1f8aebSAndroid Build Coastguard Worker 		initifs();
504*bd1f8aebSAndroid Build Coastguard Worker 		left_until_getifconf = GETIFCONF_TIMER;
505*bd1f8aebSAndroid Build Coastguard Worker 	}
506*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
507*bd1f8aebSAndroid Build Coastguard Worker 	if (responder && left_until_advertise <= 0) {
508*bd1f8aebSAndroid Build Coastguard Worker 		ntransmitted++;
509*bd1f8aebSAndroid Build Coastguard Worker 		advertise(&whereto, lifetime);
510*bd1f8aebSAndroid Build Coastguard Worker 		if (ntransmitted < initial_advertisements)
511*bd1f8aebSAndroid Build Coastguard Worker 			left_until_advertise = initial_advert_interval;
512*bd1f8aebSAndroid Build Coastguard Worker 		else
513*bd1f8aebSAndroid Build Coastguard Worker 			left_until_advertise = min_adv_int +
514*bd1f8aebSAndroid Build Coastguard Worker 				((max_adv_int - min_adv_int) *
515*bd1f8aebSAndroid Build Coastguard Worker 				 (random() % 1000)/1000);
516*bd1f8aebSAndroid Build Coastguard Worker 	} else
517*bd1f8aebSAndroid Build Coastguard Worker #endif
518*bd1f8aebSAndroid Build Coastguard Worker 	if (solicit && left_until_solicit <= 0) {
519*bd1f8aebSAndroid Build Coastguard Worker 		ntransmitted++;
520*bd1f8aebSAndroid Build Coastguard Worker 		solicitor(&whereto);
521*bd1f8aebSAndroid Build Coastguard Worker 		if (ntransmitted < max_solicitations)
522*bd1f8aebSAndroid Build Coastguard Worker 			left_until_solicit = solicitation_interval;
523*bd1f8aebSAndroid Build Coastguard Worker 		else {
524*bd1f8aebSAndroid Build Coastguard Worker 			solicit = 0;
525*bd1f8aebSAndroid Build Coastguard Worker 			if (!forever && nreceived == 0)
526*bd1f8aebSAndroid Build Coastguard Worker 				exit(5);
527*bd1f8aebSAndroid Build Coastguard Worker 		}
528*bd1f8aebSAndroid Build Coastguard Worker 	}
529*bd1f8aebSAndroid Build Coastguard Worker 	age_table(TIMER_INTERVAL);
530*bd1f8aebSAndroid Build Coastguard Worker 	alarm(TIMER_INTERVAL);
531*bd1f8aebSAndroid Build Coastguard Worker }
532*bd1f8aebSAndroid Build Coastguard Worker 
533*bd1f8aebSAndroid Build Coastguard Worker /*
534*bd1f8aebSAndroid Build Coastguard Worker  * 			S O L I C I T O R
535*bd1f8aebSAndroid Build Coastguard Worker  *
536*bd1f8aebSAndroid Build Coastguard Worker  * Compose and transmit an ICMP ROUTER SOLICITATION REQUEST packet.
537*bd1f8aebSAndroid Build Coastguard Worker  * The IP packet will be added on by the kernel.
538*bd1f8aebSAndroid Build Coastguard Worker  */
539*bd1f8aebSAndroid Build Coastguard Worker void
solicitor(struct sockaddr_in * sin)540*bd1f8aebSAndroid Build Coastguard Worker solicitor(struct sockaddr_in *sin)
541*bd1f8aebSAndroid Build Coastguard Worker {
542*bd1f8aebSAndroid Build Coastguard Worker 	static u_char outpack[MAXPACKET];
543*bd1f8aebSAndroid Build Coastguard Worker 	struct icmphdr *icp = (struct icmphdr *) ALLIGN(outpack);
544*bd1f8aebSAndroid Build Coastguard Worker 	int packetlen, i;
545*bd1f8aebSAndroid Build Coastguard Worker 
546*bd1f8aebSAndroid Build Coastguard Worker 	if (verbose) {
547*bd1f8aebSAndroid Build Coastguard Worker 		logtrace("Sending solicitation to %s\n",
548*bd1f8aebSAndroid Build Coastguard Worker 			 pr_name(sin->sin_addr));
549*bd1f8aebSAndroid Build Coastguard Worker 	}
550*bd1f8aebSAndroid Build Coastguard Worker 	icp->type = ICMP_ROUTER_SOLICITATION;
551*bd1f8aebSAndroid Build Coastguard Worker 	icp->code = 0;
552*bd1f8aebSAndroid Build Coastguard Worker 	icp->checksum = 0;
553*bd1f8aebSAndroid Build Coastguard Worker 	icp->un.gateway = 0; /* Reserved */
554*bd1f8aebSAndroid Build Coastguard Worker 	packetlen = 8;
555*bd1f8aebSAndroid Build Coastguard Worker 
556*bd1f8aebSAndroid Build Coastguard Worker 	/* Compute ICMP checksum here */
557*bd1f8aebSAndroid Build Coastguard Worker 	icp->checksum = in_cksum( (u_short *)icp, packetlen );
558*bd1f8aebSAndroid Build Coastguard Worker 
559*bd1f8aebSAndroid Build Coastguard Worker 	if (isbroadcast(sin))
560*bd1f8aebSAndroid Build Coastguard Worker 		i = sendbcast(s, (char *)outpack, packetlen);
561*bd1f8aebSAndroid Build Coastguard Worker 	else if (ismulticast(sin))
562*bd1f8aebSAndroid Build Coastguard Worker 		i = sendmcast(s, (char *)outpack, packetlen, sin);
563*bd1f8aebSAndroid Build Coastguard Worker 	else
564*bd1f8aebSAndroid Build Coastguard Worker 		i = sendto( s, (char *)outpack, packetlen, 0,
565*bd1f8aebSAndroid Build Coastguard Worker 			   (struct sockaddr *)sin, sizeof(struct sockaddr));
566*bd1f8aebSAndroid Build Coastguard Worker 
567*bd1f8aebSAndroid Build Coastguard Worker 	if( i < 0 || i != packetlen )  {
568*bd1f8aebSAndroid Build Coastguard Worker 		if( i<0 ) {
569*bd1f8aebSAndroid Build Coastguard Worker 		    logperror("solicitor:sendto");
570*bd1f8aebSAndroid Build Coastguard Worker 		}
571*bd1f8aebSAndroid Build Coastguard Worker 		logerr("wrote %s %d chars, ret=%d\n",
572*bd1f8aebSAndroid Build Coastguard Worker 			sendaddress, packetlen, i );
573*bd1f8aebSAndroid Build Coastguard Worker 	}
574*bd1f8aebSAndroid Build Coastguard Worker }
575*bd1f8aebSAndroid Build Coastguard Worker 
576*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
577*bd1f8aebSAndroid Build Coastguard Worker /*
578*bd1f8aebSAndroid Build Coastguard Worker  * 			A V E R T I S E
579*bd1f8aebSAndroid Build Coastguard Worker  *
580*bd1f8aebSAndroid Build Coastguard Worker  * Compose and transmit an ICMP ROUTER ADVERTISEMENT packet.
581*bd1f8aebSAndroid Build Coastguard Worker  * The IP packet will be added on by the kernel.
582*bd1f8aebSAndroid Build Coastguard Worker  */
583*bd1f8aebSAndroid Build Coastguard Worker void
advertise(struct sockaddr_in * sin,int lft)584*bd1f8aebSAndroid Build Coastguard Worker advertise(struct sockaddr_in *sin, int lft)
585*bd1f8aebSAndroid Build Coastguard Worker {
586*bd1f8aebSAndroid Build Coastguard Worker 	static u_char outpack[MAXPACKET];
587*bd1f8aebSAndroid Build Coastguard Worker 	struct icmp_ra *rap = (struct icmp_ra *) ALLIGN(outpack);
588*bd1f8aebSAndroid Build Coastguard Worker 	struct icmp_ra_addr *ap;
589*bd1f8aebSAndroid Build Coastguard Worker 	int packetlen, i, cc;
590*bd1f8aebSAndroid Build Coastguard Worker 
591*bd1f8aebSAndroid Build Coastguard Worker 	if (verbose) {
592*bd1f8aebSAndroid Build Coastguard Worker 		logtrace("Sending advertisement to %s\n",
593*bd1f8aebSAndroid Build Coastguard Worker 			 pr_name(sin->sin_addr));
594*bd1f8aebSAndroid Build Coastguard Worker 	}
595*bd1f8aebSAndroid Build Coastguard Worker 
596*bd1f8aebSAndroid Build Coastguard Worker 	for (i = 0; i < num_interfaces; i++) {
597*bd1f8aebSAndroid Build Coastguard Worker 		rap->icmp_type = ICMP_ROUTER_ADVERTISEMENT;
598*bd1f8aebSAndroid Build Coastguard Worker 		rap->icmp_code = 0;
599*bd1f8aebSAndroid Build Coastguard Worker 		rap->icmp_cksum = 0;
600*bd1f8aebSAndroid Build Coastguard Worker 		rap->icmp_num_addrs = 0;
601*bd1f8aebSAndroid Build Coastguard Worker 		rap->icmp_wpa = 2;
602*bd1f8aebSAndroid Build Coastguard Worker 		rap->icmp_lifetime = htons(lft);
603*bd1f8aebSAndroid Build Coastguard Worker 		packetlen = 8;
604*bd1f8aebSAndroid Build Coastguard Worker 
605*bd1f8aebSAndroid Build Coastguard Worker 		/*
606*bd1f8aebSAndroid Build Coastguard Worker 		 * TODO handle multiple logical interfaces per
607*bd1f8aebSAndroid Build Coastguard Worker 		 * physical interface. (increment with rap->icmp_wpa * 4 for
608*bd1f8aebSAndroid Build Coastguard Worker 		 * each address.)
609*bd1f8aebSAndroid Build Coastguard Worker 		 */
610*bd1f8aebSAndroid Build Coastguard Worker 		ap = (struct icmp_ra_addr *)ALLIGN(outpack + ICMP_MINLEN);
611*bd1f8aebSAndroid Build Coastguard Worker 		ap->ira_addr = interfaces[i].localaddr.s_addr;
612*bd1f8aebSAndroid Build Coastguard Worker 		ap->ira_preference = htonl(interfaces[i].preference);
613*bd1f8aebSAndroid Build Coastguard Worker 		packetlen += rap->icmp_wpa * 4;
614*bd1f8aebSAndroid Build Coastguard Worker 		rap->icmp_num_addrs++;
615*bd1f8aebSAndroid Build Coastguard Worker 
616*bd1f8aebSAndroid Build Coastguard Worker 		/* Compute ICMP checksum here */
617*bd1f8aebSAndroid Build Coastguard Worker 		rap->icmp_cksum = in_cksum( (u_short *)rap, packetlen );
618*bd1f8aebSAndroid Build Coastguard Worker 
619*bd1f8aebSAndroid Build Coastguard Worker 		if (isbroadcast(sin))
620*bd1f8aebSAndroid Build Coastguard Worker 			cc = sendbcastif(s, (char *)outpack, packetlen,
621*bd1f8aebSAndroid Build Coastguard Worker 					&interfaces[i]);
622*bd1f8aebSAndroid Build Coastguard Worker 		else if (ismulticast(sin))
623*bd1f8aebSAndroid Build Coastguard Worker 			cc = sendmcastif( s, (char *)outpack, packetlen, sin,
624*bd1f8aebSAndroid Build Coastguard Worker 					&interfaces[i]);
625*bd1f8aebSAndroid Build Coastguard Worker 		else {
626*bd1f8aebSAndroid Build Coastguard Worker 			struct interface *ifp = &interfaces[i];
627*bd1f8aebSAndroid Build Coastguard Worker 			/*
628*bd1f8aebSAndroid Build Coastguard Worker 			 * Verify that the interface matches the destination
629*bd1f8aebSAndroid Build Coastguard Worker 			 * address.
630*bd1f8aebSAndroid Build Coastguard Worker 			 */
631*bd1f8aebSAndroid Build Coastguard Worker 			if ((sin->sin_addr.s_addr & ifp->netmask.s_addr) ==
632*bd1f8aebSAndroid Build Coastguard Worker 			    (ifp->address.s_addr & ifp->netmask.s_addr)) {
633*bd1f8aebSAndroid Build Coastguard Worker 				if (debug) {
634*bd1f8aebSAndroid Build Coastguard Worker 					logdebug("Unicast to %s ",
635*bd1f8aebSAndroid Build Coastguard Worker 						 pr_name(sin->sin_addr));
636*bd1f8aebSAndroid Build Coastguard Worker 					logdebug("on interface %s, %s\n",
637*bd1f8aebSAndroid Build Coastguard Worker 						 ifp->name,
638*bd1f8aebSAndroid Build Coastguard Worker 						 pr_name(ifp->address));
639*bd1f8aebSAndroid Build Coastguard Worker 				}
640*bd1f8aebSAndroid Build Coastguard Worker 				cc = sendto( s, (char *)outpack, packetlen, 0,
641*bd1f8aebSAndroid Build Coastguard Worker 					    (struct sockaddr *)sin,
642*bd1f8aebSAndroid Build Coastguard Worker 					    sizeof(struct sockaddr));
643*bd1f8aebSAndroid Build Coastguard Worker 			} else
644*bd1f8aebSAndroid Build Coastguard Worker 				cc = packetlen;
645*bd1f8aebSAndroid Build Coastguard Worker 		}
646*bd1f8aebSAndroid Build Coastguard Worker 		if( cc < 0 || cc != packetlen )  {
647*bd1f8aebSAndroid Build Coastguard Worker 			if (cc < 0) {
648*bd1f8aebSAndroid Build Coastguard Worker 				logperror("sendto");
649*bd1f8aebSAndroid Build Coastguard Worker 			} else {
650*bd1f8aebSAndroid Build Coastguard Worker 				logerr("wrote %s %d chars, ret=%d\n",
651*bd1f8aebSAndroid Build Coastguard Worker 				       sendaddress, packetlen, cc );
652*bd1f8aebSAndroid Build Coastguard Worker 			}
653*bd1f8aebSAndroid Build Coastguard Worker 		}
654*bd1f8aebSAndroid Build Coastguard Worker 	}
655*bd1f8aebSAndroid Build Coastguard Worker }
656*bd1f8aebSAndroid Build Coastguard Worker #endif
657*bd1f8aebSAndroid Build Coastguard Worker 
658*bd1f8aebSAndroid Build Coastguard Worker /*
659*bd1f8aebSAndroid Build Coastguard Worker  * 			P R _ T Y P E
660*bd1f8aebSAndroid Build Coastguard Worker  *
661*bd1f8aebSAndroid Build Coastguard Worker  * Convert an ICMP "type" field to a printable string.
662*bd1f8aebSAndroid Build Coastguard Worker  */
663*bd1f8aebSAndroid Build Coastguard Worker char *
pr_type(int t)664*bd1f8aebSAndroid Build Coastguard Worker pr_type(int t)
665*bd1f8aebSAndroid Build Coastguard Worker {
666*bd1f8aebSAndroid Build Coastguard Worker 	static char *ttab[] = {
667*bd1f8aebSAndroid Build Coastguard Worker 		"Echo Reply",
668*bd1f8aebSAndroid Build Coastguard Worker 		"ICMP 1",
669*bd1f8aebSAndroid Build Coastguard Worker 		"ICMP 2",
670*bd1f8aebSAndroid Build Coastguard Worker 		"Dest Unreachable",
671*bd1f8aebSAndroid Build Coastguard Worker 		"Source Quench",
672*bd1f8aebSAndroid Build Coastguard Worker 		"Redirect",
673*bd1f8aebSAndroid Build Coastguard Worker 		"ICMP 6",
674*bd1f8aebSAndroid Build Coastguard Worker 		"ICMP 7",
675*bd1f8aebSAndroid Build Coastguard Worker 		"Echo",
676*bd1f8aebSAndroid Build Coastguard Worker 		"Router Advertise",
677*bd1f8aebSAndroid Build Coastguard Worker 		"Router Solicitation",
678*bd1f8aebSAndroid Build Coastguard Worker 		"Time Exceeded",
679*bd1f8aebSAndroid Build Coastguard Worker 		"Parameter Problem",
680*bd1f8aebSAndroid Build Coastguard Worker 		"Timestamp",
681*bd1f8aebSAndroid Build Coastguard Worker 		"Timestamp Reply",
682*bd1f8aebSAndroid Build Coastguard Worker 		"Info Request",
683*bd1f8aebSAndroid Build Coastguard Worker 		"Info Reply",
684*bd1f8aebSAndroid Build Coastguard Worker 		"Netmask Request",
685*bd1f8aebSAndroid Build Coastguard Worker 		"Netmask Reply"
686*bd1f8aebSAndroid Build Coastguard Worker 	};
687*bd1f8aebSAndroid Build Coastguard Worker 
688*bd1f8aebSAndroid Build Coastguard Worker 	if ( t < 0 || t > 16 )
689*bd1f8aebSAndroid Build Coastguard Worker 		return("OUT-OF-RANGE");
690*bd1f8aebSAndroid Build Coastguard Worker 
691*bd1f8aebSAndroid Build Coastguard Worker 	return(ttab[t]);
692*bd1f8aebSAndroid Build Coastguard Worker }
693*bd1f8aebSAndroid Build Coastguard Worker 
694*bd1f8aebSAndroid Build Coastguard Worker /*
695*bd1f8aebSAndroid Build Coastguard Worker  *			P R _ N A M E
696*bd1f8aebSAndroid Build Coastguard Worker  *
697*bd1f8aebSAndroid Build Coastguard Worker  * Return a string name for the given IP address.
698*bd1f8aebSAndroid Build Coastguard Worker  */
pr_name(struct in_addr addr)699*bd1f8aebSAndroid Build Coastguard Worker char *pr_name(struct in_addr addr)
700*bd1f8aebSAndroid Build Coastguard Worker {
701*bd1f8aebSAndroid Build Coastguard Worker 	struct hostent *phe;
702*bd1f8aebSAndroid Build Coastguard Worker 	static char buf[80];
703*bd1f8aebSAndroid Build Coastguard Worker 
704*bd1f8aebSAndroid Build Coastguard Worker 	phe = gethostbyaddr((char *)&addr.s_addr, 4, AF_INET);
705*bd1f8aebSAndroid Build Coastguard Worker 	if (phe == NULL)
706*bd1f8aebSAndroid Build Coastguard Worker 		return( inet_ntoa(addr));
707*bd1f8aebSAndroid Build Coastguard Worker 	snprintf(buf, sizeof(buf), "%s (%s)", phe->h_name, inet_ntoa(addr));
708*bd1f8aebSAndroid Build Coastguard Worker 	return(buf);
709*bd1f8aebSAndroid Build Coastguard Worker }
710*bd1f8aebSAndroid Build Coastguard Worker 
711*bd1f8aebSAndroid Build Coastguard Worker /*
712*bd1f8aebSAndroid Build Coastguard Worker  *			P R _ P A C K
713*bd1f8aebSAndroid Build Coastguard Worker  *
714*bd1f8aebSAndroid Build Coastguard Worker  * Print out the packet, if it came from us.  This logic is necessary
715*bd1f8aebSAndroid Build Coastguard Worker  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
716*bd1f8aebSAndroid Build Coastguard Worker  * which arrive ('tis only fair).  This permits multiple copies of this
717*bd1f8aebSAndroid Build Coastguard Worker  * program to be run without having intermingled output (or statistics!).
718*bd1f8aebSAndroid Build Coastguard Worker  */
719*bd1f8aebSAndroid Build Coastguard Worker void
pr_pack(char * buf,int cc,struct sockaddr_in * from)720*bd1f8aebSAndroid Build Coastguard Worker pr_pack(char *buf, int cc, struct sockaddr_in *from)
721*bd1f8aebSAndroid Build Coastguard Worker {
722*bd1f8aebSAndroid Build Coastguard Worker 	struct iphdr *ip;
723*bd1f8aebSAndroid Build Coastguard Worker 	struct icmphdr *icp;
724*bd1f8aebSAndroid Build Coastguard Worker 	int i;
725*bd1f8aebSAndroid Build Coastguard Worker 	int hlen;
726*bd1f8aebSAndroid Build Coastguard Worker 
727*bd1f8aebSAndroid Build Coastguard Worker 	ip = (struct iphdr *) ALLIGN(buf);
728*bd1f8aebSAndroid Build Coastguard Worker 	hlen = ip->ihl << 2;
729*bd1f8aebSAndroid Build Coastguard Worker 	if (cc < hlen + 8) {
730*bd1f8aebSAndroid Build Coastguard Worker 		if (verbose)
731*bd1f8aebSAndroid Build Coastguard Worker 			logtrace("packet too short (%d bytes) from %s\n", cc,
732*bd1f8aebSAndroid Build Coastguard Worker 				 pr_name(from->sin_addr));
733*bd1f8aebSAndroid Build Coastguard Worker 		return;
734*bd1f8aebSAndroid Build Coastguard Worker 	}
735*bd1f8aebSAndroid Build Coastguard Worker 	cc -= hlen;
736*bd1f8aebSAndroid Build Coastguard Worker 	icp = (struct icmphdr *)ALLIGN(buf + hlen);
737*bd1f8aebSAndroid Build Coastguard Worker 
738*bd1f8aebSAndroid Build Coastguard Worker 	switch (icp->type) {
739*bd1f8aebSAndroid Build Coastguard Worker 	case ICMP_ROUTER_ADVERTISEMENT:
740*bd1f8aebSAndroid Build Coastguard Worker 	{
741*bd1f8aebSAndroid Build Coastguard Worker 		struct icmp_ra *rap = (struct icmp_ra *)ALLIGN(icp);
742*bd1f8aebSAndroid Build Coastguard Worker 		struct icmp_ra_addr *ap;
743*bd1f8aebSAndroid Build Coastguard Worker 
744*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
745*bd1f8aebSAndroid Build Coastguard Worker 		if (responder)
746*bd1f8aebSAndroid Build Coastguard Worker 			break;
747*bd1f8aebSAndroid Build Coastguard Worker #endif
748*bd1f8aebSAndroid Build Coastguard Worker 
749*bd1f8aebSAndroid Build Coastguard Worker 		/* TBD verify that the link is multicast or broadcast */
750*bd1f8aebSAndroid Build Coastguard Worker 		/* XXX Find out the link it came in over? */
751*bd1f8aebSAndroid Build Coastguard Worker 		if (in_cksum((u_short *)ALLIGN(buf+hlen), cc)) {
752*bd1f8aebSAndroid Build Coastguard Worker 			if (verbose)
753*bd1f8aebSAndroid Build Coastguard Worker 				logtrace("ICMP %s from %s: Bad checksum\n",
754*bd1f8aebSAndroid Build Coastguard Worker 					 pr_type((int)rap->icmp_type),
755*bd1f8aebSAndroid Build Coastguard Worker 					 pr_name(from->sin_addr));
756*bd1f8aebSAndroid Build Coastguard Worker 			return;
757*bd1f8aebSAndroid Build Coastguard Worker 		}
758*bd1f8aebSAndroid Build Coastguard Worker 		if (rap->icmp_code != 0) {
759*bd1f8aebSAndroid Build Coastguard Worker 			if (verbose)
760*bd1f8aebSAndroid Build Coastguard Worker 				logtrace("ICMP %s from %s: Code = %d\n",
761*bd1f8aebSAndroid Build Coastguard Worker 					 pr_type((int)rap->icmp_type),
762*bd1f8aebSAndroid Build Coastguard Worker 					 pr_name(from->sin_addr),
763*bd1f8aebSAndroid Build Coastguard Worker 					 rap->icmp_code);
764*bd1f8aebSAndroid Build Coastguard Worker 			return;
765*bd1f8aebSAndroid Build Coastguard Worker 		}
766*bd1f8aebSAndroid Build Coastguard Worker 		if (rap->icmp_num_addrs < 1) {
767*bd1f8aebSAndroid Build Coastguard Worker 			if (verbose)
768*bd1f8aebSAndroid Build Coastguard Worker 				logtrace("ICMP %s from %s: No addresses\n",
769*bd1f8aebSAndroid Build Coastguard Worker 					 pr_type((int)rap->icmp_type),
770*bd1f8aebSAndroid Build Coastguard Worker 					 pr_name(from->sin_addr));
771*bd1f8aebSAndroid Build Coastguard Worker 			return;
772*bd1f8aebSAndroid Build Coastguard Worker 		}
773*bd1f8aebSAndroid Build Coastguard Worker 		if (rap->icmp_wpa < 2) {
774*bd1f8aebSAndroid Build Coastguard Worker 			if (verbose)
775*bd1f8aebSAndroid Build Coastguard Worker 				logtrace("ICMP %s from %s: Words/addr = %d\n",
776*bd1f8aebSAndroid Build Coastguard Worker 					 pr_type((int)rap->icmp_type),
777*bd1f8aebSAndroid Build Coastguard Worker 					 pr_name(from->sin_addr),
778*bd1f8aebSAndroid Build Coastguard Worker 					 rap->icmp_wpa);
779*bd1f8aebSAndroid Build Coastguard Worker 			return;
780*bd1f8aebSAndroid Build Coastguard Worker 		}
781*bd1f8aebSAndroid Build Coastguard Worker 		if ((unsigned)cc <
782*bd1f8aebSAndroid Build Coastguard Worker 		    8 + rap->icmp_num_addrs * rap->icmp_wpa * 4) {
783*bd1f8aebSAndroid Build Coastguard Worker 			if (verbose)
784*bd1f8aebSAndroid Build Coastguard Worker 				logtrace("ICMP %s from %s: Too short %d, %d\n",
785*bd1f8aebSAndroid Build Coastguard Worker 					      pr_type((int)rap->icmp_type),
786*bd1f8aebSAndroid Build Coastguard Worker 					      pr_name(from->sin_addr),
787*bd1f8aebSAndroid Build Coastguard Worker 					      cc,
788*bd1f8aebSAndroid Build Coastguard Worker 					      8 + rap->icmp_num_addrs * rap->icmp_wpa * 4);
789*bd1f8aebSAndroid Build Coastguard Worker 			return;
790*bd1f8aebSAndroid Build Coastguard Worker 		}
791*bd1f8aebSAndroid Build Coastguard Worker 
792*bd1f8aebSAndroid Build Coastguard Worker 		if (verbose)
793*bd1f8aebSAndroid Build Coastguard Worker 			logtrace("ICMP %s from %s, lifetime %d\n",
794*bd1f8aebSAndroid Build Coastguard Worker 				      pr_type((int)rap->icmp_type),
795*bd1f8aebSAndroid Build Coastguard Worker 				      pr_name(from->sin_addr),
796*bd1f8aebSAndroid Build Coastguard Worker 				      ntohs(rap->icmp_lifetime));
797*bd1f8aebSAndroid Build Coastguard Worker 
798*bd1f8aebSAndroid Build Coastguard Worker 		/* Check that at least one router address is a neighboor
799*bd1f8aebSAndroid Build Coastguard Worker 		 * on the arriving link.
800*bd1f8aebSAndroid Build Coastguard Worker 		 */
801*bd1f8aebSAndroid Build Coastguard Worker 		for (i = 0; (unsigned)i < rap->icmp_num_addrs; i++) {
802*bd1f8aebSAndroid Build Coastguard Worker 			struct in_addr ina;
803*bd1f8aebSAndroid Build Coastguard Worker 			ap = (struct icmp_ra_addr *)
804*bd1f8aebSAndroid Build Coastguard Worker 				ALLIGN(buf + hlen + 8 +
805*bd1f8aebSAndroid Build Coastguard Worker 				       i * rap->icmp_wpa * 4);
806*bd1f8aebSAndroid Build Coastguard Worker 			ina.s_addr = ap->ira_addr;
807*bd1f8aebSAndroid Build Coastguard Worker 			if (verbose)
808*bd1f8aebSAndroid Build Coastguard Worker 				logtrace("\taddress %s, preference 0x%x\n",
809*bd1f8aebSAndroid Build Coastguard Worker 					      pr_name(ina),
810*bd1f8aebSAndroid Build Coastguard Worker 					      (unsigned int)ntohl(ap->ira_preference));
811*bd1f8aebSAndroid Build Coastguard Worker 			if (is_directly_connected(ina))
812*bd1f8aebSAndroid Build Coastguard Worker 				record_router(ina,
813*bd1f8aebSAndroid Build Coastguard Worker 					      ntohl(ap->ira_preference),
814*bd1f8aebSAndroid Build Coastguard Worker 					      ntohs(rap->icmp_lifetime));
815*bd1f8aebSAndroid Build Coastguard Worker 		}
816*bd1f8aebSAndroid Build Coastguard Worker 		nreceived++;
817*bd1f8aebSAndroid Build Coastguard Worker 		if (!forever) {
818*bd1f8aebSAndroid Build Coastguard Worker 			do_fork();
819*bd1f8aebSAndroid Build Coastguard Worker 			forever = 1;
820*bd1f8aebSAndroid Build Coastguard Worker /*
821*bd1f8aebSAndroid Build Coastguard Worker  * The next line was added so that the alarm is set for the new procces
822*bd1f8aebSAndroid Build Coastguard Worker  * Fraser Gardiner Sun Microsystems Australia
823*bd1f8aebSAndroid Build Coastguard Worker  */
824*bd1f8aebSAndroid Build Coastguard Worker 			(void) alarm(TIMER_INTERVAL);
825*bd1f8aebSAndroid Build Coastguard Worker 		}
826*bd1f8aebSAndroid Build Coastguard Worker 		break;
827*bd1f8aebSAndroid Build Coastguard Worker 	}
828*bd1f8aebSAndroid Build Coastguard Worker 
829*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
830*bd1f8aebSAndroid Build Coastguard Worker 	case ICMP_ROUTER_SOLICITATION:
831*bd1f8aebSAndroid Build Coastguard Worker 	{
832*bd1f8aebSAndroid Build Coastguard Worker 		struct sockaddr_in sin;
833*bd1f8aebSAndroid Build Coastguard Worker 
834*bd1f8aebSAndroid Build Coastguard Worker 		if (!responder)
835*bd1f8aebSAndroid Build Coastguard Worker 			break;
836*bd1f8aebSAndroid Build Coastguard Worker 
837*bd1f8aebSAndroid Build Coastguard Worker 		/* TBD verify that the link is multicast or broadcast */
838*bd1f8aebSAndroid Build Coastguard Worker 		/* XXX Find out the link it came in over? */
839*bd1f8aebSAndroid Build Coastguard Worker 
840*bd1f8aebSAndroid Build Coastguard Worker 		if (in_cksum((u_short *)ALLIGN(buf+hlen), cc)) {
841*bd1f8aebSAndroid Build Coastguard Worker 			if (verbose)
842*bd1f8aebSAndroid Build Coastguard Worker 				logtrace("ICMP %s from %s: Bad checksum\n",
843*bd1f8aebSAndroid Build Coastguard Worker 					      pr_type((int)icp->type),
844*bd1f8aebSAndroid Build Coastguard Worker 					      pr_name(from->sin_addr));
845*bd1f8aebSAndroid Build Coastguard Worker 			return;
846*bd1f8aebSAndroid Build Coastguard Worker 		}
847*bd1f8aebSAndroid Build Coastguard Worker 		if (icp->code != 0) {
848*bd1f8aebSAndroid Build Coastguard Worker 			if (verbose)
849*bd1f8aebSAndroid Build Coastguard Worker 				logtrace("ICMP %s from %s: Code = %d\n",
850*bd1f8aebSAndroid Build Coastguard Worker 					      pr_type((int)icp->type),
851*bd1f8aebSAndroid Build Coastguard Worker 					      pr_name(from->sin_addr),
852*bd1f8aebSAndroid Build Coastguard Worker 					      icp->code);
853*bd1f8aebSAndroid Build Coastguard Worker 			return;
854*bd1f8aebSAndroid Build Coastguard Worker 		}
855*bd1f8aebSAndroid Build Coastguard Worker 
856*bd1f8aebSAndroid Build Coastguard Worker 		if (cc < ICMP_MINLEN) {
857*bd1f8aebSAndroid Build Coastguard Worker 			if (verbose)
858*bd1f8aebSAndroid Build Coastguard Worker 				logtrace("ICMP %s from %s: Too short %d, %d\n",
859*bd1f8aebSAndroid Build Coastguard Worker 					      pr_type((int)icp->type),
860*bd1f8aebSAndroid Build Coastguard Worker 					      pr_name(from->sin_addr),
861*bd1f8aebSAndroid Build Coastguard Worker 					      cc,
862*bd1f8aebSAndroid Build Coastguard Worker 					      ICMP_MINLEN);
863*bd1f8aebSAndroid Build Coastguard Worker 			return;
864*bd1f8aebSAndroid Build Coastguard Worker 		}
865*bd1f8aebSAndroid Build Coastguard Worker 
866*bd1f8aebSAndroid Build Coastguard Worker 		if (verbose)
867*bd1f8aebSAndroid Build Coastguard Worker 			logtrace("ICMP %s from %s\n",
868*bd1f8aebSAndroid Build Coastguard Worker 				      pr_type((int)icp->type),
869*bd1f8aebSAndroid Build Coastguard Worker 				      pr_name(from->sin_addr));
870*bd1f8aebSAndroid Build Coastguard Worker 
871*bd1f8aebSAndroid Build Coastguard Worker 		/* Check that ip_src is either a neighboor
872*bd1f8aebSAndroid Build Coastguard Worker 		 * on the arriving link or 0.
873*bd1f8aebSAndroid Build Coastguard Worker 		 */
874*bd1f8aebSAndroid Build Coastguard Worker 		sin.sin_family = AF_INET;
875*bd1f8aebSAndroid Build Coastguard Worker 		if (ip->saddr == 0) {
876*bd1f8aebSAndroid Build Coastguard Worker 			/* If it was sent to the broadcast address we respond
877*bd1f8aebSAndroid Build Coastguard Worker 			 * to the broadcast address.
878*bd1f8aebSAndroid Build Coastguard Worker 			 */
879*bd1f8aebSAndroid Build Coastguard Worker 			if (IN_CLASSD(ntohl(ip->daddr)))
880*bd1f8aebSAndroid Build Coastguard Worker 				sin.sin_addr.s_addr = htonl(0xe0000001);
881*bd1f8aebSAndroid Build Coastguard Worker 			else
882*bd1f8aebSAndroid Build Coastguard Worker 				sin.sin_addr.s_addr = INADDR_BROADCAST;
883*bd1f8aebSAndroid Build Coastguard Worker 			/* Restart the timer when we broadcast */
884*bd1f8aebSAndroid Build Coastguard Worker 			left_until_advertise = min_adv_int +
885*bd1f8aebSAndroid Build Coastguard Worker 				((max_adv_int - min_adv_int)
886*bd1f8aebSAndroid Build Coastguard Worker 				 * (random() % 1000)/1000);
887*bd1f8aebSAndroid Build Coastguard Worker 		} else {
888*bd1f8aebSAndroid Build Coastguard Worker 			sin.sin_addr.s_addr = ip->saddr;
889*bd1f8aebSAndroid Build Coastguard Worker 			if (!is_directly_connected(sin.sin_addr)) {
890*bd1f8aebSAndroid Build Coastguard Worker 				if (verbose)
891*bd1f8aebSAndroid Build Coastguard Worker 					logtrace("ICMP %s from %s: source not directly connected\n",
892*bd1f8aebSAndroid Build Coastguard Worker 						      pr_type((int)icp->type),
893*bd1f8aebSAndroid Build Coastguard Worker 						      pr_name(from->sin_addr));
894*bd1f8aebSAndroid Build Coastguard Worker 				break;
895*bd1f8aebSAndroid Build Coastguard Worker 			}
896*bd1f8aebSAndroid Build Coastguard Worker 		}
897*bd1f8aebSAndroid Build Coastguard Worker 		nreceived++;
898*bd1f8aebSAndroid Build Coastguard Worker 		ntransmitted++;
899*bd1f8aebSAndroid Build Coastguard Worker 		advertise(&sin, lifetime);
900*bd1f8aebSAndroid Build Coastguard Worker 		break;
901*bd1f8aebSAndroid Build Coastguard Worker 	}
902*bd1f8aebSAndroid Build Coastguard Worker #endif
903*bd1f8aebSAndroid Build Coastguard Worker 	}
904*bd1f8aebSAndroid Build Coastguard Worker }
905*bd1f8aebSAndroid Build Coastguard Worker 
906*bd1f8aebSAndroid Build Coastguard Worker 
907*bd1f8aebSAndroid Build Coastguard Worker /*
908*bd1f8aebSAndroid Build Coastguard Worker  *			I N _ C K S U M
909*bd1f8aebSAndroid Build Coastguard Worker  *
910*bd1f8aebSAndroid Build Coastguard Worker  * Checksum routine for Internet Protocol family headers (C Version)
911*bd1f8aebSAndroid Build Coastguard Worker  *
912*bd1f8aebSAndroid Build Coastguard Worker  */
913*bd1f8aebSAndroid Build Coastguard Worker #if BYTE_ORDER == LITTLE_ENDIAN
914*bd1f8aebSAndroid Build Coastguard Worker # define ODDBYTE(v)	(v)
915*bd1f8aebSAndroid Build Coastguard Worker #elif BYTE_ORDER == BIG_ENDIAN
916*bd1f8aebSAndroid Build Coastguard Worker # define ODDBYTE(v)	((u_short)(v) << 8)
917*bd1f8aebSAndroid Build Coastguard Worker #else
918*bd1f8aebSAndroid Build Coastguard Worker # define ODDBYTE(v)	htons((u_short)(v) << 8)
919*bd1f8aebSAndroid Build Coastguard Worker #endif
920*bd1f8aebSAndroid Build Coastguard Worker 
in_cksum(u_short * addr,int len)921*bd1f8aebSAndroid Build Coastguard Worker u_short in_cksum(u_short *addr, int len)
922*bd1f8aebSAndroid Build Coastguard Worker {
923*bd1f8aebSAndroid Build Coastguard Worker 	register int nleft = len;
924*bd1f8aebSAndroid Build Coastguard Worker 	register u_short *w = addr;
925*bd1f8aebSAndroid Build Coastguard Worker 	register u_short answer;
926*bd1f8aebSAndroid Build Coastguard Worker 	register int sum = 0;
927*bd1f8aebSAndroid Build Coastguard Worker 
928*bd1f8aebSAndroid Build Coastguard Worker 	/*
929*bd1f8aebSAndroid Build Coastguard Worker 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
930*bd1f8aebSAndroid Build Coastguard Worker 	 *  we add sequential 16 bit words to it, and at the end, fold
931*bd1f8aebSAndroid Build Coastguard Worker 	 *  back all the carry bits from the top 16 bits into the lower
932*bd1f8aebSAndroid Build Coastguard Worker 	 *  16 bits.
933*bd1f8aebSAndroid Build Coastguard Worker 	 */
934*bd1f8aebSAndroid Build Coastguard Worker 	while( nleft > 1 )  {
935*bd1f8aebSAndroid Build Coastguard Worker 		sum += *w++;
936*bd1f8aebSAndroid Build Coastguard Worker 		nleft -= 2;
937*bd1f8aebSAndroid Build Coastguard Worker 	}
938*bd1f8aebSAndroid Build Coastguard Worker 
939*bd1f8aebSAndroid Build Coastguard Worker 	/* mop up an odd byte, if necessary */
940*bd1f8aebSAndroid Build Coastguard Worker 	if( nleft == 1 )
941*bd1f8aebSAndroid Build Coastguard Worker 		sum += ODDBYTE(*(u_char *)w);	/* le16toh() may be unavailable on old systems */
942*bd1f8aebSAndroid Build Coastguard Worker 
943*bd1f8aebSAndroid Build Coastguard Worker 	/*
944*bd1f8aebSAndroid Build Coastguard Worker 	 * add back carry outs from top 16 bits to low 16 bits
945*bd1f8aebSAndroid Build Coastguard Worker 	 */
946*bd1f8aebSAndroid Build Coastguard Worker 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
947*bd1f8aebSAndroid Build Coastguard Worker 	sum += (sum >> 16);			/* add carry */
948*bd1f8aebSAndroid Build Coastguard Worker 	answer = ~sum;				/* truncate to 16 bits */
949*bd1f8aebSAndroid Build Coastguard Worker 	return (answer);
950*bd1f8aebSAndroid Build Coastguard Worker }
951*bd1f8aebSAndroid Build Coastguard Worker 
952*bd1f8aebSAndroid Build Coastguard Worker /*
953*bd1f8aebSAndroid Build Coastguard Worker  *			F I N I S H
954*bd1f8aebSAndroid Build Coastguard Worker  *
955*bd1f8aebSAndroid Build Coastguard Worker  * Print out statistics, and give up.
956*bd1f8aebSAndroid Build Coastguard Worker  * Heavily buffered STDIO is used here, so that all the statistics
957*bd1f8aebSAndroid Build Coastguard Worker  * will be written with 1 sys-write call.  This is nice when more
958*bd1f8aebSAndroid Build Coastguard Worker  * than one copy of the program is running on a terminal;  it prevents
959*bd1f8aebSAndroid Build Coastguard Worker  * the statistics output from becomming intermingled.
960*bd1f8aebSAndroid Build Coastguard Worker  */
961*bd1f8aebSAndroid Build Coastguard Worker void
finish()962*bd1f8aebSAndroid Build Coastguard Worker finish()
963*bd1f8aebSAndroid Build Coastguard Worker {
964*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
965*bd1f8aebSAndroid Build Coastguard Worker 	if (responder) {
966*bd1f8aebSAndroid Build Coastguard Worker 		/* Send out a packet with a preference so that all
967*bd1f8aebSAndroid Build Coastguard Worker 		 * hosts will know that we are dead.
968*bd1f8aebSAndroid Build Coastguard Worker 		 *
969*bd1f8aebSAndroid Build Coastguard Worker 		 * Wrong comment, wrong code.
970*bd1f8aebSAndroid Build Coastguard Worker 		 *	ttl must be set to 0 instead. --ANK
971*bd1f8aebSAndroid Build Coastguard Worker 		 */
972*bd1f8aebSAndroid Build Coastguard Worker 		logerr("terminated\n");
973*bd1f8aebSAndroid Build Coastguard Worker 		ntransmitted++;
974*bd1f8aebSAndroid Build Coastguard Worker 		advertise(&whereto, 0);
975*bd1f8aebSAndroid Build Coastguard Worker 	}
976*bd1f8aebSAndroid Build Coastguard Worker #endif
977*bd1f8aebSAndroid Build Coastguard Worker 	logtrace("\n----%s rdisc Statistics----\n", sendaddress );
978*bd1f8aebSAndroid Build Coastguard Worker 	logtrace("%d packets transmitted, ", ntransmitted );
979*bd1f8aebSAndroid Build Coastguard Worker 	logtrace("%d packets received, ", nreceived );
980*bd1f8aebSAndroid Build Coastguard Worker 	logtrace("\n");
981*bd1f8aebSAndroid Build Coastguard Worker 	(void) fflush(stdout);
982*bd1f8aebSAndroid Build Coastguard Worker 	exit(0);
983*bd1f8aebSAndroid Build Coastguard Worker }
984*bd1f8aebSAndroid Build Coastguard Worker 
985*bd1f8aebSAndroid Build Coastguard Worker void
graceful_finish()986*bd1f8aebSAndroid Build Coastguard Worker graceful_finish()
987*bd1f8aebSAndroid Build Coastguard Worker {
988*bd1f8aebSAndroid Build Coastguard Worker 	discard_table();
989*bd1f8aebSAndroid Build Coastguard Worker 	finish();
990*bd1f8aebSAndroid Build Coastguard Worker 	exit(0);
991*bd1f8aebSAndroid Build Coastguard Worker }
992*bd1f8aebSAndroid Build Coastguard Worker 
993*bd1f8aebSAndroid Build Coastguard Worker 
994*bd1f8aebSAndroid Build Coastguard Worker /* From libc/rpc/pmap_rmt.c */
995*bd1f8aebSAndroid Build Coastguard Worker 
996*bd1f8aebSAndroid Build Coastguard Worker int
sendbcast(int s,char * packet,int packetlen)997*bd1f8aebSAndroid Build Coastguard Worker sendbcast(int s, char *packet, int packetlen)
998*bd1f8aebSAndroid Build Coastguard Worker {
999*bd1f8aebSAndroid Build Coastguard Worker 	int i, cc;
1000*bd1f8aebSAndroid Build Coastguard Worker 
1001*bd1f8aebSAndroid Build Coastguard Worker 	for (i = 0; i < num_interfaces; i++) {
1002*bd1f8aebSAndroid Build Coastguard Worker 		if ((interfaces[i].flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
1003*bd1f8aebSAndroid Build Coastguard Worker 			continue;
1004*bd1f8aebSAndroid Build Coastguard Worker 		cc = sendbcastif(s, packet, packetlen, &interfaces[i]);
1005*bd1f8aebSAndroid Build Coastguard Worker 		if (cc!= packetlen) {
1006*bd1f8aebSAndroid Build Coastguard Worker 			return (cc);
1007*bd1f8aebSAndroid Build Coastguard Worker 		}
1008*bd1f8aebSAndroid Build Coastguard Worker 	}
1009*bd1f8aebSAndroid Build Coastguard Worker 	return (packetlen);
1010*bd1f8aebSAndroid Build Coastguard Worker }
1011*bd1f8aebSAndroid Build Coastguard Worker 
1012*bd1f8aebSAndroid Build Coastguard Worker int
sendbcastif(int s,char * packet,int packetlen,struct interface * ifp)1013*bd1f8aebSAndroid Build Coastguard Worker sendbcastif(int s, char *packet, int packetlen, struct interface *ifp)
1014*bd1f8aebSAndroid Build Coastguard Worker {
1015*bd1f8aebSAndroid Build Coastguard Worker 	int on;
1016*bd1f8aebSAndroid Build Coastguard Worker 	int cc;
1017*bd1f8aebSAndroid Build Coastguard Worker 	struct sockaddr_in baddr;
1018*bd1f8aebSAndroid Build Coastguard Worker 
1019*bd1f8aebSAndroid Build Coastguard Worker 	baddr.sin_family = AF_INET;
1020*bd1f8aebSAndroid Build Coastguard Worker 	baddr.sin_addr = ifp->bcastaddr;
1021*bd1f8aebSAndroid Build Coastguard Worker 	if (debug)
1022*bd1f8aebSAndroid Build Coastguard Worker 		logdebug("Broadcast to %s\n",
1023*bd1f8aebSAndroid Build Coastguard Worker 			 pr_name(baddr.sin_addr));
1024*bd1f8aebSAndroid Build Coastguard Worker 	on = 1;
1025*bd1f8aebSAndroid Build Coastguard Worker 	setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
1026*bd1f8aebSAndroid Build Coastguard Worker 	cc = sendto(s, packet, packetlen, 0,
1027*bd1f8aebSAndroid Build Coastguard Worker 		    (struct sockaddr *)&baddr, sizeof (struct sockaddr));
1028*bd1f8aebSAndroid Build Coastguard Worker 	if (cc!= packetlen) {
1029*bd1f8aebSAndroid Build Coastguard Worker 		logperror("sendbcast: sendto");
1030*bd1f8aebSAndroid Build Coastguard Worker 		logerr("Cannot send broadcast packet to %s\n",
1031*bd1f8aebSAndroid Build Coastguard Worker 		       pr_name(baddr.sin_addr));
1032*bd1f8aebSAndroid Build Coastguard Worker 	}
1033*bd1f8aebSAndroid Build Coastguard Worker 	on = 0;
1034*bd1f8aebSAndroid Build Coastguard Worker 	setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
1035*bd1f8aebSAndroid Build Coastguard Worker 	return (cc);
1036*bd1f8aebSAndroid Build Coastguard Worker }
1037*bd1f8aebSAndroid Build Coastguard Worker 
1038*bd1f8aebSAndroid Build Coastguard Worker int
sendmcast(int s,char * packet,int packetlen,struct sockaddr_in * sin)1039*bd1f8aebSAndroid Build Coastguard Worker sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *sin)
1040*bd1f8aebSAndroid Build Coastguard Worker {
1041*bd1f8aebSAndroid Build Coastguard Worker 	int i, cc;
1042*bd1f8aebSAndroid Build Coastguard Worker 
1043*bd1f8aebSAndroid Build Coastguard Worker 	for (i = 0; i < num_interfaces; i++) {
1044*bd1f8aebSAndroid Build Coastguard Worker 		if ((interfaces[i].flags & (IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST)) == 0)
1045*bd1f8aebSAndroid Build Coastguard Worker 			continue;
1046*bd1f8aebSAndroid Build Coastguard Worker 		cc = sendmcastif(s, packet, packetlen, sin, &interfaces[i]);
1047*bd1f8aebSAndroid Build Coastguard Worker 		if (cc!= packetlen) {
1048*bd1f8aebSAndroid Build Coastguard Worker 			return (cc);
1049*bd1f8aebSAndroid Build Coastguard Worker 		}
1050*bd1f8aebSAndroid Build Coastguard Worker 	}
1051*bd1f8aebSAndroid Build Coastguard Worker 	return (packetlen);
1052*bd1f8aebSAndroid Build Coastguard Worker }
1053*bd1f8aebSAndroid Build Coastguard Worker 
1054*bd1f8aebSAndroid Build Coastguard Worker int
sendmcastif(int s,char * packet,int packetlen,struct sockaddr_in * sin,struct interface * ifp)1055*bd1f8aebSAndroid Build Coastguard Worker sendmcastif(int s, char *packet, int packetlen,	struct sockaddr_in *sin,
1056*bd1f8aebSAndroid Build Coastguard Worker 	    struct interface *ifp)
1057*bd1f8aebSAndroid Build Coastguard Worker {
1058*bd1f8aebSAndroid Build Coastguard Worker 	int cc;
1059*bd1f8aebSAndroid Build Coastguard Worker 	struct ip_mreqn mreq;
1060*bd1f8aebSAndroid Build Coastguard Worker 
1061*bd1f8aebSAndroid Build Coastguard Worker 	memset(&mreq, 0, sizeof(mreq));
1062*bd1f8aebSAndroid Build Coastguard Worker 	mreq.imr_ifindex = ifp->ifindex;
1063*bd1f8aebSAndroid Build Coastguard Worker 	mreq.imr_address = ifp->localaddr;
1064*bd1f8aebSAndroid Build Coastguard Worker 	if (debug)
1065*bd1f8aebSAndroid Build Coastguard Worker 		logdebug("Multicast to interface %s, %s\n",
1066*bd1f8aebSAndroid Build Coastguard Worker 			 ifp->name,
1067*bd1f8aebSAndroid Build Coastguard Worker 			 pr_name(mreq.imr_address));
1068*bd1f8aebSAndroid Build Coastguard Worker 	if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
1069*bd1f8aebSAndroid Build Coastguard Worker 		       (char *)&mreq,
1070*bd1f8aebSAndroid Build Coastguard Worker 		       sizeof(mreq)) < 0) {
1071*bd1f8aebSAndroid Build Coastguard Worker 		logperror("setsockopt (IP_MULTICAST_IF)");
1072*bd1f8aebSAndroid Build Coastguard Worker 		logerr("Cannot send multicast packet over interface %s, %s\n",
1073*bd1f8aebSAndroid Build Coastguard Worker 		       ifp->name,
1074*bd1f8aebSAndroid Build Coastguard Worker 		       pr_name(mreq.imr_address));
1075*bd1f8aebSAndroid Build Coastguard Worker 		return (-1);
1076*bd1f8aebSAndroid Build Coastguard Worker 	}
1077*bd1f8aebSAndroid Build Coastguard Worker 	cc = sendto(s, packet, packetlen, 0,
1078*bd1f8aebSAndroid Build Coastguard Worker 		    (struct sockaddr *)sin, sizeof (struct sockaddr));
1079*bd1f8aebSAndroid Build Coastguard Worker 	if (cc!= packetlen) {
1080*bd1f8aebSAndroid Build Coastguard Worker 		logperror("sendmcast: sendto");
1081*bd1f8aebSAndroid Build Coastguard Worker 		logerr("Cannot send multicast packet over interface %s, %s\n",
1082*bd1f8aebSAndroid Build Coastguard Worker 		       ifp->name, pr_name(mreq.imr_address));
1083*bd1f8aebSAndroid Build Coastguard Worker 	}
1084*bd1f8aebSAndroid Build Coastguard Worker 	return (cc);
1085*bd1f8aebSAndroid Build Coastguard Worker }
1086*bd1f8aebSAndroid Build Coastguard Worker 
1087*bd1f8aebSAndroid Build Coastguard Worker void
init()1088*bd1f8aebSAndroid Build Coastguard Worker init()
1089*bd1f8aebSAndroid Build Coastguard Worker {
1090*bd1f8aebSAndroid Build Coastguard Worker 	initifs();
1091*bd1f8aebSAndroid Build Coastguard Worker #ifdef RDISC_SERVER
1092*bd1f8aebSAndroid Build Coastguard Worker 	{
1093*bd1f8aebSAndroid Build Coastguard Worker 		int i;
1094*bd1f8aebSAndroid Build Coastguard Worker 		for (i = 0; i < interfaces_size; i++)
1095*bd1f8aebSAndroid Build Coastguard Worker 			interfaces[i].preference = preference;
1096*bd1f8aebSAndroid Build Coastguard Worker 	}
1097*bd1f8aebSAndroid Build Coastguard Worker #endif
1098*bd1f8aebSAndroid Build Coastguard Worker }
1099*bd1f8aebSAndroid Build Coastguard Worker 
1100*bd1f8aebSAndroid Build Coastguard Worker void
initifs()1101*bd1f8aebSAndroid Build Coastguard Worker initifs()
1102*bd1f8aebSAndroid Build Coastguard Worker {
1103*bd1f8aebSAndroid Build Coastguard Worker 	int	sock;
1104*bd1f8aebSAndroid Build Coastguard Worker 	struct ifconf ifc;
1105*bd1f8aebSAndroid Build Coastguard Worker 	struct ifreq ifreq, *ifr;
1106*bd1f8aebSAndroid Build Coastguard Worker 	struct sockaddr_in *sin;
1107*bd1f8aebSAndroid Build Coastguard Worker 	int n, i;
1108*bd1f8aebSAndroid Build Coastguard Worker 	char *buf;
1109*bd1f8aebSAndroid Build Coastguard Worker 	int numifs;
1110*bd1f8aebSAndroid Build Coastguard Worker 	unsigned bufsize;
1111*bd1f8aebSAndroid Build Coastguard Worker 
1112*bd1f8aebSAndroid Build Coastguard Worker 	sock = socket(AF_INET, SOCK_DGRAM, 0);
1113*bd1f8aebSAndroid Build Coastguard Worker 	if (sock < 0) {
1114*bd1f8aebSAndroid Build Coastguard Worker 		logperror("initifs: socket");
1115*bd1f8aebSAndroid Build Coastguard Worker 		return;
1116*bd1f8aebSAndroid Build Coastguard Worker 	}
1117*bd1f8aebSAndroid Build Coastguard Worker #ifdef SIOCGIFNUM
1118*bd1f8aebSAndroid Build Coastguard Worker 	if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) {
1119*bd1f8aebSAndroid Build Coastguard Worker 		numifs = MAXIFS;
1120*bd1f8aebSAndroid Build Coastguard Worker 	}
1121*bd1f8aebSAndroid Build Coastguard Worker #else
1122*bd1f8aebSAndroid Build Coastguard Worker 	numifs = MAXIFS;
1123*bd1f8aebSAndroid Build Coastguard Worker #endif
1124*bd1f8aebSAndroid Build Coastguard Worker 	bufsize = numifs * sizeof(struct ifreq);
1125*bd1f8aebSAndroid Build Coastguard Worker 	buf = (char *)malloc(bufsize);
1126*bd1f8aebSAndroid Build Coastguard Worker 	if (buf == NULL) {
1127*bd1f8aebSAndroid Build Coastguard Worker 		logerr("out of memory\n");
1128*bd1f8aebSAndroid Build Coastguard Worker 		(void) close(sock);
1129*bd1f8aebSAndroid Build Coastguard Worker 		return;
1130*bd1f8aebSAndroid Build Coastguard Worker 	}
1131*bd1f8aebSAndroid Build Coastguard Worker 	if (interfaces != NULL)
1132*bd1f8aebSAndroid Build Coastguard Worker 		(void) free(interfaces);
1133*bd1f8aebSAndroid Build Coastguard Worker 	interfaces = (struct interface *)ALLIGN(malloc(numifs *
1134*bd1f8aebSAndroid Build Coastguard Worker 					sizeof(struct interface)));
1135*bd1f8aebSAndroid Build Coastguard Worker 	if (interfaces == NULL) {
1136*bd1f8aebSAndroid Build Coastguard Worker 		logerr("out of memory\n");
1137*bd1f8aebSAndroid Build Coastguard Worker 		(void) close(sock);
1138*bd1f8aebSAndroid Build Coastguard Worker 		(void) free(buf);
1139*bd1f8aebSAndroid Build Coastguard Worker 		return;
1140*bd1f8aebSAndroid Build Coastguard Worker 	}
1141*bd1f8aebSAndroid Build Coastguard Worker 	interfaces_size = numifs;
1142*bd1f8aebSAndroid Build Coastguard Worker 
1143*bd1f8aebSAndroid Build Coastguard Worker 	ifc.ifc_len = bufsize;
1144*bd1f8aebSAndroid Build Coastguard Worker 	ifc.ifc_buf = buf;
1145*bd1f8aebSAndroid Build Coastguard Worker 	if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1146*bd1f8aebSAndroid Build Coastguard Worker 		logperror("initifs: ioctl (get interface configuration)");
1147*bd1f8aebSAndroid Build Coastguard Worker 		(void) close(sock);
1148*bd1f8aebSAndroid Build Coastguard Worker 		(void) free(buf);
1149*bd1f8aebSAndroid Build Coastguard Worker 		return;
1150*bd1f8aebSAndroid Build Coastguard Worker 	}
1151*bd1f8aebSAndroid Build Coastguard Worker 	ifr = ifc.ifc_req;
1152*bd1f8aebSAndroid Build Coastguard Worker 	for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
1153*bd1f8aebSAndroid Build Coastguard Worker 		ifreq = *ifr;
1154*bd1f8aebSAndroid Build Coastguard Worker 		if (strlen(ifreq.ifr_name) >= IFNAMSIZ)
1155*bd1f8aebSAndroid Build Coastguard Worker 			continue;
1156*bd1f8aebSAndroid Build Coastguard Worker 		if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
1157*bd1f8aebSAndroid Build Coastguard Worker 			logperror("initifs: ioctl (get interface flags)");
1158*bd1f8aebSAndroid Build Coastguard Worker 			continue;
1159*bd1f8aebSAndroid Build Coastguard Worker 		}
1160*bd1f8aebSAndroid Build Coastguard Worker 		if (ifr->ifr_addr.sa_family != AF_INET)
1161*bd1f8aebSAndroid Build Coastguard Worker 			continue;
1162*bd1f8aebSAndroid Build Coastguard Worker 		if ((ifreq.ifr_flags & IFF_UP) == 0)
1163*bd1f8aebSAndroid Build Coastguard Worker 			continue;
1164*bd1f8aebSAndroid Build Coastguard Worker 		if (ifreq.ifr_flags & IFF_LOOPBACK)
1165*bd1f8aebSAndroid Build Coastguard Worker 			continue;
1166*bd1f8aebSAndroid Build Coastguard Worker 		if ((ifreq.ifr_flags & (IFF_MULTICAST|IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
1167*bd1f8aebSAndroid Build Coastguard Worker 			continue;
1168*bd1f8aebSAndroid Build Coastguard Worker 		strncpy(interfaces[i].name, ifr->ifr_name, IFNAMSIZ-1);
1169*bd1f8aebSAndroid Build Coastguard Worker 
1170*bd1f8aebSAndroid Build Coastguard Worker 		sin = (struct sockaddr_in *)ALLIGN(&ifr->ifr_addr);
1171*bd1f8aebSAndroid Build Coastguard Worker 		interfaces[i].localaddr = sin->sin_addr;
1172*bd1f8aebSAndroid Build Coastguard Worker 		interfaces[i].flags = ifreq.ifr_flags;
1173*bd1f8aebSAndroid Build Coastguard Worker 		interfaces[i].netmask.s_addr = (__u32)0xffffffff;
1174*bd1f8aebSAndroid Build Coastguard Worker 		if (ioctl(sock, SIOCGIFINDEX, (char *)&ifreq) < 0) {
1175*bd1f8aebSAndroid Build Coastguard Worker 			logperror("initifs: ioctl (get ifindex)");
1176*bd1f8aebSAndroid Build Coastguard Worker 			continue;
1177*bd1f8aebSAndroid Build Coastguard Worker 		}
1178*bd1f8aebSAndroid Build Coastguard Worker 		interfaces[i].ifindex = ifreq.ifr_ifindex;
1179*bd1f8aebSAndroid Build Coastguard Worker 		if (ifreq.ifr_flags & IFF_POINTOPOINT) {
1180*bd1f8aebSAndroid Build Coastguard Worker 			if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
1181*bd1f8aebSAndroid Build Coastguard Worker 				logperror("initifs: ioctl (get destination addr)");
1182*bd1f8aebSAndroid Build Coastguard Worker 				continue;
1183*bd1f8aebSAndroid Build Coastguard Worker 			}
1184*bd1f8aebSAndroid Build Coastguard Worker 			sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
1185*bd1f8aebSAndroid Build Coastguard Worker 			/* A pt-pt link is identified by the remote address */
1186*bd1f8aebSAndroid Build Coastguard Worker 			interfaces[i].address = sin->sin_addr;
1187*bd1f8aebSAndroid Build Coastguard Worker 			interfaces[i].remoteaddr = sin->sin_addr;
1188*bd1f8aebSAndroid Build Coastguard Worker 			/* Simulate broadcast for pt-pt */
1189*bd1f8aebSAndroid Build Coastguard Worker 			interfaces[i].bcastaddr = sin->sin_addr;
1190*bd1f8aebSAndroid Build Coastguard Worker 			interfaces[i].flags |= IFF_BROADCAST;
1191*bd1f8aebSAndroid Build Coastguard Worker 		} else {
1192*bd1f8aebSAndroid Build Coastguard Worker 			/* Non pt-pt links are identified by the local address */
1193*bd1f8aebSAndroid Build Coastguard Worker 			interfaces[i].address = interfaces[i].localaddr;
1194*bd1f8aebSAndroid Build Coastguard Worker 			interfaces[i].remoteaddr = interfaces[i].address;
1195*bd1f8aebSAndroid Build Coastguard Worker 			if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
1196*bd1f8aebSAndroid Build Coastguard Worker 				logperror("initifs: ioctl (get netmask)");
1197*bd1f8aebSAndroid Build Coastguard Worker 				continue;
1198*bd1f8aebSAndroid Build Coastguard Worker 			}
1199*bd1f8aebSAndroid Build Coastguard Worker 			sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
1200*bd1f8aebSAndroid Build Coastguard Worker 			interfaces[i].netmask = sin->sin_addr;
1201*bd1f8aebSAndroid Build Coastguard Worker 			if (ifreq.ifr_flags & IFF_BROADCAST) {
1202*bd1f8aebSAndroid Build Coastguard Worker 				if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
1203*bd1f8aebSAndroid Build Coastguard Worker 					logperror("initifs: ioctl (get broadcast address)");
1204*bd1f8aebSAndroid Build Coastguard Worker 					continue;
1205*bd1f8aebSAndroid Build Coastguard Worker 				}
1206*bd1f8aebSAndroid Build Coastguard Worker 				sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
1207*bd1f8aebSAndroid Build Coastguard Worker 				interfaces[i].bcastaddr = sin->sin_addr;
1208*bd1f8aebSAndroid Build Coastguard Worker 			}
1209*bd1f8aebSAndroid Build Coastguard Worker 		}
1210*bd1f8aebSAndroid Build Coastguard Worker #ifdef notdef
1211*bd1f8aebSAndroid Build Coastguard Worker 		if (debug)
1212*bd1f8aebSAndroid Build Coastguard Worker 			logdebug("Found interface %s, flags 0x%x\n",
1213*bd1f8aebSAndroid Build Coastguard Worker 				 pr_name(interfaces[i].localaddr),
1214*bd1f8aebSAndroid Build Coastguard Worker 				 interfaces[i].flags);
1215*bd1f8aebSAndroid Build Coastguard Worker #endif
1216*bd1f8aebSAndroid Build Coastguard Worker 		i++;
1217*bd1f8aebSAndroid Build Coastguard Worker 	}
1218*bd1f8aebSAndroid Build Coastguard Worker 	num_interfaces = i;
1219*bd1f8aebSAndroid Build Coastguard Worker #ifdef notdef
1220*bd1f8aebSAndroid Build Coastguard Worker 	if (debug)
1221*bd1f8aebSAndroid Build Coastguard Worker 		logdebug("Found %d interfaces\n", num_interfaces);
1222*bd1f8aebSAndroid Build Coastguard Worker #endif
1223*bd1f8aebSAndroid Build Coastguard Worker 	(void) close(sock);
1224*bd1f8aebSAndroid Build Coastguard Worker 	(void) free(buf);
1225*bd1f8aebSAndroid Build Coastguard Worker }
1226*bd1f8aebSAndroid Build Coastguard Worker 
1227*bd1f8aebSAndroid Build Coastguard Worker int
join(int sock,struct sockaddr_in * sin)1228*bd1f8aebSAndroid Build Coastguard Worker join(int sock, struct sockaddr_in *sin)
1229*bd1f8aebSAndroid Build Coastguard Worker {
1230*bd1f8aebSAndroid Build Coastguard Worker 	int i, j;
1231*bd1f8aebSAndroid Build Coastguard Worker 	struct ip_mreqn mreq;
1232*bd1f8aebSAndroid Build Coastguard Worker 	int joined[num_interfaces];
1233*bd1f8aebSAndroid Build Coastguard Worker 
1234*bd1f8aebSAndroid Build Coastguard Worker 	memset(joined, 0, sizeof(joined));
1235*bd1f8aebSAndroid Build Coastguard Worker 
1236*bd1f8aebSAndroid Build Coastguard Worker 	if (isbroadcast(sin))
1237*bd1f8aebSAndroid Build Coastguard Worker 		return (0);
1238*bd1f8aebSAndroid Build Coastguard Worker 
1239*bd1f8aebSAndroid Build Coastguard Worker 	mreq.imr_multiaddr = sin->sin_addr;
1240*bd1f8aebSAndroid Build Coastguard Worker 	for (i = 0; i < num_interfaces; i++) {
1241*bd1f8aebSAndroid Build Coastguard Worker 		for (j = 0; j < i; j++) {
1242*bd1f8aebSAndroid Build Coastguard Worker 			if (joined[j] == interfaces[i].ifindex)
1243*bd1f8aebSAndroid Build Coastguard Worker 				break;
1244*bd1f8aebSAndroid Build Coastguard Worker 		}
1245*bd1f8aebSAndroid Build Coastguard Worker 		if (j != i)
1246*bd1f8aebSAndroid Build Coastguard Worker 			continue;
1247*bd1f8aebSAndroid Build Coastguard Worker 
1248*bd1f8aebSAndroid Build Coastguard Worker 		mreq.imr_ifindex = interfaces[i].ifindex;
1249*bd1f8aebSAndroid Build Coastguard Worker 		mreq.imr_address.s_addr = 0;
1250*bd1f8aebSAndroid Build Coastguard Worker 
1251*bd1f8aebSAndroid Build Coastguard Worker 		if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1252*bd1f8aebSAndroid Build Coastguard Worker 			       (char *)&mreq, sizeof(mreq)) < 0) {
1253*bd1f8aebSAndroid Build Coastguard Worker 			logperror("setsockopt (IP_ADD_MEMBERSHIP)");
1254*bd1f8aebSAndroid Build Coastguard Worker 			return (-1);
1255*bd1f8aebSAndroid Build Coastguard Worker 		}
1256*bd1f8aebSAndroid Build Coastguard Worker 
1257*bd1f8aebSAndroid Build Coastguard Worker 		joined[i] = interfaces[i].ifindex;
1258*bd1f8aebSAndroid Build Coastguard Worker 	}
1259*bd1f8aebSAndroid Build Coastguard Worker 	return (0);
1260*bd1f8aebSAndroid Build Coastguard Worker }
1261*bd1f8aebSAndroid Build Coastguard Worker 
support_multicast()1262*bd1f8aebSAndroid Build Coastguard Worker int support_multicast()
1263*bd1f8aebSAndroid Build Coastguard Worker {
1264*bd1f8aebSAndroid Build Coastguard Worker 	int sock;
1265*bd1f8aebSAndroid Build Coastguard Worker 	u_char ttl = 1;
1266*bd1f8aebSAndroid Build Coastguard Worker 
1267*bd1f8aebSAndroid Build Coastguard Worker 	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1268*bd1f8aebSAndroid Build Coastguard Worker 	if (sock < 0) {
1269*bd1f8aebSAndroid Build Coastguard Worker 		logperror("support_multicast: socket");
1270*bd1f8aebSAndroid Build Coastguard Worker 		return (0);
1271*bd1f8aebSAndroid Build Coastguard Worker 	}
1272*bd1f8aebSAndroid Build Coastguard Worker 
1273*bd1f8aebSAndroid Build Coastguard Worker 	if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
1274*bd1f8aebSAndroid Build Coastguard Worker 		       (char *)&ttl, sizeof(ttl)) < 0) {
1275*bd1f8aebSAndroid Build Coastguard Worker 		(void) close(sock);
1276*bd1f8aebSAndroid Build Coastguard Worker 		return (0);
1277*bd1f8aebSAndroid Build Coastguard Worker 	}
1278*bd1f8aebSAndroid Build Coastguard Worker 	(void) close(sock);
1279*bd1f8aebSAndroid Build Coastguard Worker 	return (1);
1280*bd1f8aebSAndroid Build Coastguard Worker }
1281*bd1f8aebSAndroid Build Coastguard Worker 
1282*bd1f8aebSAndroid Build Coastguard Worker int
is_directly_connected(struct in_addr in)1283*bd1f8aebSAndroid Build Coastguard Worker is_directly_connected(struct in_addr in)
1284*bd1f8aebSAndroid Build Coastguard Worker {
1285*bd1f8aebSAndroid Build Coastguard Worker 	int i;
1286*bd1f8aebSAndroid Build Coastguard Worker 
1287*bd1f8aebSAndroid Build Coastguard Worker 	for (i = 0; i < num_interfaces; i++) {
1288*bd1f8aebSAndroid Build Coastguard Worker 		/* Check that the subnetwork numbers match */
1289*bd1f8aebSAndroid Build Coastguard Worker 
1290*bd1f8aebSAndroid Build Coastguard Worker 		if ((in.s_addr & interfaces[i].netmask.s_addr ) ==
1291*bd1f8aebSAndroid Build Coastguard Worker 		    (interfaces[i].remoteaddr.s_addr & interfaces[i].netmask.s_addr))
1292*bd1f8aebSAndroid Build Coastguard Worker 			return (1);
1293*bd1f8aebSAndroid Build Coastguard Worker 	}
1294*bd1f8aebSAndroid Build Coastguard Worker 	return (0);
1295*bd1f8aebSAndroid Build Coastguard Worker }
1296*bd1f8aebSAndroid Build Coastguard Worker 
1297*bd1f8aebSAndroid Build Coastguard Worker /*
1298*bd1f8aebSAndroid Build Coastguard Worker  * TABLES
1299*bd1f8aebSAndroid Build Coastguard Worker  */
1300*bd1f8aebSAndroid Build Coastguard Worker struct table {
1301*bd1f8aebSAndroid Build Coastguard Worker 	struct in_addr	router;
1302*bd1f8aebSAndroid Build Coastguard Worker 	int		preference;
1303*bd1f8aebSAndroid Build Coastguard Worker 	int		remaining_time;
1304*bd1f8aebSAndroid Build Coastguard Worker 	int		in_kernel;
1305*bd1f8aebSAndroid Build Coastguard Worker 	struct table	*next;
1306*bd1f8aebSAndroid Build Coastguard Worker };
1307*bd1f8aebSAndroid Build Coastguard Worker 
1308*bd1f8aebSAndroid Build Coastguard Worker struct table *table;
1309*bd1f8aebSAndroid Build Coastguard Worker 
1310*bd1f8aebSAndroid Build Coastguard Worker struct table *
find_router(struct in_addr addr)1311*bd1f8aebSAndroid Build Coastguard Worker find_router(struct in_addr addr)
1312*bd1f8aebSAndroid Build Coastguard Worker {
1313*bd1f8aebSAndroid Build Coastguard Worker 	struct table *tp;
1314*bd1f8aebSAndroid Build Coastguard Worker 
1315*bd1f8aebSAndroid Build Coastguard Worker 	tp = table;
1316*bd1f8aebSAndroid Build Coastguard Worker 	while (tp) {
1317*bd1f8aebSAndroid Build Coastguard Worker 		if (tp->router.s_addr == addr.s_addr)
1318*bd1f8aebSAndroid Build Coastguard Worker 			return (tp);
1319*bd1f8aebSAndroid Build Coastguard Worker 		tp = tp->next;
1320*bd1f8aebSAndroid Build Coastguard Worker 	}
1321*bd1f8aebSAndroid Build Coastguard Worker 	return (NULL);
1322*bd1f8aebSAndroid Build Coastguard Worker }
1323*bd1f8aebSAndroid Build Coastguard Worker 
max_preference(void)1324*bd1f8aebSAndroid Build Coastguard Worker int max_preference(void)
1325*bd1f8aebSAndroid Build Coastguard Worker {
1326*bd1f8aebSAndroid Build Coastguard Worker 	struct table *tp;
1327*bd1f8aebSAndroid Build Coastguard Worker 	int max = (int)INELIGIBLE_PREF;
1328*bd1f8aebSAndroid Build Coastguard Worker 
1329*bd1f8aebSAndroid Build Coastguard Worker 	tp = table;
1330*bd1f8aebSAndroid Build Coastguard Worker 	while (tp) {
1331*bd1f8aebSAndroid Build Coastguard Worker 		if (tp->preference > max)
1332*bd1f8aebSAndroid Build Coastguard Worker 			max = tp->preference;
1333*bd1f8aebSAndroid Build Coastguard Worker 		tp = tp->next;
1334*bd1f8aebSAndroid Build Coastguard Worker 	}
1335*bd1f8aebSAndroid Build Coastguard Worker 	return (max);
1336*bd1f8aebSAndroid Build Coastguard Worker }
1337*bd1f8aebSAndroid Build Coastguard Worker 
1338*bd1f8aebSAndroid Build Coastguard Worker 
1339*bd1f8aebSAndroid Build Coastguard Worker /* Note: this might leave the kernel with no default route for a short time. */
1340*bd1f8aebSAndroid Build Coastguard Worker void
age_table(int time)1341*bd1f8aebSAndroid Build Coastguard Worker age_table(int time)
1342*bd1f8aebSAndroid Build Coastguard Worker {
1343*bd1f8aebSAndroid Build Coastguard Worker 	struct table **tpp, *tp;
1344*bd1f8aebSAndroid Build Coastguard Worker 	int recalculate_max = 0;
1345*bd1f8aebSAndroid Build Coastguard Worker 	int max = max_preference();
1346*bd1f8aebSAndroid Build Coastguard Worker 
1347*bd1f8aebSAndroid Build Coastguard Worker 	tpp = &table;
1348*bd1f8aebSAndroid Build Coastguard Worker 	while (*tpp != NULL) {
1349*bd1f8aebSAndroid Build Coastguard Worker 		tp = *tpp;
1350*bd1f8aebSAndroid Build Coastguard Worker 		tp->remaining_time -= time;
1351*bd1f8aebSAndroid Build Coastguard Worker 		if (tp->remaining_time <= 0) {
1352*bd1f8aebSAndroid Build Coastguard Worker 			*tpp = tp->next;
1353*bd1f8aebSAndroid Build Coastguard Worker 			if (tp->in_kernel)
1354*bd1f8aebSAndroid Build Coastguard Worker 				del_route(tp->router);
1355*bd1f8aebSAndroid Build Coastguard Worker 			if (best_preference &&
1356*bd1f8aebSAndroid Build Coastguard Worker 			    tp->preference == max)
1357*bd1f8aebSAndroid Build Coastguard Worker 				recalculate_max++;
1358*bd1f8aebSAndroid Build Coastguard Worker 			free((char *)tp);
1359*bd1f8aebSAndroid Build Coastguard Worker 		} else {
1360*bd1f8aebSAndroid Build Coastguard Worker 			tpp = &tp->next;
1361*bd1f8aebSAndroid Build Coastguard Worker 		}
1362*bd1f8aebSAndroid Build Coastguard Worker 	}
1363*bd1f8aebSAndroid Build Coastguard Worker 	if (recalculate_max) {
1364*bd1f8aebSAndroid Build Coastguard Worker 		int max = max_preference();
1365*bd1f8aebSAndroid Build Coastguard Worker 
1366*bd1f8aebSAndroid Build Coastguard Worker 		if (max != INELIGIBLE_PREF) {
1367*bd1f8aebSAndroid Build Coastguard Worker 			tp = table;
1368*bd1f8aebSAndroid Build Coastguard Worker 			while (tp) {
1369*bd1f8aebSAndroid Build Coastguard Worker 				if (tp->preference == max && !tp->in_kernel) {
1370*bd1f8aebSAndroid Build Coastguard Worker 					add_route(tp->router);
1371*bd1f8aebSAndroid Build Coastguard Worker 					tp->in_kernel++;
1372*bd1f8aebSAndroid Build Coastguard Worker 				}
1373*bd1f8aebSAndroid Build Coastguard Worker 				tp = tp->next;
1374*bd1f8aebSAndroid Build Coastguard Worker 			}
1375*bd1f8aebSAndroid Build Coastguard Worker 		}
1376*bd1f8aebSAndroid Build Coastguard Worker 	}
1377*bd1f8aebSAndroid Build Coastguard Worker }
1378*bd1f8aebSAndroid Build Coastguard Worker 
discard_table(void)1379*bd1f8aebSAndroid Build Coastguard Worker void discard_table(void)
1380*bd1f8aebSAndroid Build Coastguard Worker {
1381*bd1f8aebSAndroid Build Coastguard Worker 	struct table **tpp, *tp;
1382*bd1f8aebSAndroid Build Coastguard Worker 
1383*bd1f8aebSAndroid Build Coastguard Worker 	tpp = &table;
1384*bd1f8aebSAndroid Build Coastguard Worker 	while (*tpp != NULL) {
1385*bd1f8aebSAndroid Build Coastguard Worker 		tp = *tpp;
1386*bd1f8aebSAndroid Build Coastguard Worker 		*tpp = tp->next;
1387*bd1f8aebSAndroid Build Coastguard Worker 		if (tp->in_kernel)
1388*bd1f8aebSAndroid Build Coastguard Worker 			del_route(tp->router);
1389*bd1f8aebSAndroid Build Coastguard Worker 		free((char *)tp);
1390*bd1f8aebSAndroid Build Coastguard Worker 	}
1391*bd1f8aebSAndroid Build Coastguard Worker }
1392*bd1f8aebSAndroid Build Coastguard Worker 
1393*bd1f8aebSAndroid Build Coastguard Worker 
1394*bd1f8aebSAndroid Build Coastguard Worker void
record_router(struct in_addr router,int preference,int ttl)1395*bd1f8aebSAndroid Build Coastguard Worker record_router(struct in_addr router, int preference, int ttl)
1396*bd1f8aebSAndroid Build Coastguard Worker {
1397*bd1f8aebSAndroid Build Coastguard Worker 	struct table *tp;
1398*bd1f8aebSAndroid Build Coastguard Worker 	int old_max = max_preference();
1399*bd1f8aebSAndroid Build Coastguard Worker 	int changed_up = 0;	/* max preference could have increased */
1400*bd1f8aebSAndroid Build Coastguard Worker 	int changed_down = 0;	/* max preference could have decreased */
1401*bd1f8aebSAndroid Build Coastguard Worker 
1402*bd1f8aebSAndroid Build Coastguard Worker 	if (ttl < 4)
1403*bd1f8aebSAndroid Build Coastguard Worker 		preference = INELIGIBLE_PREF;
1404*bd1f8aebSAndroid Build Coastguard Worker 
1405*bd1f8aebSAndroid Build Coastguard Worker 	if (debug)
1406*bd1f8aebSAndroid Build Coastguard Worker 		logdebug("Recording %s, ttl %d, preference 0x%x\n",
1407*bd1f8aebSAndroid Build Coastguard Worker 			 pr_name(router),
1408*bd1f8aebSAndroid Build Coastguard Worker 			 ttl,
1409*bd1f8aebSAndroid Build Coastguard Worker 			 preference);
1410*bd1f8aebSAndroid Build Coastguard Worker 	tp = find_router(router);
1411*bd1f8aebSAndroid Build Coastguard Worker 	if (tp) {
1412*bd1f8aebSAndroid Build Coastguard Worker 		if (tp->preference > preference &&
1413*bd1f8aebSAndroid Build Coastguard Worker 		    tp->preference == old_max)
1414*bd1f8aebSAndroid Build Coastguard Worker 			changed_down++;
1415*bd1f8aebSAndroid Build Coastguard Worker 		else if (preference > tp->preference)
1416*bd1f8aebSAndroid Build Coastguard Worker 			changed_up++;
1417*bd1f8aebSAndroid Build Coastguard Worker 		tp->preference = preference;
1418*bd1f8aebSAndroid Build Coastguard Worker 		tp->remaining_time = ttl;
1419*bd1f8aebSAndroid Build Coastguard Worker 	} else {
1420*bd1f8aebSAndroid Build Coastguard Worker 		if (preference > old_max)
1421*bd1f8aebSAndroid Build Coastguard Worker 			changed_up++;
1422*bd1f8aebSAndroid Build Coastguard Worker 		tp = (struct table *)ALLIGN(malloc(sizeof(struct table)));
1423*bd1f8aebSAndroid Build Coastguard Worker 		if (tp == NULL) {
1424*bd1f8aebSAndroid Build Coastguard Worker 			logerr("Out of memory\n");
1425*bd1f8aebSAndroid Build Coastguard Worker 			return;
1426*bd1f8aebSAndroid Build Coastguard Worker 		}
1427*bd1f8aebSAndroid Build Coastguard Worker 		tp->router = router;
1428*bd1f8aebSAndroid Build Coastguard Worker 		tp->preference = preference;
1429*bd1f8aebSAndroid Build Coastguard Worker 		tp->remaining_time = ttl;
1430*bd1f8aebSAndroid Build Coastguard Worker 		tp->in_kernel = 0;
1431*bd1f8aebSAndroid Build Coastguard Worker 		tp->next = table;
1432*bd1f8aebSAndroid Build Coastguard Worker 		table = tp;
1433*bd1f8aebSAndroid Build Coastguard Worker 	}
1434*bd1f8aebSAndroid Build Coastguard Worker 	if (!tp->in_kernel &&
1435*bd1f8aebSAndroid Build Coastguard Worker 	    (!best_preference || tp->preference == max_preference()) &&
1436*bd1f8aebSAndroid Build Coastguard Worker 	    tp->preference != INELIGIBLE_PREF) {
1437*bd1f8aebSAndroid Build Coastguard Worker 		add_route(tp->router);
1438*bd1f8aebSAndroid Build Coastguard Worker 		tp->in_kernel++;
1439*bd1f8aebSAndroid Build Coastguard Worker 	}
1440*bd1f8aebSAndroid Build Coastguard Worker 	if (tp->preference == INELIGIBLE_PREF && tp->in_kernel) {
1441*bd1f8aebSAndroid Build Coastguard Worker 		del_route(tp->router);
1442*bd1f8aebSAndroid Build Coastguard Worker 		tp->in_kernel = 0;
1443*bd1f8aebSAndroid Build Coastguard Worker 	}
1444*bd1f8aebSAndroid Build Coastguard Worker 	if (best_preference && changed_down) {
1445*bd1f8aebSAndroid Build Coastguard Worker 		/* Check if we should add routes */
1446*bd1f8aebSAndroid Build Coastguard Worker 		int new_max = max_preference();
1447*bd1f8aebSAndroid Build Coastguard Worker 		if (new_max != INELIGIBLE_PREF) {
1448*bd1f8aebSAndroid Build Coastguard Worker 			tp = table;
1449*bd1f8aebSAndroid Build Coastguard Worker 			while (tp) {
1450*bd1f8aebSAndroid Build Coastguard Worker 				if (tp->preference == new_max &&
1451*bd1f8aebSAndroid Build Coastguard Worker 				    !tp->in_kernel) {
1452*bd1f8aebSAndroid Build Coastguard Worker 					add_route(tp->router);
1453*bd1f8aebSAndroid Build Coastguard Worker 					tp->in_kernel++;
1454*bd1f8aebSAndroid Build Coastguard Worker 				}
1455*bd1f8aebSAndroid Build Coastguard Worker 				tp = tp->next;
1456*bd1f8aebSAndroid Build Coastguard Worker 			}
1457*bd1f8aebSAndroid Build Coastguard Worker 		}
1458*bd1f8aebSAndroid Build Coastguard Worker 	}
1459*bd1f8aebSAndroid Build Coastguard Worker 	if (best_preference && (changed_up || changed_down)) {
1460*bd1f8aebSAndroid Build Coastguard Worker 		/* Check if we should remove routes already in the kernel */
1461*bd1f8aebSAndroid Build Coastguard Worker 		int new_max = max_preference();
1462*bd1f8aebSAndroid Build Coastguard Worker 		tp = table;
1463*bd1f8aebSAndroid Build Coastguard Worker 		while (tp) {
1464*bd1f8aebSAndroid Build Coastguard Worker 			if (tp->preference < new_max && tp->in_kernel) {
1465*bd1f8aebSAndroid Build Coastguard Worker 				del_route(tp->router);
1466*bd1f8aebSAndroid Build Coastguard Worker 				tp->in_kernel = 0;
1467*bd1f8aebSAndroid Build Coastguard Worker 			}
1468*bd1f8aebSAndroid Build Coastguard Worker 			tp = tp->next;
1469*bd1f8aebSAndroid Build Coastguard Worker 		}
1470*bd1f8aebSAndroid Build Coastguard Worker 	}
1471*bd1f8aebSAndroid Build Coastguard Worker }
1472*bd1f8aebSAndroid Build Coastguard Worker 
1473*bd1f8aebSAndroid Build Coastguard Worker void
add_route(struct in_addr addr)1474*bd1f8aebSAndroid Build Coastguard Worker add_route(struct in_addr addr)
1475*bd1f8aebSAndroid Build Coastguard Worker {
1476*bd1f8aebSAndroid Build Coastguard Worker 	if (debug)
1477*bd1f8aebSAndroid Build Coastguard Worker 		logdebug("Add default route to %s\n", pr_name(addr));
1478*bd1f8aebSAndroid Build Coastguard Worker 	rtioctl(addr, SIOCADDRT);
1479*bd1f8aebSAndroid Build Coastguard Worker }
1480*bd1f8aebSAndroid Build Coastguard Worker 
1481*bd1f8aebSAndroid Build Coastguard Worker void
del_route(struct in_addr addr)1482*bd1f8aebSAndroid Build Coastguard Worker del_route(struct in_addr addr)
1483*bd1f8aebSAndroid Build Coastguard Worker {
1484*bd1f8aebSAndroid Build Coastguard Worker 	if (debug)
1485*bd1f8aebSAndroid Build Coastguard Worker 		logdebug("Delete default route to %s\n", pr_name(addr));
1486*bd1f8aebSAndroid Build Coastguard Worker 	rtioctl(addr, SIOCDELRT);
1487*bd1f8aebSAndroid Build Coastguard Worker }
1488*bd1f8aebSAndroid Build Coastguard Worker 
1489*bd1f8aebSAndroid Build Coastguard Worker void
rtioctl(struct in_addr addr,int op)1490*bd1f8aebSAndroid Build Coastguard Worker rtioctl(struct in_addr addr, int op)
1491*bd1f8aebSAndroid Build Coastguard Worker {
1492*bd1f8aebSAndroid Build Coastguard Worker 	int sock;
1493*bd1f8aebSAndroid Build Coastguard Worker 	struct rtentry rt;
1494*bd1f8aebSAndroid Build Coastguard Worker 	struct sockaddr_in *sin;
1495*bd1f8aebSAndroid Build Coastguard Worker 
1496*bd1f8aebSAndroid Build Coastguard Worker 	memset((char *)&rt, 0, sizeof(struct rtentry));
1497*bd1f8aebSAndroid Build Coastguard Worker 	rt.rt_dst.sa_family = AF_INET;
1498*bd1f8aebSAndroid Build Coastguard Worker 	rt.rt_gateway.sa_family = AF_INET;
1499*bd1f8aebSAndroid Build Coastguard Worker 	rt.rt_genmask.sa_family = AF_INET;
1500*bd1f8aebSAndroid Build Coastguard Worker 	sin = (struct sockaddr_in *)ALLIGN(&rt.rt_gateway);
1501*bd1f8aebSAndroid Build Coastguard Worker 	sin->sin_addr = addr;
1502*bd1f8aebSAndroid Build Coastguard Worker 	rt.rt_flags = RTF_UP | RTF_GATEWAY;
1503*bd1f8aebSAndroid Build Coastguard Worker 
1504*bd1f8aebSAndroid Build Coastguard Worker 	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1505*bd1f8aebSAndroid Build Coastguard Worker 	if (sock < 0) {
1506*bd1f8aebSAndroid Build Coastguard Worker 		logperror("rtioctl: socket");
1507*bd1f8aebSAndroid Build Coastguard Worker 		return;
1508*bd1f8aebSAndroid Build Coastguard Worker 	}
1509*bd1f8aebSAndroid Build Coastguard Worker 	if (ioctl(sock, op, (char *)&rt) < 0) {
1510*bd1f8aebSAndroid Build Coastguard Worker 		if (!(op == SIOCADDRT && errno == EEXIST))
1511*bd1f8aebSAndroid Build Coastguard Worker 			logperror("ioctl (add/delete route)");
1512*bd1f8aebSAndroid Build Coastguard Worker 	}
1513*bd1f8aebSAndroid Build Coastguard Worker 	(void) close(sock);
1514*bd1f8aebSAndroid Build Coastguard Worker }
1515*bd1f8aebSAndroid Build Coastguard Worker 
1516*bd1f8aebSAndroid Build Coastguard Worker /*
1517*bd1f8aebSAndroid Build Coastguard Worker  * LOGGER
1518*bd1f8aebSAndroid Build Coastguard Worker  */
1519*bd1f8aebSAndroid Build Coastguard Worker 
initlog(void)1520*bd1f8aebSAndroid Build Coastguard Worker void initlog(void)
1521*bd1f8aebSAndroid Build Coastguard Worker {
1522*bd1f8aebSAndroid Build Coastguard Worker 	logging++;
1523*bd1f8aebSAndroid Build Coastguard Worker 	openlog("in.rdiscd", LOG_PID | LOG_CONS, LOG_DAEMON);
1524*bd1f8aebSAndroid Build Coastguard Worker }
1525*bd1f8aebSAndroid Build Coastguard Worker 
1526*bd1f8aebSAndroid Build Coastguard Worker 
1527*bd1f8aebSAndroid Build Coastguard Worker void
logperror(char * str)1528*bd1f8aebSAndroid Build Coastguard Worker logperror(char *str)
1529*bd1f8aebSAndroid Build Coastguard Worker {
1530*bd1f8aebSAndroid Build Coastguard Worker 	if (logging)
1531*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_ERR, "%s: %m", str);
1532*bd1f8aebSAndroid Build Coastguard Worker 	else
1533*bd1f8aebSAndroid Build Coastguard Worker 		(void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
1534*bd1f8aebSAndroid Build Coastguard Worker }
1535