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