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