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