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