17c478bd9Sstevel@tonic-gate /* 2aee32e3dScarlsonj * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* 77c478bd9Sstevel@tonic-gate * Copyright (c) 1987 Regents of the University of California. 87c478bd9Sstevel@tonic-gate * All rights reserved. 97c478bd9Sstevel@tonic-gate * 107c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 117c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 127c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 137c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 147c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 157c478bd9Sstevel@tonic-gate * by the University of California, Berkeley. The name of the 167c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived 177c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 187c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 197c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 207c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate 237c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #include <stdio.h> 267c478bd9Sstevel@tonic-gate #include <errno.h> 277c478bd9Sstevel@tonic-gate #include <signal.h> 287c478bd9Sstevel@tonic-gate #include <sys/types.h> 297c478bd9Sstevel@tonic-gate #include <sys/time.h> 307c478bd9Sstevel@tonic-gate #include <sys/stat.h> 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/param.h> 337c478bd9Sstevel@tonic-gate #include <sys/socket.h> 347c478bd9Sstevel@tonic-gate #include <sys/file.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 377c478bd9Sstevel@tonic-gate #include <net/if.h> 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 407c478bd9Sstevel@tonic-gate #include <netinet/in.h> 417c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 427c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h> 437c478bd9Sstevel@tonic-gate #include <netdb.h> 447c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #include <fcntl.h> 477c478bd9Sstevel@tonic-gate #include <strings.h> 487c478bd9Sstevel@tonic-gate #include <stdlib.h> 497c478bd9Sstevel@tonic-gate #include <unistd.h> 507c478bd9Sstevel@tonic-gate #include <assert.h> 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #ifdef lint 537c478bd9Sstevel@tonic-gate #define ALIGN(ptr) (ptr ? 0 : 0) 547c478bd9Sstevel@tonic-gate #else 557c478bd9Sstevel@tonic-gate #define ALIGN(ptr) (ptr) 567c478bd9Sstevel@tonic-gate #endif 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #ifdef SYSV 597c478bd9Sstevel@tonic-gate #define signal(s, f) sigset(s, (void (*)(int))f) 607c478bd9Sstevel@tonic-gate #define random() rand() 617c478bd9Sstevel@tonic-gate #endif 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate #define ALL_HOSTS_ADDRESS "224.0.0.1" 647c478bd9Sstevel@tonic-gate #define ALL_ROUTERS_ADDRESS "224.0.0.2" 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #define MAXIFS 256 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate /* For router advertisement */ 697c478bd9Sstevel@tonic-gate struct icmp_ra { 707c478bd9Sstevel@tonic-gate uchar_t icmp_type; /* type of message, see below */ 717c478bd9Sstevel@tonic-gate uchar_t icmp_code; /* type sub code */ 727c478bd9Sstevel@tonic-gate ushort_t icmp_cksum; /* ones complement cksum of struct */ 737c478bd9Sstevel@tonic-gate uchar_t icmp_num_addrs; 747c478bd9Sstevel@tonic-gate uchar_t icmp_wpa; /* Words per address */ 757c478bd9Sstevel@tonic-gate short icmp_lifetime; 767c478bd9Sstevel@tonic-gate }; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate struct icmp_ra_addr { 797c478bd9Sstevel@tonic-gate ulong_t addr; 807c478bd9Sstevel@tonic-gate ulong_t preference; 817c478bd9Sstevel@tonic-gate }; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* Router constants */ 847c478bd9Sstevel@tonic-gate #define MAX_INITIAL_ADVERT_INTERVAL 16 857c478bd9Sstevel@tonic-gate #define MAX_INITIAL_ADVERTISEMENTS 3 867c478bd9Sstevel@tonic-gate #define MAX_RESPONSE_DELAY 2 /* Not used */ 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* Host constants */ 897c478bd9Sstevel@tonic-gate #define MAX_SOLICITATIONS 3 907c478bd9Sstevel@tonic-gate #define SOLICITATION_INTERVAL 3 917c478bd9Sstevel@tonic-gate #define MAX_SOLICITATION_DELAY 1 /* Not used */ 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate #define IGNORE_PREFERENCE 0x80000000 /* Maximum negative */ 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate #define MAX_ADV_INT 600 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * A doubly linked list of all physical interfaces that each contain a 1007c478bd9Sstevel@tonic-gate * doubly linked list of logical interfaces aka IP addresses. 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate struct phyint { 1037c478bd9Sstevel@tonic-gate char pi_name[IFNAMSIZ]; /* Used to identify it */ 1047c478bd9Sstevel@tonic-gate int pi_state; /* See below */ 1057c478bd9Sstevel@tonic-gate struct logint *pi_logical_first; 1067c478bd9Sstevel@tonic-gate struct logint *pi_logical_last; 1077c478bd9Sstevel@tonic-gate struct phyint *pi_next; 1087c478bd9Sstevel@tonic-gate struct phyint *pi_prev; 1097c478bd9Sstevel@tonic-gate }; 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate struct logint { 1127c478bd9Sstevel@tonic-gate char li_name[IFNAMSIZ]; /* Used to identify it */ 1137c478bd9Sstevel@tonic-gate int li_state; /* See below */ 1147c478bd9Sstevel@tonic-gate struct in_addr li_address; /* Used to identify the interface */ 1157c478bd9Sstevel@tonic-gate struct in_addr li_localaddr; /* Actual address of the interface */ 1167c478bd9Sstevel@tonic-gate int li_preference; 1177c478bd9Sstevel@tonic-gate int li_index; /* interface index (SIOCGLIFINDEX) */ 1187c478bd9Sstevel@tonic-gate uint64_t li_flags; 1197c478bd9Sstevel@tonic-gate struct in_addr li_bcastaddr; 1207c478bd9Sstevel@tonic-gate struct in_addr li_remoteaddr; 1217c478bd9Sstevel@tonic-gate struct in_addr li_netmask; 1227c478bd9Sstevel@tonic-gate struct logint *li_next; /* Next logical for this physical */ 1237c478bd9Sstevel@tonic-gate struct logint *li_prev; /* Prev logical for this physical */ 1247c478bd9Sstevel@tonic-gate struct phyint *li_physical; /* Back pointer */ 1257c478bd9Sstevel@tonic-gate }; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate struct phyint *phyint; 1287c478bd9Sstevel@tonic-gate int num_usable_interfaces; /* Num used for sending/receiving */ 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate * State bits 1327c478bd9Sstevel@tonic-gate */ 1337c478bd9Sstevel@tonic-gate #define ST_MARKED 0x01 /* To determine removed interfaces */ 1347c478bd9Sstevel@tonic-gate #define ST_JOINED 0x02 /* Joined multicast group */ 1357c478bd9Sstevel@tonic-gate #define ST_DELETED 0x04 /* Interface should be ignored */ 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate /* Function prototypes */ 1387c478bd9Sstevel@tonic-gate static void solicitor(struct sockaddr_in *sin); 1397c478bd9Sstevel@tonic-gate static void advertise(struct sockaddr_in *sin); 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate static void age_table(int time); 1427c478bd9Sstevel@tonic-gate static void flush_unreachable_routers(void); 1437c478bd9Sstevel@tonic-gate static void record_router(struct in_addr router, long preference, int ttl); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate static void add_route(struct in_addr addr); 1467c478bd9Sstevel@tonic-gate static void del_route(struct in_addr addr); 1477c478bd9Sstevel@tonic-gate static void rtioctl(struct in_addr addr, int op); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate static int support_multicast(void); 1507c478bd9Sstevel@tonic-gate static int sendbcast(int s, char *packet, int packetlen); 1517c478bd9Sstevel@tonic-gate static int sendbcastif(int s, char *packet, int packetlen, 1527c478bd9Sstevel@tonic-gate struct logint *li); 1537c478bd9Sstevel@tonic-gate static int sendmcast(int s, char *packet, int packetlen, 1547c478bd9Sstevel@tonic-gate struct sockaddr_in *sin); 1557c478bd9Sstevel@tonic-gate static int sendmcastif(int s, char *packet, int packetlen, 1567c478bd9Sstevel@tonic-gate struct sockaddr_in *sin, struct logint *li); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate static int ismulticast(struct sockaddr_in *sin); 1597c478bd9Sstevel@tonic-gate static int isbroadcast(struct sockaddr_in *sin); 1607c478bd9Sstevel@tonic-gate int in_cksum(ushort_t *addr, int len); 1617c478bd9Sstevel@tonic-gate static struct logint *find_directly_connected_logint(struct in_addr in, 1627c478bd9Sstevel@tonic-gate struct phyint *pi); 1637c478bd9Sstevel@tonic-gate static void force_preference(int preference); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate static void timer(void); 1667c478bd9Sstevel@tonic-gate static void finish(void); 1677c478bd9Sstevel@tonic-gate static void report(void); 1687c478bd9Sstevel@tonic-gate static void report_interfaces(void); 1697c478bd9Sstevel@tonic-gate static void report_routes(void); 1707c478bd9Sstevel@tonic-gate static void reinitifs(void); 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate static struct phyint *find_phyint(char *name); 1737c478bd9Sstevel@tonic-gate static struct phyint *add_phyint(char *name); 1747c478bd9Sstevel@tonic-gate static void free_phyint(struct phyint *pi); 1757c478bd9Sstevel@tonic-gate static struct logint *find_logint(struct phyint *pi, char *name); 1767c478bd9Sstevel@tonic-gate static struct logint *add_logint(struct phyint *pi, char *name); 1777c478bd9Sstevel@tonic-gate static void free_logint(struct logint *li); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate static void deleted_phyint(struct phyint *pi, int s, 1807c478bd9Sstevel@tonic-gate struct sockaddr_in *joinaddr); 1817c478bd9Sstevel@tonic-gate static void added_logint(struct logint *li, int s, 1827c478bd9Sstevel@tonic-gate struct sockaddr_in *joinaddr); 1837c478bd9Sstevel@tonic-gate static void deleted_logint(struct logint *li, struct logint *newli, int s, 1847c478bd9Sstevel@tonic-gate struct sockaddr_in *joinaddr); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate static int initifs(int s, struct sockaddr_in *joinaddr, int preference); 1877c478bd9Sstevel@tonic-gate static boolean_t getconfig(int sock, uint64_t if_flags, struct sockaddr *addr, 1887c478bd9Sstevel@tonic-gate struct ifreq *ifr, struct logint *li); 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate static void pr_pack(char *buf, int cc, struct sockaddr_in *from); 1917c478bd9Sstevel@tonic-gate char *pr_name(struct in_addr addr); 1927c478bd9Sstevel@tonic-gate char *pr_type(int t); 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate static void initlog(void); 1957c478bd9Sstevel@tonic-gate void logerr(), logtrace(), logdebug(), logperror(); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* Local variables */ 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate #define MAXPACKET 4096 /* max packet size */ 2007c478bd9Sstevel@tonic-gate uchar_t packet[MAXPACKET]; 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate char usage[] = 2037c478bd9Sstevel@tonic-gate "Usage: rdisc [-s] [-v] [-f] [-a] [send_address] [receive_address]\n" 2047c478bd9Sstevel@tonic-gate " rdisc -r [-v] [-p <preference>] [-T <secs>] \n" 2057c478bd9Sstevel@tonic-gate " [send_address] [receive_address]\n"; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate int s; /* Socket file descriptor */ 2097c478bd9Sstevel@tonic-gate struct sockaddr_in whereto; /* Address to send to */ 2107c478bd9Sstevel@tonic-gate struct sockaddr_in g_joinaddr; /* Address to receive on */ 2117c478bd9Sstevel@tonic-gate char *sendaddress, *recvaddress; /* For logging purposes only */ 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* Common variables */ 2147c478bd9Sstevel@tonic-gate int verbose = 0; 2157c478bd9Sstevel@tonic-gate int debug = 0; 2167c478bd9Sstevel@tonic-gate int trace = 0; 2177c478bd9Sstevel@tonic-gate int start_solicit = 0; /* -s parameter set */ 2187c478bd9Sstevel@tonic-gate int solicit = 0; /* Are we currently sending solicitations? */ 2197c478bd9Sstevel@tonic-gate int responder; 2207c478bd9Sstevel@tonic-gate int ntransmitted = 0; 2217c478bd9Sstevel@tonic-gate int nreceived = 0; 2227c478bd9Sstevel@tonic-gate int forever = 0; /* Never give up on host. If 0 defer fork until */ 2237c478bd9Sstevel@tonic-gate /* first response. */ 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* Router variables */ 2267c478bd9Sstevel@tonic-gate int max_adv_int = MAX_ADV_INT; 2277c478bd9Sstevel@tonic-gate int min_adv_int; 2287c478bd9Sstevel@tonic-gate int lifetime; 2297c478bd9Sstevel@tonic-gate int initial_advert_interval = MAX_INITIAL_ADVERT_INTERVAL; 2307c478bd9Sstevel@tonic-gate int initial_advertisements = MAX_INITIAL_ADVERTISEMENTS; 2317c478bd9Sstevel@tonic-gate ulong_t g_preference = 0; /* Setable with -p option */ 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* Host variables */ 2347c478bd9Sstevel@tonic-gate int max_solicitations = MAX_SOLICITATIONS; 2357c478bd9Sstevel@tonic-gate unsigned int solicitation_interval = SOLICITATION_INTERVAL; 2367c478bd9Sstevel@tonic-gate int best_preference = 1; /* Set to record only the router(s) with the */ 2377c478bd9Sstevel@tonic-gate /* best preference in the kernel. Not set */ 2387c478bd9Sstevel@tonic-gate /* puts all routes in the kernel. */ 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate static void 2427c478bd9Sstevel@tonic-gate prusage() 2437c478bd9Sstevel@tonic-gate { 2447c478bd9Sstevel@tonic-gate (void) fprintf(stderr, usage); 2457c478bd9Sstevel@tonic-gate exit(1); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate static int sock = -1; 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate static void 2517c478bd9Sstevel@tonic-gate do_fork() 2527c478bd9Sstevel@tonic-gate { 2537c478bd9Sstevel@tonic-gate int t; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate if (trace) 2567c478bd9Sstevel@tonic-gate return; 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate if (fork()) 2597c478bd9Sstevel@tonic-gate exit(0); 2607c478bd9Sstevel@tonic-gate for (t = 0; t < 20; t++) 2617c478bd9Sstevel@tonic-gate if (t != s) 2627c478bd9Sstevel@tonic-gate (void) close(t); 2637c478bd9Sstevel@tonic-gate sock = -1; 2647c478bd9Sstevel@tonic-gate (void) open("/", 0); 2657c478bd9Sstevel@tonic-gate (void) dup2(0, 1); 2667c478bd9Sstevel@tonic-gate (void) dup2(0, 2); 2677c478bd9Sstevel@tonic-gate #ifndef SYSV 2687c478bd9Sstevel@tonic-gate t = open("/dev/tty", 2); 2697c478bd9Sstevel@tonic-gate if (t >= 0) { 2707c478bd9Sstevel@tonic-gate (void) ioctl(t, TIOCNOTTY, (char *)0); 2717c478bd9Sstevel@tonic-gate (void) close(t); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate #else 2747c478bd9Sstevel@tonic-gate (void) setpgrp(); 2757c478bd9Sstevel@tonic-gate #endif 2767c478bd9Sstevel@tonic-gate initlog(); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * M A I N 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate int 2837c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 2847c478bd9Sstevel@tonic-gate { 2857c478bd9Sstevel@tonic-gate #ifndef SYSV 2867c478bd9Sstevel@tonic-gate struct sigvec sv; 2877c478bd9Sstevel@tonic-gate #endif 2887c478bd9Sstevel@tonic-gate struct sockaddr_in from; 2897c478bd9Sstevel@tonic-gate char **av = argv; 2907c478bd9Sstevel@tonic-gate struct sockaddr_in *to = &whereto; 2917c478bd9Sstevel@tonic-gate ulong_t val; 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate min_adv_int = (max_adv_int * 3 / 4); 2947c478bd9Sstevel@tonic-gate lifetime = (3*max_adv_int); 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate argc--, av++; 2977c478bd9Sstevel@tonic-gate while (argc > 0 && *av[0] == '-') { 2987c478bd9Sstevel@tonic-gate while (*++av[0]) 2997c478bd9Sstevel@tonic-gate switch (*av[0]) { 3007c478bd9Sstevel@tonic-gate case 'd': 3017c478bd9Sstevel@tonic-gate debug = 1; 3027c478bd9Sstevel@tonic-gate break; 3037c478bd9Sstevel@tonic-gate case 't': 3047c478bd9Sstevel@tonic-gate trace = 1; 3057c478bd9Sstevel@tonic-gate break; 3067c478bd9Sstevel@tonic-gate case 'v': 3077c478bd9Sstevel@tonic-gate verbose++; 3087c478bd9Sstevel@tonic-gate break; 3097c478bd9Sstevel@tonic-gate case 's': 3107c478bd9Sstevel@tonic-gate start_solicit = solicit = 1; 3117c478bd9Sstevel@tonic-gate break; 3127c478bd9Sstevel@tonic-gate case 'r': 3137c478bd9Sstevel@tonic-gate responder = 1; 3147c478bd9Sstevel@tonic-gate break; 3157c478bd9Sstevel@tonic-gate case 'a': 3167c478bd9Sstevel@tonic-gate best_preference = 0; 3177c478bd9Sstevel@tonic-gate break; 3187c478bd9Sstevel@tonic-gate case 'b': 3197c478bd9Sstevel@tonic-gate best_preference = 1; 3207c478bd9Sstevel@tonic-gate break; 3217c478bd9Sstevel@tonic-gate case 'f': 3227c478bd9Sstevel@tonic-gate forever = 1; 3237c478bd9Sstevel@tonic-gate break; 3247c478bd9Sstevel@tonic-gate case 'T': 3257c478bd9Sstevel@tonic-gate argc--, av++; 3267c478bd9Sstevel@tonic-gate if (argc != 0) { 3277c478bd9Sstevel@tonic-gate val = strtol(av[0], (char **)NULL, 0); 3287c478bd9Sstevel@tonic-gate if (val < 4 || val > 1800) { 3297c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3307c478bd9Sstevel@tonic-gate "Bad Max Advertisement Interval\n"); 3317c478bd9Sstevel@tonic-gate exit(1); 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate max_adv_int = val; 3347c478bd9Sstevel@tonic-gate min_adv_int = (max_adv_int * 3 / 4); 3357c478bd9Sstevel@tonic-gate lifetime = (3*max_adv_int); 3367c478bd9Sstevel@tonic-gate } else { 3377c478bd9Sstevel@tonic-gate prusage(); 3387c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate goto next; 3417c478bd9Sstevel@tonic-gate case 'p': 3427c478bd9Sstevel@tonic-gate argc--, av++; 3437c478bd9Sstevel@tonic-gate if (argc != 0) { 3447c478bd9Sstevel@tonic-gate val = strtoul(av[0], (char **)NULL, 0); 3457c478bd9Sstevel@tonic-gate g_preference = val; 3467c478bd9Sstevel@tonic-gate } else { 3477c478bd9Sstevel@tonic-gate prusage(); 3487c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate goto next; 3517c478bd9Sstevel@tonic-gate default: 3527c478bd9Sstevel@tonic-gate prusage(); 3537c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate next: 3567c478bd9Sstevel@tonic-gate argc--, av++; 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate if (argc < 1) { 3597c478bd9Sstevel@tonic-gate if (support_multicast()) { 3607c478bd9Sstevel@tonic-gate if (responder) 3617c478bd9Sstevel@tonic-gate sendaddress = ALL_HOSTS_ADDRESS; 3627c478bd9Sstevel@tonic-gate else 3637c478bd9Sstevel@tonic-gate sendaddress = ALL_ROUTERS_ADDRESS; 3647c478bd9Sstevel@tonic-gate } else 3657c478bd9Sstevel@tonic-gate sendaddress = "255.255.255.255"; 3667c478bd9Sstevel@tonic-gate } else { 3677c478bd9Sstevel@tonic-gate sendaddress = av[0]; 3687c478bd9Sstevel@tonic-gate argc--; 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate if (argc < 1) { 3717c478bd9Sstevel@tonic-gate if (support_multicast()) { 3727c478bd9Sstevel@tonic-gate if (responder) 3737c478bd9Sstevel@tonic-gate recvaddress = ALL_ROUTERS_ADDRESS; 3747c478bd9Sstevel@tonic-gate else 3757c478bd9Sstevel@tonic-gate recvaddress = ALL_HOSTS_ADDRESS; 3767c478bd9Sstevel@tonic-gate } else 3777c478bd9Sstevel@tonic-gate recvaddress = "255.255.255.255"; 3787c478bd9Sstevel@tonic-gate } else { 3797c478bd9Sstevel@tonic-gate recvaddress = av[0]; 3807c478bd9Sstevel@tonic-gate argc--; 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate if (argc != 0) { 3837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Extra paramaters\n"); 3847c478bd9Sstevel@tonic-gate prusage(); 3857c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate if (solicit && responder) { 3897c478bd9Sstevel@tonic-gate prusage(); 3907c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate if (!(solicit && !forever)) { 3947c478bd9Sstevel@tonic-gate do_fork(); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate bzero((char *)&whereto, sizeof (struct sockaddr_in)); 3987c478bd9Sstevel@tonic-gate to->sin_family = AF_INET; 3997c478bd9Sstevel@tonic-gate to->sin_addr.s_addr = inet_addr(sendaddress); 4007c478bd9Sstevel@tonic-gate if (to->sin_addr.s_addr == (unsigned long)-1) { 4017c478bd9Sstevel@tonic-gate logerr("in.rdisc: bad address %s\n", sendaddress); 4027c478bd9Sstevel@tonic-gate exit(1); 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate bzero((char *)&g_joinaddr, sizeof (struct sockaddr_in)); 4067c478bd9Sstevel@tonic-gate g_joinaddr.sin_family = AF_INET; 4077c478bd9Sstevel@tonic-gate g_joinaddr.sin_addr.s_addr = inet_addr(recvaddress); 4087c478bd9Sstevel@tonic-gate if (g_joinaddr.sin_addr.s_addr == (unsigned long)-1) { 4097c478bd9Sstevel@tonic-gate logerr("in.rdisc: bad address %s\n", recvaddress); 4107c478bd9Sstevel@tonic-gate exit(1); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate if (responder) { 4147c478bd9Sstevel@tonic-gate #ifdef SYSV 4157c478bd9Sstevel@tonic-gate srand((int)gethostid()); 4167c478bd9Sstevel@tonic-gate #else 4177c478bd9Sstevel@tonic-gate srandom((int)gethostid()); 4187c478bd9Sstevel@tonic-gate #endif 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { 4227c478bd9Sstevel@tonic-gate logperror("socket"); 4237c478bd9Sstevel@tonic-gate exit(5); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate #ifdef SYSV 4277c478bd9Sstevel@tonic-gate setvbuf(stdout, NULL, _IOLBF, 0); 4287c478bd9Sstevel@tonic-gate #else 4297c478bd9Sstevel@tonic-gate setlinebuf(stdout); 4307c478bd9Sstevel@tonic-gate #endif 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate (void) signal(SIGINT, finish); 4337c478bd9Sstevel@tonic-gate (void) signal(SIGTERM, finish); 4347c478bd9Sstevel@tonic-gate (void) signal(SIGHUP, reinitifs); 4357c478bd9Sstevel@tonic-gate (void) signal(SIGUSR1, report); 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate if (initifs(s, &g_joinaddr, g_preference) < 0) { 4387c478bd9Sstevel@tonic-gate logerr("Failed initializing interfaces\n"); 4397c478bd9Sstevel@tonic-gate exit(2); 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate /* 4437c478bd9Sstevel@tonic-gate * If there are no usable interfaces and we are soliciting 4447c478bd9Sstevel@tonic-gate * waiting for to return an exit code (i.e. forever isn't set) 4457c478bd9Sstevel@tonic-gate * give up immediately. 4467c478bd9Sstevel@tonic-gate */ 4477c478bd9Sstevel@tonic-gate if (num_usable_interfaces == 0 && solicit && !forever) { 4487c478bd9Sstevel@tonic-gate logerr("in.rdisc: No interfaces up\n"); 4497c478bd9Sstevel@tonic-gate exit(5); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate #ifdef SYSV 4537c478bd9Sstevel@tonic-gate (void) signal(SIGALRM, timer); 4547c478bd9Sstevel@tonic-gate #else 4557c478bd9Sstevel@tonic-gate /* 4567c478bd9Sstevel@tonic-gate * Make sure that this signal actually interrupts (rather than 4577c478bd9Sstevel@tonic-gate * restarts) the recvfrom call below. 4587c478bd9Sstevel@tonic-gate */ 4597c478bd9Sstevel@tonic-gate sv.sv_handler = timer; 4607c478bd9Sstevel@tonic-gate sv.sv_mask = 0; 4617c478bd9Sstevel@tonic-gate sv.sv_flags = SV_INTERRUPT; 4627c478bd9Sstevel@tonic-gate (void) sigvec(SIGALRM, &sv, (struct sigvec *)NULL); 4637c478bd9Sstevel@tonic-gate #endif 4647c478bd9Sstevel@tonic-gate timer(); /* start things going */ 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate for (;;) { 4677c478bd9Sstevel@tonic-gate int len = sizeof (packet); 4687c478bd9Sstevel@tonic-gate socklen_t fromlen = (socklen_t)sizeof (from); 4697c478bd9Sstevel@tonic-gate int cc; 4707c478bd9Sstevel@tonic-gate sigset_t newmask, oldmask; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if ((cc = recvfrom(s, (char *)packet, len, 0, 4737c478bd9Sstevel@tonic-gate (struct sockaddr *)&from, 4747c478bd9Sstevel@tonic-gate &fromlen)) < 0) { 4757c478bd9Sstevel@tonic-gate if (errno == EINTR) 4767c478bd9Sstevel@tonic-gate continue; 4777c478bd9Sstevel@tonic-gate logperror("recvfrom"); 4787c478bd9Sstevel@tonic-gate continue; 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate /* Block all signals while processing */ 4817c478bd9Sstevel@tonic-gate (void) sigfillset(&newmask); 4827c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &newmask, &oldmask); 4837c478bd9Sstevel@tonic-gate pr_pack((char *)packet, cc, &from); 4847c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &oldmask, NULL); 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate static void 4907c478bd9Sstevel@tonic-gate report(void) 4917c478bd9Sstevel@tonic-gate { 4927c478bd9Sstevel@tonic-gate report_interfaces(); 4937c478bd9Sstevel@tonic-gate report_routes(); 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate #define TIMER_INTERVAL 6 4977c478bd9Sstevel@tonic-gate #define GETIFCONF_TIMER 30 4987c478bd9Sstevel@tonic-gate 499aee32e3dScarlsonj static int left_until_advertise; 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* Called every TIMER_INTERVAL */ 5027c478bd9Sstevel@tonic-gate static void 5037c478bd9Sstevel@tonic-gate timer(void) 5047c478bd9Sstevel@tonic-gate { 505aee32e3dScarlsonj static int time; 506aee32e3dScarlsonj static int left_until_getifconf; 507aee32e3dScarlsonj static int left_until_solicit; 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate time += TIMER_INTERVAL; 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate left_until_getifconf -= TIMER_INTERVAL; 5127c478bd9Sstevel@tonic-gate left_until_advertise -= TIMER_INTERVAL; 5137c478bd9Sstevel@tonic-gate left_until_solicit -= TIMER_INTERVAL; 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate if (left_until_getifconf < 0) { 5167c478bd9Sstevel@tonic-gate (void) initifs(s, &g_joinaddr, g_preference); 5177c478bd9Sstevel@tonic-gate left_until_getifconf = GETIFCONF_TIMER; 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate if (responder && left_until_advertise <= 0) { 5207c478bd9Sstevel@tonic-gate ntransmitted++; 5217c478bd9Sstevel@tonic-gate advertise(&whereto); 5227c478bd9Sstevel@tonic-gate if (ntransmitted < initial_advertisements) 5237c478bd9Sstevel@tonic-gate left_until_advertise = initial_advert_interval; 5247c478bd9Sstevel@tonic-gate else 5257c478bd9Sstevel@tonic-gate left_until_advertise = min_adv_int + 5267c478bd9Sstevel@tonic-gate ((max_adv_int - min_adv_int) * 5277c478bd9Sstevel@tonic-gate (random() % 1000)/1000); 5287c478bd9Sstevel@tonic-gate } else if (solicit && left_until_solicit <= 0) { 5297c478bd9Sstevel@tonic-gate if (ntransmitted < max_solicitations) { 5307c478bd9Sstevel@tonic-gate ntransmitted++; 5317c478bd9Sstevel@tonic-gate solicitor(&whereto); 5327c478bd9Sstevel@tonic-gate left_until_solicit = solicitation_interval; 5337c478bd9Sstevel@tonic-gate } else { 5347c478bd9Sstevel@tonic-gate solicit = 0; 5357c478bd9Sstevel@tonic-gate if (!forever && nreceived == 0) 5367c478bd9Sstevel@tonic-gate exit(5); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate age_table(TIMER_INTERVAL); 5407c478bd9Sstevel@tonic-gate (void) alarm(TIMER_INTERVAL); 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* 5447c478bd9Sstevel@tonic-gate * S O L I C I T O R 5457c478bd9Sstevel@tonic-gate * 5467c478bd9Sstevel@tonic-gate * Compose and transmit an ICMP ROUTER SOLICITATION REQUEST packet. 5477c478bd9Sstevel@tonic-gate * The IP packet will be added on by the kernel. 5487c478bd9Sstevel@tonic-gate */ 5497c478bd9Sstevel@tonic-gate static void 5507c478bd9Sstevel@tonic-gate solicitor(struct sockaddr_in *sin) 5517c478bd9Sstevel@tonic-gate { 5527c478bd9Sstevel@tonic-gate static uchar_t outpack[MAXPACKET]; 5537c478bd9Sstevel@tonic-gate register struct icmp *icp = (struct icmp *)ALIGN(outpack); 5547c478bd9Sstevel@tonic-gate int packetlen, i; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate if (verbose) { 5577c478bd9Sstevel@tonic-gate logtrace("Sending solicitation to %s\n", 5587c478bd9Sstevel@tonic-gate pr_name(sin->sin_addr)); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate icp->icmp_type = ICMP_ROUTERSOLICIT; 5617c478bd9Sstevel@tonic-gate icp->icmp_code = 0; 5627c478bd9Sstevel@tonic-gate icp->icmp_cksum = 0; 5637c478bd9Sstevel@tonic-gate icp->icmp_void = 0; /* Reserved */ 5647c478bd9Sstevel@tonic-gate packetlen = 8; 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate /* Compute ICMP checksum here */ 5677c478bd9Sstevel@tonic-gate icp->icmp_cksum = in_cksum((ushort_t *)icp, packetlen); 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate if (isbroadcast(sin)) 5707c478bd9Sstevel@tonic-gate i = sendbcast(s, (char *)outpack, packetlen); 5717c478bd9Sstevel@tonic-gate else if (ismulticast(sin)) 5727c478bd9Sstevel@tonic-gate i = sendmcast(s, (char *)outpack, packetlen, sin); 5737c478bd9Sstevel@tonic-gate else { 5747c478bd9Sstevel@tonic-gate struct logint *li; 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate li = find_directly_connected_logint(sin->sin_addr, NULL); 5777c478bd9Sstevel@tonic-gate if (li != NULL && (li->li_flags & IFF_NORTEXCH)) { 5787c478bd9Sstevel@tonic-gate if (verbose) { 5797c478bd9Sstevel@tonic-gate logtrace("Suppressing sending %s on %s " 5807c478bd9Sstevel@tonic-gate "(no route exchange on interface)\n", 5817c478bd9Sstevel@tonic-gate pr_type((int)icp->icmp_type), li->li_name); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate return; 5847c478bd9Sstevel@tonic-gate } else { 5857c478bd9Sstevel@tonic-gate i = sendto(s, (char *)outpack, packetlen, 0, 5867c478bd9Sstevel@tonic-gate (struct sockaddr *)sin, sizeof (struct sockaddr)); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate if (i < 0 || i != packetlen) { 5917c478bd9Sstevel@tonic-gate if (i < 0) { 5927c478bd9Sstevel@tonic-gate logperror("sendto"); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate logerr("wrote %s %d chars, ret=%d\n", 5957c478bd9Sstevel@tonic-gate sendaddress, packetlen, i); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate /* 6007c478bd9Sstevel@tonic-gate * A D V E R T I S E 6017c478bd9Sstevel@tonic-gate * 6027c478bd9Sstevel@tonic-gate * Compose and transmit an ICMP ROUTER ADVERTISEMENT packet. 6037c478bd9Sstevel@tonic-gate * The IP packet will be added on by the kernel. 6047c478bd9Sstevel@tonic-gate */ 6057c478bd9Sstevel@tonic-gate static void 6067c478bd9Sstevel@tonic-gate advertise(struct sockaddr_in *sin) 6077c478bd9Sstevel@tonic-gate { 6087c478bd9Sstevel@tonic-gate struct phyint *pi; 6097c478bd9Sstevel@tonic-gate struct logint *li, *li_tmp; 6107c478bd9Sstevel@tonic-gate static uchar_t outpack[MAXPACKET]; 6117c478bd9Sstevel@tonic-gate register struct icmp_ra *rap = (struct icmp_ra *)ALIGN(outpack); 6127c478bd9Sstevel@tonic-gate struct icmp_ra_addr *ap; 6137c478bd9Sstevel@tonic-gate int packetlen, cc; 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate if (verbose) { 6167c478bd9Sstevel@tonic-gate logtrace("Sending advertisement to %s\n", 6177c478bd9Sstevel@tonic-gate pr_name(sin->sin_addr)); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate for (pi = phyint; pi != NULL; pi = pi->pi_next) { 6217c478bd9Sstevel@tonic-gate rap->icmp_type = ICMP_ROUTERADVERT; 6227c478bd9Sstevel@tonic-gate rap->icmp_code = 0; 6237c478bd9Sstevel@tonic-gate rap->icmp_cksum = 0; 6247c478bd9Sstevel@tonic-gate rap->icmp_num_addrs = 0; 6257c478bd9Sstevel@tonic-gate rap->icmp_wpa = 2; 6267c478bd9Sstevel@tonic-gate rap->icmp_lifetime = htons(lifetime); 6277c478bd9Sstevel@tonic-gate packetlen = ICMP_MINLEN; 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; li = li->li_next) { 6307c478bd9Sstevel@tonic-gate if (li->li_state & ST_DELETED) 6317c478bd9Sstevel@tonic-gate continue; 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* 6347c478bd9Sstevel@tonic-gate * XXX Just truncate the list of addresses. 6357c478bd9Sstevel@tonic-gate * Should probably send multiple packets. 6367c478bd9Sstevel@tonic-gate */ 6377c478bd9Sstevel@tonic-gate if (packetlen + rap->icmp_wpa * 4 > sizeof (outpack)) { 6387c478bd9Sstevel@tonic-gate if (debug) 6397c478bd9Sstevel@tonic-gate logdebug("full packet: %d addresses\n", 6407c478bd9Sstevel@tonic-gate rap->icmp_num_addrs); 6417c478bd9Sstevel@tonic-gate break; 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate ap = (struct icmp_ra_addr *)ALIGN(outpack + packetlen); 6447c478bd9Sstevel@tonic-gate ap->addr = li->li_localaddr.s_addr; 6457c478bd9Sstevel@tonic-gate ap->preference = htonl(li->li_preference); 6467c478bd9Sstevel@tonic-gate packetlen += rap->icmp_wpa * 4; 6477c478bd9Sstevel@tonic-gate rap->icmp_num_addrs++; 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate if (rap->icmp_num_addrs == 0) 6517c478bd9Sstevel@tonic-gate continue; 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate /* Compute ICMP checksum here */ 6547c478bd9Sstevel@tonic-gate rap->icmp_cksum = in_cksum((ushort_t *)rap, packetlen); 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate if (isbroadcast(sin)) 6577c478bd9Sstevel@tonic-gate cc = sendbcastif(s, (char *)outpack, packetlen, 6587c478bd9Sstevel@tonic-gate pi->pi_logical_first); 6597c478bd9Sstevel@tonic-gate else if (ismulticast(sin)) 6607c478bd9Sstevel@tonic-gate cc = sendmcastif(s, (char *)outpack, packetlen, sin, 6617c478bd9Sstevel@tonic-gate pi->pi_logical_first); 6627c478bd9Sstevel@tonic-gate else { 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * Verify that the physical interface matches the 6657c478bd9Sstevel@tonic-gate * destination address. 6667c478bd9Sstevel@tonic-gate */ 6677c478bd9Sstevel@tonic-gate li_tmp = find_directly_connected_logint(sin->sin_addr, 6687c478bd9Sstevel@tonic-gate pi); 6697c478bd9Sstevel@tonic-gate if (li_tmp == NULL) 6707c478bd9Sstevel@tonic-gate continue; 6717c478bd9Sstevel@tonic-gate if (li_tmp->li_flags & IFF_NORTEXCH) { 6727c478bd9Sstevel@tonic-gate if (verbose) { 6737c478bd9Sstevel@tonic-gate logtrace("Suppressing sending %s on %s " 6747c478bd9Sstevel@tonic-gate "(no route exchange on " 6757c478bd9Sstevel@tonic-gate "interface)\n", 6767c478bd9Sstevel@tonic-gate pr_type((int)rap->icmp_type), 6777c478bd9Sstevel@tonic-gate li_tmp->li_name); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate continue; 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate if (debug) { 6827c478bd9Sstevel@tonic-gate logdebug("Unicast to %s ", 6837c478bd9Sstevel@tonic-gate pr_name(sin->sin_addr)); 6847c478bd9Sstevel@tonic-gate logdebug("on interface %s\n", pi->pi_name); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate cc = sendto(s, (char *)outpack, packetlen, 0, 6877c478bd9Sstevel@tonic-gate (struct sockaddr *)sin, sizeof (struct sockaddr)); 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate if (cc < 0 || cc != packetlen) { 6907c478bd9Sstevel@tonic-gate if (cc < 0) { 6917c478bd9Sstevel@tonic-gate logperror("sendto"); 6927c478bd9Sstevel@tonic-gate } else { 6937c478bd9Sstevel@tonic-gate logerr("wrote %s %d chars, ret=%d\n", 6947c478bd9Sstevel@tonic-gate sendaddress, packetlen, cc); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* 7017c478bd9Sstevel@tonic-gate * P R _ T Y P E 7027c478bd9Sstevel@tonic-gate * 7037c478bd9Sstevel@tonic-gate * Convert an ICMP "type" field to a printable string. 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate char * 7067c478bd9Sstevel@tonic-gate pr_type(int t) 7077c478bd9Sstevel@tonic-gate { 7087c478bd9Sstevel@tonic-gate static char *ttab[] = { 7097c478bd9Sstevel@tonic-gate "Echo Reply", 7107c478bd9Sstevel@tonic-gate "ICMP 1", 7117c478bd9Sstevel@tonic-gate "ICMP 2", 7127c478bd9Sstevel@tonic-gate "Dest Unreachable", 7137c478bd9Sstevel@tonic-gate "Source Quench", 7147c478bd9Sstevel@tonic-gate "Redirect", 7157c478bd9Sstevel@tonic-gate "ICMP 6", 7167c478bd9Sstevel@tonic-gate "ICMP 7", 7177c478bd9Sstevel@tonic-gate "Echo", 7187c478bd9Sstevel@tonic-gate "Router Advertise", 7197c478bd9Sstevel@tonic-gate "Router Solicitation", 7207c478bd9Sstevel@tonic-gate "Time Exceeded", 7217c478bd9Sstevel@tonic-gate "Parameter Problem", 7227c478bd9Sstevel@tonic-gate "Timestamp", 7237c478bd9Sstevel@tonic-gate "Timestamp Reply", 7247c478bd9Sstevel@tonic-gate "Info Request", 7257c478bd9Sstevel@tonic-gate "Info Reply", 7267c478bd9Sstevel@tonic-gate "Netmask Request", 7277c478bd9Sstevel@tonic-gate "Netmask Reply" 7287c478bd9Sstevel@tonic-gate }; 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate if (t < 0 || t > 16) 7317c478bd9Sstevel@tonic-gate return ("OUT-OF-RANGE"); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate return (ttab[t]); 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate /* 7377c478bd9Sstevel@tonic-gate * P R _ N A M E 7387c478bd9Sstevel@tonic-gate * 7397c478bd9Sstevel@tonic-gate * Return a string name for the given IP address. 7407c478bd9Sstevel@tonic-gate */ 7417c478bd9Sstevel@tonic-gate char * 7427c478bd9Sstevel@tonic-gate pr_name(struct in_addr addr) 7437c478bd9Sstevel@tonic-gate { 7447c478bd9Sstevel@tonic-gate struct hostent *phe; 7457c478bd9Sstevel@tonic-gate static char buf[256]; 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate phe = gethostbyaddr((char *)&addr.s_addr, 4, AF_INET); 7487c478bd9Sstevel@tonic-gate if (phe == NULL) 7497c478bd9Sstevel@tonic-gate return (inet_ntoa(addr)); 7507c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%s (%s)", phe->h_name, inet_ntoa(addr)); 7517c478bd9Sstevel@tonic-gate return (buf); 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate /* 7557c478bd9Sstevel@tonic-gate * P R _ P A C K 7567c478bd9Sstevel@tonic-gate * 7577c478bd9Sstevel@tonic-gate * Print out the packet, if it came from us. This logic is necessary 7587c478bd9Sstevel@tonic-gate * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 7597c478bd9Sstevel@tonic-gate * which arrive ('tis only fair). This permits multiple copies of this 7607c478bd9Sstevel@tonic-gate * program to be run without having intermingled output (or statistics!). 7617c478bd9Sstevel@tonic-gate */ 7627c478bd9Sstevel@tonic-gate static void 7637c478bd9Sstevel@tonic-gate pr_pack(char *buf, int cc, struct sockaddr_in *from) 7647c478bd9Sstevel@tonic-gate { 7657c478bd9Sstevel@tonic-gate struct ip *ip; 7667c478bd9Sstevel@tonic-gate register struct icmp *icp; 7677c478bd9Sstevel@tonic-gate register int i; 7687c478bd9Sstevel@tonic-gate int hlen; 7697c478bd9Sstevel@tonic-gate struct logint *li; 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate ip = (struct ip *)ALIGN(buf); 7727c478bd9Sstevel@tonic-gate hlen = ip->ip_hl << 2; 7737c478bd9Sstevel@tonic-gate if (cc < hlen + ICMP_MINLEN) { 7747c478bd9Sstevel@tonic-gate if (verbose) 7757c478bd9Sstevel@tonic-gate logtrace("packet too short (%d bytes) from %s\n", cc, 7767c478bd9Sstevel@tonic-gate pr_name(from->sin_addr)); 7777c478bd9Sstevel@tonic-gate return; 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate cc -= hlen; 7817c478bd9Sstevel@tonic-gate icp = (struct icmp *)ALIGN(buf + hlen); 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* 7847c478bd9Sstevel@tonic-gate * Let's check if IFF_NORTEXCH flag is set on the interface which 7857c478bd9Sstevel@tonic-gate * recevied this packet. 7867c478bd9Sstevel@tonic-gate * TODO: this code can be re-written using one socket per interface 7877c478bd9Sstevel@tonic-gate * to determine which interface the packet is recevied. 7887c478bd9Sstevel@tonic-gate */ 7897c478bd9Sstevel@tonic-gate li = find_directly_connected_logint(ip->ip_src, NULL); 7907c478bd9Sstevel@tonic-gate if (li != NULL && (li->li_flags & IFF_NORTEXCH)) { 7917c478bd9Sstevel@tonic-gate if (verbose) { 7927c478bd9Sstevel@tonic-gate logtrace("Ignoring received %s on %s " 7937c478bd9Sstevel@tonic-gate "(no route exchange on interface)", 7947c478bd9Sstevel@tonic-gate pr_type((int)icp->icmp_type), li->li_name); 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate return; 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate if (ip->ip_p == 0) { 8007c478bd9Sstevel@tonic-gate /* 8017c478bd9Sstevel@tonic-gate * Assume that we are running on a pre-4.3BSD system 8027c478bd9Sstevel@tonic-gate * such as SunOS before 4.0 8037c478bd9Sstevel@tonic-gate */ 8047c478bd9Sstevel@tonic-gate icp = (struct icmp *)ALIGN(buf); 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate switch (icp->icmp_type) { 8077c478bd9Sstevel@tonic-gate case ICMP_ROUTERADVERT: { 8087c478bd9Sstevel@tonic-gate struct icmp_ra *rap = (struct icmp_ra *)ALIGN(icp); 8097c478bd9Sstevel@tonic-gate struct icmp_ra_addr *ap; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate if (responder) 8127c478bd9Sstevel@tonic-gate break; 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate /* TBD verify that the link is multicast or broadcast */ 8157c478bd9Sstevel@tonic-gate /* XXX Find out the link it came in over? */ 8167c478bd9Sstevel@tonic-gate #ifdef notdef 8177c478bd9Sstevel@tonic-gate if (debug) { 8187c478bd9Sstevel@tonic-gate logdebug("ROUTER_ADVERTISEMENT: \n"); 8197c478bd9Sstevel@tonic-gate pr_hex(buf+hlen, cc); 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate #endif /* notdef */ 8227c478bd9Sstevel@tonic-gate if (in_cksum((ushort_t *)ALIGN(buf+hlen), cc)) { 8237c478bd9Sstevel@tonic-gate if (verbose) 8247c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s: Bad checksum\n", 8257c478bd9Sstevel@tonic-gate pr_type((int)rap->icmp_type), 8267c478bd9Sstevel@tonic-gate pr_name(from->sin_addr)); 8277c478bd9Sstevel@tonic-gate return; 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate if (rap->icmp_code != 0) { 8307c478bd9Sstevel@tonic-gate if (verbose) 8317c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s: Code = %d\n", 8327c478bd9Sstevel@tonic-gate pr_type((int)rap->icmp_type), 8337c478bd9Sstevel@tonic-gate pr_name(from->sin_addr), 8347c478bd9Sstevel@tonic-gate rap->icmp_code); 8357c478bd9Sstevel@tonic-gate return; 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate if (rap->icmp_num_addrs < 1) { 8387c478bd9Sstevel@tonic-gate if (verbose) 8397c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s: No addresses\n", 8407c478bd9Sstevel@tonic-gate pr_type((int)rap->icmp_type), 8417c478bd9Sstevel@tonic-gate pr_name(from->sin_addr)); 8427c478bd9Sstevel@tonic-gate return; 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate if (rap->icmp_wpa < 2) { 8457c478bd9Sstevel@tonic-gate if (verbose) 8467c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s: Words/addr = %d\n", 8477c478bd9Sstevel@tonic-gate pr_type((int)rap->icmp_type), 8487c478bd9Sstevel@tonic-gate pr_name(from->sin_addr), 8497c478bd9Sstevel@tonic-gate rap->icmp_wpa); 8507c478bd9Sstevel@tonic-gate return; 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate if ((unsigned)cc < 8537c478bd9Sstevel@tonic-gate ICMP_MINLEN + rap->icmp_num_addrs * rap->icmp_wpa * 4) { 8547c478bd9Sstevel@tonic-gate if (verbose) 8557c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s: Too short %d, %d\n", 8567c478bd9Sstevel@tonic-gate pr_type((int)rap->icmp_type), 8577c478bd9Sstevel@tonic-gate pr_name(from->sin_addr), 8587c478bd9Sstevel@tonic-gate cc, 8597c478bd9Sstevel@tonic-gate ICMP_MINLEN + 8607c478bd9Sstevel@tonic-gate rap->icmp_num_addrs * 8617c478bd9Sstevel@tonic-gate rap->icmp_wpa * 4); 8627c478bd9Sstevel@tonic-gate return; 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate rap->icmp_lifetime = ntohs(rap->icmp_lifetime); 8657c478bd9Sstevel@tonic-gate if ((rap->icmp_lifetime < 4 && rap->icmp_lifetime != 0) || 8667c478bd9Sstevel@tonic-gate rap->icmp_lifetime > 9000) { 8677c478bd9Sstevel@tonic-gate if (verbose) 8687c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s: Invalid lifetime %d\n", 8697c478bd9Sstevel@tonic-gate pr_type((int)rap->icmp_type), 8707c478bd9Sstevel@tonic-gate pr_name(from->sin_addr), 8717c478bd9Sstevel@tonic-gate rap->icmp_lifetime); 8727c478bd9Sstevel@tonic-gate return; 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate if (verbose) 8757c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s, lifetime %d\n", 8767c478bd9Sstevel@tonic-gate pr_type((int)rap->icmp_type), 8777c478bd9Sstevel@tonic-gate pr_name(from->sin_addr), 8787c478bd9Sstevel@tonic-gate rap->icmp_lifetime); 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate /* 8817c478bd9Sstevel@tonic-gate * Check that at least one router address is a neighbor 8827c478bd9Sstevel@tonic-gate * on the arriving link. 8837c478bd9Sstevel@tonic-gate */ 8847c478bd9Sstevel@tonic-gate for (i = 0; (unsigned)i < rap->icmp_num_addrs; i++) { 8857c478bd9Sstevel@tonic-gate struct in_addr ina; 8867c478bd9Sstevel@tonic-gate ap = (struct icmp_ra_addr *) 8877c478bd9Sstevel@tonic-gate ALIGN(buf + hlen + ICMP_MINLEN + 8887c478bd9Sstevel@tonic-gate i * rap->icmp_wpa * 4); 8897c478bd9Sstevel@tonic-gate ap->preference = ntohl(ap->preference); 8907c478bd9Sstevel@tonic-gate ina.s_addr = ap->addr; 8917c478bd9Sstevel@tonic-gate if (verbose) 8927c478bd9Sstevel@tonic-gate logtrace("\taddress %s, preference 0x%x\n", 8937c478bd9Sstevel@tonic-gate pr_name(ina), 8947c478bd9Sstevel@tonic-gate ap->preference); 8957c478bd9Sstevel@tonic-gate if (!responder) { 8967c478bd9Sstevel@tonic-gate if (find_directly_connected_logint(ina, NULL) != 8977c478bd9Sstevel@tonic-gate NULL) { 8987c478bd9Sstevel@tonic-gate record_router(ina, 8997c478bd9Sstevel@tonic-gate (long)ap->preference, 9007c478bd9Sstevel@tonic-gate rap->icmp_lifetime); 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate nreceived++; 9057c478bd9Sstevel@tonic-gate if (!forever) { 9067c478bd9Sstevel@tonic-gate (void) alarm(0); 9077c478bd9Sstevel@tonic-gate do_fork(); 9087c478bd9Sstevel@tonic-gate forever = 1; 9097c478bd9Sstevel@tonic-gate (void) alarm(TIMER_INTERVAL); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate break; 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate case ICMP_ROUTERSOLICIT: { 9157c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate if (!responder) 9187c478bd9Sstevel@tonic-gate break; 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate /* TBD verify that the link is multicast or broadcast */ 9217c478bd9Sstevel@tonic-gate /* XXX Find out the link it came in over? */ 9227c478bd9Sstevel@tonic-gate #ifdef notdef 9237c478bd9Sstevel@tonic-gate if (debug) { 9247c478bd9Sstevel@tonic-gate logdebug("ROUTER_SOLICITATION: \n"); 9257c478bd9Sstevel@tonic-gate pr_hex(buf+hlen, cc); 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate #endif /* notdef */ 9287c478bd9Sstevel@tonic-gate if (in_cksum((ushort_t *)ALIGN(buf+hlen), cc)) { 9297c478bd9Sstevel@tonic-gate if (verbose) 9307c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s: Bad checksum\n", 9317c478bd9Sstevel@tonic-gate pr_type((int)icp->icmp_type), 9327c478bd9Sstevel@tonic-gate pr_name(from->sin_addr)); 9337c478bd9Sstevel@tonic-gate return; 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate if (icp->icmp_code != 0) { 9367c478bd9Sstevel@tonic-gate if (verbose) 9377c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s: Code = %d\n", 9387c478bd9Sstevel@tonic-gate pr_type((int)icp->icmp_type), 9397c478bd9Sstevel@tonic-gate pr_name(from->sin_addr), 9407c478bd9Sstevel@tonic-gate icp->icmp_code); 9417c478bd9Sstevel@tonic-gate return; 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate if (cc < ICMP_MINLEN) { 9457c478bd9Sstevel@tonic-gate if (verbose) 9467c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s: Too short %d, %d\n", 9477c478bd9Sstevel@tonic-gate pr_type((int)icp->icmp_type), 9487c478bd9Sstevel@tonic-gate pr_name(from->sin_addr), 9497c478bd9Sstevel@tonic-gate cc, 9507c478bd9Sstevel@tonic-gate ICMP_MINLEN); 9517c478bd9Sstevel@tonic-gate return; 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate if (verbose) 9557c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s\n", 9567c478bd9Sstevel@tonic-gate pr_type((int)icp->icmp_type), 9577c478bd9Sstevel@tonic-gate pr_name(from->sin_addr)); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate if (!responder) 9607c478bd9Sstevel@tonic-gate break; 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate /* 9637c478bd9Sstevel@tonic-gate * Check that ip_src is either a neighbor 9647c478bd9Sstevel@tonic-gate * on the arriving link or 0. 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 9677c478bd9Sstevel@tonic-gate if (ip->ip_src.s_addr == 0) { 9687c478bd9Sstevel@tonic-gate /* 9697c478bd9Sstevel@tonic-gate * If it was sent to the broadcast address we respond 9707c478bd9Sstevel@tonic-gate * to the broadcast address. 9717c478bd9Sstevel@tonic-gate */ 9727c478bd9Sstevel@tonic-gate if (IN_CLASSD(ntohl(ip->ip_dst.s_addr))) { 9737c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = 9747c478bd9Sstevel@tonic-gate htonl(INADDR_ALLHOSTS_GROUP); 9757c478bd9Sstevel@tonic-gate } else 9767c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); 9777c478bd9Sstevel@tonic-gate /* Restart the timer when we broadcast */ 9787c478bd9Sstevel@tonic-gate left_until_advertise = min_adv_int + 9797c478bd9Sstevel@tonic-gate ((max_adv_int - min_adv_int) 9807c478bd9Sstevel@tonic-gate * (random() % 1000)/1000); 9817c478bd9Sstevel@tonic-gate } else { 9827c478bd9Sstevel@tonic-gate if (li == NULL) { 9837c478bd9Sstevel@tonic-gate if (verbose) 9847c478bd9Sstevel@tonic-gate logtrace("ICMP %s from %s: %s\n", 9857c478bd9Sstevel@tonic-gate pr_type((int)icp->icmp_type), 9867c478bd9Sstevel@tonic-gate pr_name(from->sin_addr), 9877c478bd9Sstevel@tonic-gate "source not directly connected"); 9887c478bd9Sstevel@tonic-gate break; 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = ip->ip_src.s_addr; 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate nreceived++; 9937c478bd9Sstevel@tonic-gate ntransmitted++; 9947c478bd9Sstevel@tonic-gate advertise(&sin); 9957c478bd9Sstevel@tonic-gate break; 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate /* 10027c478bd9Sstevel@tonic-gate * I N _ C K S U M 10037c478bd9Sstevel@tonic-gate * 10047c478bd9Sstevel@tonic-gate * Checksum routine for Internet Protocol family headers (C Version) 10057c478bd9Sstevel@tonic-gate * 10067c478bd9Sstevel@tonic-gate */ 10077c478bd9Sstevel@tonic-gate int 10087c478bd9Sstevel@tonic-gate in_cksum(ushort_t *addr, int len) 10097c478bd9Sstevel@tonic-gate { 10107c478bd9Sstevel@tonic-gate register int nleft = len; 10117c478bd9Sstevel@tonic-gate register ushort_t *w = addr; 10127c478bd9Sstevel@tonic-gate register ushort_t answer; 10137c478bd9Sstevel@tonic-gate ushort_t odd_byte = 0; 10147c478bd9Sstevel@tonic-gate register int sum = 0; 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate /* 10177c478bd9Sstevel@tonic-gate * Our algorithm is simple, using a 32 bit accumulator (sum), 10187c478bd9Sstevel@tonic-gate * we add sequential 16 bit words to it, and at the end, fold 10197c478bd9Sstevel@tonic-gate * back all the carry bits from the top 16 bits into the lower 10207c478bd9Sstevel@tonic-gate * 16 bits. 10217c478bd9Sstevel@tonic-gate */ 10227c478bd9Sstevel@tonic-gate while (nleft > 1) { 10237c478bd9Sstevel@tonic-gate sum += *w++; 10247c478bd9Sstevel@tonic-gate nleft -= 2; 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* mop up an odd byte, if necessary */ 10287c478bd9Sstevel@tonic-gate if (nleft == 1) { 10297c478bd9Sstevel@tonic-gate *(uchar_t *)(&odd_byte) = *(uchar_t *)w; 10307c478bd9Sstevel@tonic-gate sum += odd_byte; 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate /* 10347c478bd9Sstevel@tonic-gate * add back carry outs from top 16 bits to low 16 bits 10357c478bd9Sstevel@tonic-gate */ 10367c478bd9Sstevel@tonic-gate sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 10377c478bd9Sstevel@tonic-gate sum += (sum >> 16); /* add carry */ 10387c478bd9Sstevel@tonic-gate answer = ~sum; /* truncate to 16 bits */ 10397c478bd9Sstevel@tonic-gate return (answer); 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate /* 10437c478bd9Sstevel@tonic-gate * F I N I S H 10447c478bd9Sstevel@tonic-gate * 10457c478bd9Sstevel@tonic-gate * Print out statistics, and give up. 10467c478bd9Sstevel@tonic-gate * Heavily buffered stdio is used here, so that all the statistics 10477c478bd9Sstevel@tonic-gate * will be written with 1 sys-write call. This is nice when more 10487c478bd9Sstevel@tonic-gate * than one copy of the program is running on a terminal; it prevents 10497c478bd9Sstevel@tonic-gate * the statistics output from becoming intermingled. 10507c478bd9Sstevel@tonic-gate */ 10517c478bd9Sstevel@tonic-gate static void 10527c478bd9Sstevel@tonic-gate finish(void) 10537c478bd9Sstevel@tonic-gate { 10547c478bd9Sstevel@tonic-gate if (responder) { 10557c478bd9Sstevel@tonic-gate /* 10567c478bd9Sstevel@tonic-gate * Send out a packet with a preference so that all 10577c478bd9Sstevel@tonic-gate * hosts will know that we are dead. 10587c478bd9Sstevel@tonic-gate */ 10597c478bd9Sstevel@tonic-gate logerr("terminated\n"); 10607c478bd9Sstevel@tonic-gate force_preference(IGNORE_PREFERENCE); 10617c478bd9Sstevel@tonic-gate ntransmitted++; 10627c478bd9Sstevel@tonic-gate advertise(&whereto); 10637c478bd9Sstevel@tonic-gate } 10647c478bd9Sstevel@tonic-gate if (verbose) { 10657c478bd9Sstevel@tonic-gate logtrace("\n----%s rdisc Statistics----\n", sendaddress); 10667c478bd9Sstevel@tonic-gate logtrace("%d packets transmitted, ", ntransmitted); 10677c478bd9Sstevel@tonic-gate logtrace("%d packets received, ", nreceived); 10687c478bd9Sstevel@tonic-gate logtrace("\n"); 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate (void) fflush(stdout); 10717c478bd9Sstevel@tonic-gate exit(0); 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate #include <ctype.h> 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate #ifdef notdef 10777c478bd9Sstevel@tonic-gate int 10787c478bd9Sstevel@tonic-gate pr_hex(unsigned char *data, int len) 10797c478bd9Sstevel@tonic-gate { 10807c478bd9Sstevel@tonic-gate FILE *out; 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate out = stdout; 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate while (len) { 10857c478bd9Sstevel@tonic-gate register int i; 10867c478bd9Sstevel@tonic-gate char charstring[17]; 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate (void) strcpy(charstring, " "); /* 16 spaces */ 10897c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) { 10907c478bd9Sstevel@tonic-gate /* 10917c478bd9Sstevel@tonic-gate * output the bytes one at a time, 10927c478bd9Sstevel@tonic-gate * not going past "len" bytes 10937c478bd9Sstevel@tonic-gate */ 10947c478bd9Sstevel@tonic-gate if (len) { 10957c478bd9Sstevel@tonic-gate char ch = *data & 0x7f; /* strip parity */ 10967c478bd9Sstevel@tonic-gate if (!isprint((uchar_t)ch)) 10977c478bd9Sstevel@tonic-gate ch = ' '; /* ensure printable */ 10987c478bd9Sstevel@tonic-gate charstring[i] = ch; 10997c478bd9Sstevel@tonic-gate (void) fprintf(out, "%02x ", *data++); 11007c478bd9Sstevel@tonic-gate len--; 11017c478bd9Sstevel@tonic-gate } else 11027c478bd9Sstevel@tonic-gate (void) fprintf(out, " "); 11037c478bd9Sstevel@tonic-gate if (i == 7) 11047c478bd9Sstevel@tonic-gate (void) fprintf(out, " "); 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate (void) fprintf(out, " *%s*\n", charstring); 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate #endif /* notdef */ 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate static int 11137c478bd9Sstevel@tonic-gate isbroadcast(struct sockaddr_in *sin) 11147c478bd9Sstevel@tonic-gate { 11157c478bd9Sstevel@tonic-gate return (sin->sin_addr.s_addr == htonl(INADDR_BROADCAST)); 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate static int 11197c478bd9Sstevel@tonic-gate ismulticast(struct sockaddr_in *sin) 11207c478bd9Sstevel@tonic-gate { 11217c478bd9Sstevel@tonic-gate return (IN_CLASSD(ntohl(sin->sin_addr.s_addr))); 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate /* From libc/rpc/pmap_rmt.c */ 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate /* Only send once per physical interface */ 11287c478bd9Sstevel@tonic-gate static int 11297c478bd9Sstevel@tonic-gate sendbcast(int s, char *packet, int packetlen) 11307c478bd9Sstevel@tonic-gate { 11317c478bd9Sstevel@tonic-gate struct phyint *pi; 11327c478bd9Sstevel@tonic-gate struct logint *li; 11337c478bd9Sstevel@tonic-gate boolean_t bcast; 11347c478bd9Sstevel@tonic-gate int cc; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate for (pi = phyint; pi != NULL; pi = pi->pi_next) { 11377c478bd9Sstevel@tonic-gate bcast = B_FALSE; 11387c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; li = li->li_next) { 11397c478bd9Sstevel@tonic-gate if (li->li_state & ST_DELETED) 11407c478bd9Sstevel@tonic-gate continue; 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate if (li->li_flags & IFF_BROADCAST) { 11437c478bd9Sstevel@tonic-gate bcast = B_TRUE; 11447c478bd9Sstevel@tonic-gate break; 11457c478bd9Sstevel@tonic-gate } 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate if (!bcast) 11487c478bd9Sstevel@tonic-gate continue; 11497c478bd9Sstevel@tonic-gate cc = sendbcastif(s, packet, packetlen, li); 11507c478bd9Sstevel@tonic-gate if (cc != packetlen) { 11517c478bd9Sstevel@tonic-gate return (cc); 11527c478bd9Sstevel@tonic-gate } 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate return (packetlen); 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate static int 11587c478bd9Sstevel@tonic-gate sendbcastif(int s, char *packet, int packetlen, struct logint *li) 11597c478bd9Sstevel@tonic-gate { 11607c478bd9Sstevel@tonic-gate int cc; 11617c478bd9Sstevel@tonic-gate struct sockaddr_in baddr; 11627c478bd9Sstevel@tonic-gate struct icmp *icp = (struct icmp *)ALIGN(packet); 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate baddr.sin_family = AF_INET; 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate if ((li->li_flags & IFF_BROADCAST) == 0) { 11677c478bd9Sstevel@tonic-gate if (verbose) { 11687c478bd9Sstevel@tonic-gate logtrace("Suppressing sending %s on %s " 11697c478bd9Sstevel@tonic-gate "(interface is not broadcast capable)\n", 11707c478bd9Sstevel@tonic-gate pr_type((int)icp->icmp_type), li->li_name); 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate return (packetlen); 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate if (li->li_flags & IFF_NORTEXCH) { 11757c478bd9Sstevel@tonic-gate if (verbose) { 11767c478bd9Sstevel@tonic-gate logtrace("Suppressing sending %s on %s " 11777c478bd9Sstevel@tonic-gate "(no route exchange on interface)\n", 11787c478bd9Sstevel@tonic-gate pr_type((int)icp->icmp_type), li->li_name); 11797c478bd9Sstevel@tonic-gate } 11807c478bd9Sstevel@tonic-gate return (packetlen); 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate baddr.sin_addr = li->li_bcastaddr; 11847c478bd9Sstevel@tonic-gate if (debug) 11857c478bd9Sstevel@tonic-gate logdebug("Broadcast to %s\n", 11867c478bd9Sstevel@tonic-gate pr_name(baddr.sin_addr)); 11877c478bd9Sstevel@tonic-gate cc = sendto(s, packet, packetlen, 0, 11887c478bd9Sstevel@tonic-gate (struct sockaddr *)&baddr, sizeof (struct sockaddr)); 11897c478bd9Sstevel@tonic-gate if (cc != packetlen) { 11907c478bd9Sstevel@tonic-gate logperror("sendbcast: sendto"); 11917c478bd9Sstevel@tonic-gate logerr("Cannot send broadcast packet to %s\n", 11927c478bd9Sstevel@tonic-gate pr_name(baddr.sin_addr)); 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate return (cc); 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate static int 11987c478bd9Sstevel@tonic-gate sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *sin) 11997c478bd9Sstevel@tonic-gate { 12007c478bd9Sstevel@tonic-gate struct phyint *pi; 12017c478bd9Sstevel@tonic-gate struct logint *li; 12027c478bd9Sstevel@tonic-gate boolean_t mcast; 12037c478bd9Sstevel@tonic-gate int cc; 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate for (pi = phyint; pi != NULL; pi = pi->pi_next) { 12067c478bd9Sstevel@tonic-gate mcast = B_FALSE; 12077c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; li = li->li_next) { 12087c478bd9Sstevel@tonic-gate if (li->li_state & ST_DELETED) 12097c478bd9Sstevel@tonic-gate continue; 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate if (li->li_flags & IFF_MULTICAST) { 12127c478bd9Sstevel@tonic-gate mcast = B_TRUE; 12137c478bd9Sstevel@tonic-gate break; 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate } 12167c478bd9Sstevel@tonic-gate if (!mcast) 12177c478bd9Sstevel@tonic-gate continue; 12187c478bd9Sstevel@tonic-gate cc = sendmcastif(s, packet, packetlen, sin, li); 12197c478bd9Sstevel@tonic-gate if (cc != packetlen) { 12207c478bd9Sstevel@tonic-gate return (cc); 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate return (packetlen); 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate static int 12277c478bd9Sstevel@tonic-gate sendmcastif(int s, char *packet, int packetlen, struct sockaddr_in *sin, 12287c478bd9Sstevel@tonic-gate struct logint *li) 12297c478bd9Sstevel@tonic-gate { 12307c478bd9Sstevel@tonic-gate int cc; 12317c478bd9Sstevel@tonic-gate struct sockaddr_in ifaddr; 12327c478bd9Sstevel@tonic-gate struct icmp *icp = (struct icmp *)ALIGN(packet); 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate ifaddr.sin_family = AF_INET; 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate if ((li->li_flags & IFF_MULTICAST) == 0) { 12377c478bd9Sstevel@tonic-gate if (verbose) { 12387c478bd9Sstevel@tonic-gate logtrace("Suppressing sending %s on %s " 12397c478bd9Sstevel@tonic-gate "(interface is not multicast capable)\n", 12407c478bd9Sstevel@tonic-gate pr_type((int)icp->icmp_type), li->li_name); 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate return (packetlen); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate if (li->li_flags & IFF_NORTEXCH) { 12457c478bd9Sstevel@tonic-gate if (verbose) { 12467c478bd9Sstevel@tonic-gate logtrace("Suppressing sending %s on %s " 12477c478bd9Sstevel@tonic-gate "(no route exchange on interface)\n", 12487c478bd9Sstevel@tonic-gate pr_type((int)icp->icmp_type), li->li_name); 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate return (packetlen); 12517c478bd9Sstevel@tonic-gate } 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate ifaddr.sin_addr = li->li_address; 12547c478bd9Sstevel@tonic-gate if (debug) 12557c478bd9Sstevel@tonic-gate logdebug("Multicast to interface %s\n", 12567c478bd9Sstevel@tonic-gate pr_name(ifaddr.sin_addr)); 12577c478bd9Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, 12587c478bd9Sstevel@tonic-gate (char *)&ifaddr.sin_addr, 12597c478bd9Sstevel@tonic-gate sizeof (ifaddr.sin_addr)) < 0) { 12607c478bd9Sstevel@tonic-gate logperror("setsockopt (IP_MULTICAST_IF)"); 12617c478bd9Sstevel@tonic-gate logerr("Cannot send multicast packet over interface %s\n", 12627c478bd9Sstevel@tonic-gate pr_name(ifaddr.sin_addr)); 12637c478bd9Sstevel@tonic-gate return (-1); 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate cc = sendto(s, packet, packetlen, 0, 12667c478bd9Sstevel@tonic-gate (struct sockaddr *)sin, sizeof (struct sockaddr)); 12677c478bd9Sstevel@tonic-gate if (cc != packetlen) { 12687c478bd9Sstevel@tonic-gate logperror("sendmcast: sendto"); 12697c478bd9Sstevel@tonic-gate logerr("Cannot send multicast packet over interface %s\n", 12707c478bd9Sstevel@tonic-gate pr_name(ifaddr.sin_addr)); 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate return (cc); 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate static void 12767c478bd9Sstevel@tonic-gate reinitifs(void) 12777c478bd9Sstevel@tonic-gate { 12787c478bd9Sstevel@tonic-gate (void) initifs(s, &g_joinaddr, g_preference); 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate static void 12827c478bd9Sstevel@tonic-gate force_preference(int preference) 12837c478bd9Sstevel@tonic-gate { 12847c478bd9Sstevel@tonic-gate struct phyint *pi; 12857c478bd9Sstevel@tonic-gate struct logint *li; 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate for (pi = phyint; pi != NULL; pi = pi->pi_next) { 12887c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; li = li->li_next) { 12897c478bd9Sstevel@tonic-gate if (li->li_state & ST_DELETED) 12907c478bd9Sstevel@tonic-gate continue; 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate li->li_preference = preference; 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate /* 12987c478bd9Sstevel@tonic-gate * Returns -1 on failure. 12997c478bd9Sstevel@tonic-gate */ 13007c478bd9Sstevel@tonic-gate static int 13017c478bd9Sstevel@tonic-gate initifs(int s, struct sockaddr_in *joinaddr, int preference) 13027c478bd9Sstevel@tonic-gate { 13037c478bd9Sstevel@tonic-gate struct ifconf ifc; 13047c478bd9Sstevel@tonic-gate struct ifreq ifreq, *ifr; 13057c478bd9Sstevel@tonic-gate struct lifreq lifreq; 13067c478bd9Sstevel@tonic-gate int n; 13077c478bd9Sstevel@tonic-gate char *buf; 13087c478bd9Sstevel@tonic-gate int numifs; 13097c478bd9Sstevel@tonic-gate unsigned bufsize; 13107c478bd9Sstevel@tonic-gate struct phyint *pi; 13117c478bd9Sstevel@tonic-gate struct logint *li; 13127c478bd9Sstevel@tonic-gate int num_deletions; 13137c478bd9Sstevel@tonic-gate char phyintname[IFNAMSIZ]; 13147c478bd9Sstevel@tonic-gate char *cp; 13157c478bd9Sstevel@tonic-gate int old_num_usable_interfaces = num_usable_interfaces; 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate /* 13187c478bd9Sstevel@tonic-gate * Mark all interfaces so that we can determine which ones 13197c478bd9Sstevel@tonic-gate * have gone away. 13207c478bd9Sstevel@tonic-gate */ 13217c478bd9Sstevel@tonic-gate for (pi = phyint; pi != NULL; pi = pi->pi_next) { 13227c478bd9Sstevel@tonic-gate pi->pi_state |= ST_MARKED; 13237c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; li = li->li_next) { 13247c478bd9Sstevel@tonic-gate li->li_state |= ST_MARKED; 13257c478bd9Sstevel@tonic-gate } 13267c478bd9Sstevel@tonic-gate } 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate if (sock < 0) { 13297c478bd9Sstevel@tonic-gate sock = socket(AF_INET, SOCK_DGRAM, 0); 13307c478bd9Sstevel@tonic-gate if (sock < 0) { 13317c478bd9Sstevel@tonic-gate logperror("initifs: socket"); 13327c478bd9Sstevel@tonic-gate return (-1); 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate #ifdef SIOCGIFNUM 13367c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) { 13377c478bd9Sstevel@tonic-gate logperror("initifs: SIOCGIFNUM"); 13387c478bd9Sstevel@tonic-gate return (-1); 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate #else 13417c478bd9Sstevel@tonic-gate numifs = MAXIFS; 13427c478bd9Sstevel@tonic-gate #endif 13437c478bd9Sstevel@tonic-gate bufsize = numifs * sizeof (struct ifreq); 13447c478bd9Sstevel@tonic-gate buf = (char *)malloc(bufsize); 13457c478bd9Sstevel@tonic-gate if (buf == NULL) { 13467c478bd9Sstevel@tonic-gate logerr("out of memory\n"); 13477c478bd9Sstevel@tonic-gate (void) close(sock); 13487c478bd9Sstevel@tonic-gate sock = -1; 13497c478bd9Sstevel@tonic-gate return (-1); 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate ifc.ifc_len = bufsize; 13527c478bd9Sstevel@tonic-gate ifc.ifc_buf = buf; 13537c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { 13547c478bd9Sstevel@tonic-gate logperror("initifs: ioctl (get interface configuration)"); 13557c478bd9Sstevel@tonic-gate (void) close(sock); 13567c478bd9Sstevel@tonic-gate sock = -1; 13577c478bd9Sstevel@tonic-gate (void) free(buf); 13587c478bd9Sstevel@tonic-gate return (-1); 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate ifr = ifc.ifc_req; 13617c478bd9Sstevel@tonic-gate for (n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) { 13627c478bd9Sstevel@tonic-gate ifreq = *ifr; 13637c478bd9Sstevel@tonic-gate /* 13647c478bd9Sstevel@tonic-gate * We need to use new interface ioctls to get 64-bit flags. 13657c478bd9Sstevel@tonic-gate */ 13667c478bd9Sstevel@tonic-gate (void) strncpy(lifreq.lifr_name, ifr->ifr_name, 13677c478bd9Sstevel@tonic-gate sizeof (ifr->ifr_name)); 13687c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) { 13697c478bd9Sstevel@tonic-gate logperror("initifs: ioctl (get interface flags)"); 13707c478bd9Sstevel@tonic-gate continue; 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate if (ifr->ifr_addr.sa_family != AF_INET) 13737c478bd9Sstevel@tonic-gate continue; 13747c478bd9Sstevel@tonic-gate if ((lifreq.lifr_flags & IFF_UP) == 0) 13757c478bd9Sstevel@tonic-gate continue; 13767c478bd9Sstevel@tonic-gate if (lifreq.lifr_flags & IFF_LOOPBACK) 13777c478bd9Sstevel@tonic-gate continue; 13787c478bd9Sstevel@tonic-gate if ((lifreq.lifr_flags & (IFF_MULTICAST | IFF_BROADCAST)) == 0) 13797c478bd9Sstevel@tonic-gate continue; 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* Create the physical name by truncating at the ':' */ 13827c478bd9Sstevel@tonic-gate strncpy(phyintname, ifreq.ifr_name, sizeof (phyintname)); 13837c478bd9Sstevel@tonic-gate if ((cp = strchr(phyintname, ':')) != NULL) 13847c478bd9Sstevel@tonic-gate *cp = '\0'; 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate pi = find_phyint(phyintname); 13877c478bd9Sstevel@tonic-gate if (pi == NULL) { 13887c478bd9Sstevel@tonic-gate pi = add_phyint(phyintname); 13897c478bd9Sstevel@tonic-gate if (pi == NULL) { 13907c478bd9Sstevel@tonic-gate logerr("out of memory\n"); 13917c478bd9Sstevel@tonic-gate (void) close(sock); 13927c478bd9Sstevel@tonic-gate sock = -1; 13937c478bd9Sstevel@tonic-gate (void) free(buf); 13947c478bd9Sstevel@tonic-gate return (-1); 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate } 13977c478bd9Sstevel@tonic-gate pi->pi_state &= ~ST_MARKED; 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate li = find_logint(pi, ifreq.ifr_name); 14007c478bd9Sstevel@tonic-gate if (li != NULL) { 14017c478bd9Sstevel@tonic-gate /* 14027c478bd9Sstevel@tonic-gate * Detect significant changes. 14037c478bd9Sstevel@tonic-gate * We treat netmask changes as insignificant but all 14047c478bd9Sstevel@tonic-gate * other changes cause a delete plus add of the 14057c478bd9Sstevel@tonic-gate * logical interface. 14067c478bd9Sstevel@tonic-gate * Note: if the flags and localaddr are unchanged 14077c478bd9Sstevel@tonic-gate * then nothing but the netmask and the broadcast 14087c478bd9Sstevel@tonic-gate * address could have changed since the other addresses 14097c478bd9Sstevel@tonic-gate * are derived from the flags and the localaddr. 14107c478bd9Sstevel@tonic-gate */ 14117c478bd9Sstevel@tonic-gate struct logint newli; 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate if (!getconfig(sock, lifreq.lifr_flags, &ifr->ifr_addr, 14147c478bd9Sstevel@tonic-gate &ifreq, &newli)) { 14157c478bd9Sstevel@tonic-gate free_logint(li); 14167c478bd9Sstevel@tonic-gate continue; 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate if (newli.li_flags != li->li_flags || 14207c478bd9Sstevel@tonic-gate newli.li_localaddr.s_addr != 14217c478bd9Sstevel@tonic-gate li->li_localaddr.s_addr || newli.li_index != 14227c478bd9Sstevel@tonic-gate li->li_index) { 14237c478bd9Sstevel@tonic-gate /* Treat as an interface deletion + addition */ 14247c478bd9Sstevel@tonic-gate li->li_state |= ST_DELETED; 14257c478bd9Sstevel@tonic-gate deleted_logint(li, &newli, s, joinaddr); 14267c478bd9Sstevel@tonic-gate free_logint(li); 14277c478bd9Sstevel@tonic-gate li = NULL; /* li recreated below */ 14287c478bd9Sstevel@tonic-gate } else { 14297c478bd9Sstevel@tonic-gate /* 14307c478bd9Sstevel@tonic-gate * No significant changes. 14317c478bd9Sstevel@tonic-gate * Just update the netmask, and broadcast. 14327c478bd9Sstevel@tonic-gate */ 14337c478bd9Sstevel@tonic-gate li->li_netmask = newli.li_netmask; 14347c478bd9Sstevel@tonic-gate li->li_bcastaddr = newli.li_bcastaddr; 14357c478bd9Sstevel@tonic-gate } 14367c478bd9Sstevel@tonic-gate } 14377c478bd9Sstevel@tonic-gate if (li == NULL) { 14387c478bd9Sstevel@tonic-gate li = add_logint(pi, ifreq.ifr_name); 14397c478bd9Sstevel@tonic-gate if (li == NULL) { 14407c478bd9Sstevel@tonic-gate logerr("out of memory\n"); 14417c478bd9Sstevel@tonic-gate (void) close(sock); 14427c478bd9Sstevel@tonic-gate sock = -1; 14437c478bd9Sstevel@tonic-gate (void) free(buf); 14447c478bd9Sstevel@tonic-gate return (-1); 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate /* init li */ 14487c478bd9Sstevel@tonic-gate if (!getconfig(sock, lifreq.lifr_flags, &ifr->ifr_addr, 14497c478bd9Sstevel@tonic-gate &ifreq, li)) { 14507c478bd9Sstevel@tonic-gate free_logint(li); 14517c478bd9Sstevel@tonic-gate continue; 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate li->li_preference = preference; 14547c478bd9Sstevel@tonic-gate added_logint(li, s, joinaddr); 14557c478bd9Sstevel@tonic-gate } 14567c478bd9Sstevel@tonic-gate li->li_state &= ~ST_MARKED; 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate (void) free(buf); 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate /* 14617c478bd9Sstevel@tonic-gate * Determine which interfaces have gone away. 14627c478bd9Sstevel@tonic-gate * The deletion is done in three phases: 14637c478bd9Sstevel@tonic-gate * 1. Mark ST_DELETED 14647c478bd9Sstevel@tonic-gate * 2. Inform using the deleted_* function. 14657c478bd9Sstevel@tonic-gate * 3. Unlink and free the actual memory. 14667c478bd9Sstevel@tonic-gate * Note that for #3 the physical interface must be deleted after 14677c478bd9Sstevel@tonic-gate * the logical ones. 14687c478bd9Sstevel@tonic-gate * Also count the number of physical interfaces. 14697c478bd9Sstevel@tonic-gate */ 14707c478bd9Sstevel@tonic-gate num_usable_interfaces = 0; 14717c478bd9Sstevel@tonic-gate num_deletions = 0; 14727c478bd9Sstevel@tonic-gate for (pi = phyint; pi != NULL; pi = pi->pi_next) { 14737c478bd9Sstevel@tonic-gate if (pi->pi_state & ST_MARKED) { 14747c478bd9Sstevel@tonic-gate num_deletions++; 14757c478bd9Sstevel@tonic-gate pi->pi_state |= ST_DELETED; 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; li = li->li_next) { 14787c478bd9Sstevel@tonic-gate if (li->li_state & ST_MARKED) { 14797c478bd9Sstevel@tonic-gate num_deletions++; 14807c478bd9Sstevel@tonic-gate li->li_state |= ST_DELETED; 14817c478bd9Sstevel@tonic-gate } 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate if (!(pi->pi_state & ST_DELETED)) 14847c478bd9Sstevel@tonic-gate num_usable_interfaces++; 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate if (num_deletions != 0) { 14877c478bd9Sstevel@tonic-gate struct phyint *nextpi; 14887c478bd9Sstevel@tonic-gate struct logint *nextli; 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate for (pi = phyint; pi != NULL; pi = pi->pi_next) { 14917c478bd9Sstevel@tonic-gate if (pi->pi_state & ST_DELETED) { 14927c478bd9Sstevel@tonic-gate /* 14937c478bd9Sstevel@tonic-gate * By deleting the physical interface pi, all of 14947c478bd9Sstevel@tonic-gate * the corresponding logical interfaces will 14957c478bd9Sstevel@tonic-gate * also be deleted so there is no need to delete 14967c478bd9Sstevel@tonic-gate * them individually. 14977c478bd9Sstevel@tonic-gate */ 14987c478bd9Sstevel@tonic-gate deleted_phyint(pi, s, joinaddr); 14997c478bd9Sstevel@tonic-gate } else { 15007c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; 15017c478bd9Sstevel@tonic-gate li = li->li_next) { 15027c478bd9Sstevel@tonic-gate if (li->li_state & ST_DELETED) { 15037c478bd9Sstevel@tonic-gate deleted_logint(li, NULL, s, 15047c478bd9Sstevel@tonic-gate joinaddr); 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate } 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate /* Do the actual linked list update + free */ 15107c478bd9Sstevel@tonic-gate for (pi = phyint; pi != NULL; pi = nextpi) { 15117c478bd9Sstevel@tonic-gate nextpi = pi->pi_next; 15127c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; 15137c478bd9Sstevel@tonic-gate li = nextli) { 15147c478bd9Sstevel@tonic-gate nextli = li->li_next; 15157c478bd9Sstevel@tonic-gate if (li->li_state & ST_DELETED) 15167c478bd9Sstevel@tonic-gate free_logint(li); 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate if (pi->pi_state & ST_DELETED) 15197c478bd9Sstevel@tonic-gate free_phyint(pi); 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate } 15227c478bd9Sstevel@tonic-gate /* 15237c478bd9Sstevel@tonic-gate * When the set of available interfaces goes from zero to 15247c478bd9Sstevel@tonic-gate * non-zero we restart solicitations if '-s' was specified. 15257c478bd9Sstevel@tonic-gate */ 15267c478bd9Sstevel@tonic-gate if (old_num_usable_interfaces == 0 && num_usable_interfaces > 0 && 15277c478bd9Sstevel@tonic-gate start_solicit && !solicit) { 15287c478bd9Sstevel@tonic-gate if (debug) 15297c478bd9Sstevel@tonic-gate logdebug("switching to solicitations: num if %d\n", 15307c478bd9Sstevel@tonic-gate num_usable_interfaces); 15317c478bd9Sstevel@tonic-gate solicit = start_solicit; 15327c478bd9Sstevel@tonic-gate ntransmitted = 0; 15337c478bd9Sstevel@tonic-gate ntransmitted++; 15347c478bd9Sstevel@tonic-gate solicitor(&whereto); 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate return (0); 15377c478bd9Sstevel@tonic-gate } 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate static boolean_t 15407c478bd9Sstevel@tonic-gate getconfig(int sock, uint64_t if_flags, struct sockaddr *addr, 15417c478bd9Sstevel@tonic-gate struct ifreq *ifr, struct logint *li) 15427c478bd9Sstevel@tonic-gate { 15437c478bd9Sstevel@tonic-gate struct ifreq ifreq; 15447c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 15457c478bd9Sstevel@tonic-gate struct lifreq lifreq; 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate ifreq = *ifr; /* Copy name etc */ 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate li->li_flags = if_flags; 15507c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)ALIGN(addr); 15517c478bd9Sstevel@tonic-gate li->li_localaddr = sin->sin_addr; 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate (void) strlcpy(lifreq.lifr_name, ifr->ifr_name, 15547c478bd9Sstevel@tonic-gate sizeof (lifreq.lifr_name)); 15557c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFINDEX, &lifreq) < 0) { 15567c478bd9Sstevel@tonic-gate logperror("initifs: ioctl (get if index)"); 15577c478bd9Sstevel@tonic-gate /* Continue with 0; a safe value never used for interfaces */ 15587c478bd9Sstevel@tonic-gate li->li_index = 0; 15597c478bd9Sstevel@tonic-gate } else { 15607c478bd9Sstevel@tonic-gate li->li_index = lifreq.lifr_index; 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate if (if_flags & IFF_POINTOPOINT) { 15647c478bd9Sstevel@tonic-gate li->li_netmask.s_addr = (unsigned long)0xffffffff; 15657c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { 15667c478bd9Sstevel@tonic-gate logperror("initifs: ioctl (get dest addr)"); 15677c478bd9Sstevel@tonic-gate return (B_FALSE); 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate /* A pt-pt link is identified by the remote address */ 15707c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr); 15717c478bd9Sstevel@tonic-gate li->li_address = sin->sin_addr; 15727c478bd9Sstevel@tonic-gate li->li_remoteaddr = sin->sin_addr; 15737c478bd9Sstevel@tonic-gate /* Simulate broadcast for pt-pt */ 15747c478bd9Sstevel@tonic-gate li->li_bcastaddr = sin->sin_addr; 15757c478bd9Sstevel@tonic-gate li->li_flags |= IFF_BROADCAST; 15767c478bd9Sstevel@tonic-gate } else { 15777c478bd9Sstevel@tonic-gate /* 15787c478bd9Sstevel@tonic-gate * Non pt-pt links are identified by the local 15797c478bd9Sstevel@tonic-gate * address 15807c478bd9Sstevel@tonic-gate */ 15817c478bd9Sstevel@tonic-gate li->li_address = li->li_localaddr; 15827c478bd9Sstevel@tonic-gate li->li_remoteaddr = li->li_address; 15837c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) { 15847c478bd9Sstevel@tonic-gate logperror("initifs: ioctl (get netmask)"); 15857c478bd9Sstevel@tonic-gate return (B_FALSE); 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr); 15887c478bd9Sstevel@tonic-gate li->li_netmask = sin->sin_addr; 15897c478bd9Sstevel@tonic-gate if (if_flags & IFF_BROADCAST) { 15907c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 15917c478bd9Sstevel@tonic-gate logperror( 15927c478bd9Sstevel@tonic-gate "initifs: ioctl (get broadcast address)"); 15937c478bd9Sstevel@tonic-gate return (B_FALSE); 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)ALIGN(&ifreq.ifr_addr); 15967c478bd9Sstevel@tonic-gate li->li_bcastaddr = sin->sin_addr; 15977c478bd9Sstevel@tonic-gate } 15987c478bd9Sstevel@tonic-gate } 15997c478bd9Sstevel@tonic-gate return (B_TRUE); 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate static int 16047c478bd9Sstevel@tonic-gate support_multicast(void) 16057c478bd9Sstevel@tonic-gate { 16067c478bd9Sstevel@tonic-gate int sock; 16077c478bd9Sstevel@tonic-gate uchar_t ttl = 1; 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 16107c478bd9Sstevel@tonic-gate if (sock < 0) { 16117c478bd9Sstevel@tonic-gate logperror("support_multicast: socket"); 16127c478bd9Sstevel@tonic-gate return (0); 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, 16167c478bd9Sstevel@tonic-gate (char *)&ttl, sizeof (ttl)) < 0) { 16177c478bd9Sstevel@tonic-gate (void) close(sock); 16187c478bd9Sstevel@tonic-gate return (0); 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate (void) close(sock); 16217c478bd9Sstevel@tonic-gate return (1); 16227c478bd9Sstevel@tonic-gate } 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate /* 16257c478bd9Sstevel@tonic-gate * For a given destination address, find the logical interface to use. 16267c478bd9Sstevel@tonic-gate * If opi is NULL check all interfaces. Otherwise just match against 16277c478bd9Sstevel@tonic-gate * the specified physical interface. 16287c478bd9Sstevel@tonic-gate * Return logical interface if there's a match, NULL otherwise. 16297c478bd9Sstevel@tonic-gate */ 16307c478bd9Sstevel@tonic-gate static struct logint * 16317c478bd9Sstevel@tonic-gate find_directly_connected_logint(struct in_addr in, struct phyint *opi) 16327c478bd9Sstevel@tonic-gate { 16337c478bd9Sstevel@tonic-gate struct phyint *pi; 16347c478bd9Sstevel@tonic-gate struct logint *li; 16357c478bd9Sstevel@tonic-gate 16367c478bd9Sstevel@tonic-gate if (opi == NULL) 16377c478bd9Sstevel@tonic-gate pi = phyint; 16387c478bd9Sstevel@tonic-gate else 16397c478bd9Sstevel@tonic-gate pi = opi; 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate for (; pi != NULL; pi = pi->pi_next) { 16427c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; li = li->li_next) { 16437c478bd9Sstevel@tonic-gate if (li->li_state & ST_DELETED) 16447c478bd9Sstevel@tonic-gate continue; 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate /* Check that the subnetwork numbers match */ 16477c478bd9Sstevel@tonic-gate if ((in.s_addr & li->li_netmask.s_addr) == 16487c478bd9Sstevel@tonic-gate (li->li_remoteaddr.s_addr & 16497c478bd9Sstevel@tonic-gate li->li_netmask.s_addr)) 16507c478bd9Sstevel@tonic-gate return (li); 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate if (opi != NULL) 16537c478bd9Sstevel@tonic-gate break; 16547c478bd9Sstevel@tonic-gate } 16557c478bd9Sstevel@tonic-gate return (NULL); 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate /* 16597c478bd9Sstevel@tonic-gate * INTERFACES - physical and logical identified by name 16607c478bd9Sstevel@tonic-gate */ 16617c478bd9Sstevel@tonic-gate 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate static void 16647c478bd9Sstevel@tonic-gate report_interfaces(void) 16657c478bd9Sstevel@tonic-gate { 16667c478bd9Sstevel@tonic-gate struct phyint *pi; 16677c478bd9Sstevel@tonic-gate struct logint *li; 16687c478bd9Sstevel@tonic-gate 16697c478bd9Sstevel@tonic-gate logdebug("\nInterfaces:\n\n"); 16707c478bd9Sstevel@tonic-gate for (pi = phyint; pi != NULL; pi = pi->pi_next) { 16717c478bd9Sstevel@tonic-gate logdebug("Phyint %s state 0x%x\n", 16727c478bd9Sstevel@tonic-gate pi->pi_name, pi->pi_state); 16737c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; li = li->li_next) { 16747c478bd9Sstevel@tonic-gate logdebug("IF %s state 0x%x, flags 0x%x, addr %s\n", 16757c478bd9Sstevel@tonic-gate li->li_name, li->li_state, li->li_flags, 16767c478bd9Sstevel@tonic-gate pr_name(li->li_address)); 16777c478bd9Sstevel@tonic-gate logdebug("\tlocal %s pref 0x%x ", 16787c478bd9Sstevel@tonic-gate pr_name(li->li_localaddr), li->li_preference); 16797c478bd9Sstevel@tonic-gate logdebug("bcast %s\n", 16807c478bd9Sstevel@tonic-gate pr_name(li->li_bcastaddr)); 16817c478bd9Sstevel@tonic-gate logdebug("\tremote %s ", 16827c478bd9Sstevel@tonic-gate pr_name(li->li_remoteaddr)); 16837c478bd9Sstevel@tonic-gate logdebug("netmask %s\n", 16847c478bd9Sstevel@tonic-gate pr_name(li->li_netmask)); 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate } 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate static struct phyint * 16907c478bd9Sstevel@tonic-gate find_phyint(char *name) 16917c478bd9Sstevel@tonic-gate { 16927c478bd9Sstevel@tonic-gate struct phyint *pi; 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate for (pi = phyint; pi != NULL; pi = pi->pi_next) { 16957c478bd9Sstevel@tonic-gate if (strcmp(pi->pi_name, name) == 0) 16967c478bd9Sstevel@tonic-gate return (pi); 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate return (NULL); 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate /* Assumes that the entry does not exist - caller must use find_* */ 17027c478bd9Sstevel@tonic-gate static struct phyint * 17037c478bd9Sstevel@tonic-gate add_phyint(char *name) 17047c478bd9Sstevel@tonic-gate { 17057c478bd9Sstevel@tonic-gate struct phyint *pi; 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate pi = malloc(sizeof (*pi)); 17087c478bd9Sstevel@tonic-gate if (pi == NULL) 17097c478bd9Sstevel@tonic-gate return (NULL); 17107c478bd9Sstevel@tonic-gate bzero((char *)pi, sizeof (*pi)); 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate strncpy(pi->pi_name, name, sizeof (pi->pi_name)); 17137c478bd9Sstevel@tonic-gate /* Link into list */ 17147c478bd9Sstevel@tonic-gate pi->pi_next = phyint; 17157c478bd9Sstevel@tonic-gate pi->pi_prev = NULL; 17167c478bd9Sstevel@tonic-gate if (phyint != NULL) 17177c478bd9Sstevel@tonic-gate phyint->pi_prev = pi; 17187c478bd9Sstevel@tonic-gate phyint = pi; 17197c478bd9Sstevel@tonic-gate return (pi); 17207c478bd9Sstevel@tonic-gate } 17217c478bd9Sstevel@tonic-gate 17227c478bd9Sstevel@tonic-gate static void 17237c478bd9Sstevel@tonic-gate free_phyint(struct phyint *pi) 17247c478bd9Sstevel@tonic-gate { 17257c478bd9Sstevel@tonic-gate assert(pi->pi_logical_first == NULL); 17267c478bd9Sstevel@tonic-gate assert(pi->pi_logical_last == NULL); 17277c478bd9Sstevel@tonic-gate 17287c478bd9Sstevel@tonic-gate if (pi->pi_prev == NULL) { 17297c478bd9Sstevel@tonic-gate /* Delete first */ 17307c478bd9Sstevel@tonic-gate assert(phyint == pi); 17317c478bd9Sstevel@tonic-gate phyint = pi->pi_next; 17327c478bd9Sstevel@tonic-gate } else { 17337c478bd9Sstevel@tonic-gate assert(pi->pi_prev->pi_next == pi); 17347c478bd9Sstevel@tonic-gate pi->pi_prev->pi_next = pi->pi_next; 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate if (pi->pi_next != NULL) { 17377c478bd9Sstevel@tonic-gate assert(pi->pi_next->pi_prev == pi); 17387c478bd9Sstevel@tonic-gate pi->pi_next->pi_prev = pi->pi_prev; 17397c478bd9Sstevel@tonic-gate } 17407c478bd9Sstevel@tonic-gate free(pi); 17417c478bd9Sstevel@tonic-gate } 17427c478bd9Sstevel@tonic-gate 17437c478bd9Sstevel@tonic-gate static struct logint * 17447c478bd9Sstevel@tonic-gate find_logint(struct phyint *pi, char *name) 17457c478bd9Sstevel@tonic-gate { 17467c478bd9Sstevel@tonic-gate struct logint *li; 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; li = li->li_next) { 17497c478bd9Sstevel@tonic-gate if (strcmp(li->li_name, name) == 0) 17507c478bd9Sstevel@tonic-gate return (li); 17517c478bd9Sstevel@tonic-gate } 17527c478bd9Sstevel@tonic-gate return (NULL); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate /* 17567c478bd9Sstevel@tonic-gate * Assumes that the entry does not exist - caller must use find_* 17577c478bd9Sstevel@tonic-gate * Tail insertion. 17587c478bd9Sstevel@tonic-gate */ 17597c478bd9Sstevel@tonic-gate static struct logint * 17607c478bd9Sstevel@tonic-gate add_logint(struct phyint *pi, char *name) 17617c478bd9Sstevel@tonic-gate { 17627c478bd9Sstevel@tonic-gate struct logint *li; 17637c478bd9Sstevel@tonic-gate 17647c478bd9Sstevel@tonic-gate li = malloc(sizeof (*li)); 17657c478bd9Sstevel@tonic-gate if (li == NULL) 17667c478bd9Sstevel@tonic-gate return (NULL); 17677c478bd9Sstevel@tonic-gate bzero((char *)li, sizeof (*li)); 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate strncpy(li->li_name, name, sizeof (li->li_name)); 17707c478bd9Sstevel@tonic-gate /* Link into list */ 17717c478bd9Sstevel@tonic-gate li->li_prev = pi->pi_logical_last; 17727c478bd9Sstevel@tonic-gate if (pi->pi_logical_last == NULL) { 17737c478bd9Sstevel@tonic-gate /* First one */ 17747c478bd9Sstevel@tonic-gate assert(pi->pi_logical_first == NULL); 17757c478bd9Sstevel@tonic-gate pi->pi_logical_first = li; 17767c478bd9Sstevel@tonic-gate } else { 17777c478bd9Sstevel@tonic-gate pi->pi_logical_last->li_next = li; 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate li->li_next = NULL; 17807c478bd9Sstevel@tonic-gate li->li_physical = pi; 17817c478bd9Sstevel@tonic-gate pi->pi_logical_last = li; 17827c478bd9Sstevel@tonic-gate return (li); 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate } 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate static void 17877c478bd9Sstevel@tonic-gate free_logint(struct logint *li) 17887c478bd9Sstevel@tonic-gate { 17897c478bd9Sstevel@tonic-gate struct phyint *pi; 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate pi = li->li_physical; 17927c478bd9Sstevel@tonic-gate if (li->li_prev == NULL) { 17937c478bd9Sstevel@tonic-gate /* Delete first */ 17947c478bd9Sstevel@tonic-gate assert(pi->pi_logical_first == li); 17957c478bd9Sstevel@tonic-gate pi->pi_logical_first = li->li_next; 17967c478bd9Sstevel@tonic-gate } else { 17977c478bd9Sstevel@tonic-gate assert(li->li_prev->li_next == li); 17987c478bd9Sstevel@tonic-gate li->li_prev->li_next = li->li_next; 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate if (li->li_next == NULL) { 18017c478bd9Sstevel@tonic-gate /* Delete last */ 18027c478bd9Sstevel@tonic-gate assert(pi->pi_logical_last == li); 18037c478bd9Sstevel@tonic-gate pi->pi_logical_last = li->li_prev; 18047c478bd9Sstevel@tonic-gate } else { 18057c478bd9Sstevel@tonic-gate assert(li->li_next->li_prev == li); 18067c478bd9Sstevel@tonic-gate li->li_next->li_prev = li->li_prev; 18077c478bd9Sstevel@tonic-gate } 18087c478bd9Sstevel@tonic-gate free(li); 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate /* Tell all the logical interfaces that they are going away */ 18137c478bd9Sstevel@tonic-gate static void 18147c478bd9Sstevel@tonic-gate deleted_phyint(struct phyint *pi, int s, 18157c478bd9Sstevel@tonic-gate struct sockaddr_in *joinaddr) 18167c478bd9Sstevel@tonic-gate { 18177c478bd9Sstevel@tonic-gate struct logint *li; 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate if (debug) 18207c478bd9Sstevel@tonic-gate logdebug("Deleting physical interface %s\n", pi->pi_name); 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; li = li->li_next) { 18237c478bd9Sstevel@tonic-gate li->li_state |= ST_DELETED; 18247c478bd9Sstevel@tonic-gate } 18257c478bd9Sstevel@tonic-gate for (li = pi->pi_logical_first; li != NULL; li = li->li_next) { 18267c478bd9Sstevel@tonic-gate deleted_logint(li, NULL, s, joinaddr); 18277c478bd9Sstevel@tonic-gate } 18287c478bd9Sstevel@tonic-gate } 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate /* 18317c478bd9Sstevel@tonic-gate * Join the multicast address if no other logical interface has done 18327c478bd9Sstevel@tonic-gate * so for this physical interface. 18337c478bd9Sstevel@tonic-gate */ 18347c478bd9Sstevel@tonic-gate static void 18357c478bd9Sstevel@tonic-gate added_logint(struct logint *li, int s, 18367c478bd9Sstevel@tonic-gate struct sockaddr_in *joinaddr) 18377c478bd9Sstevel@tonic-gate { 18387c478bd9Sstevel@tonic-gate if (debug) 18397c478bd9Sstevel@tonic-gate logdebug("Adding logical interface %s\n", li->li_name); 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate if ((!(li->li_physical->pi_state & ST_JOINED)) && 18427c478bd9Sstevel@tonic-gate (!isbroadcast(joinaddr))) { 18437c478bd9Sstevel@tonic-gate struct ip_mreq mreq; 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate mreq.imr_multiaddr = joinaddr->sin_addr; 18467c478bd9Sstevel@tonic-gate mreq.imr_interface = li->li_address; 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate if (debug) 18497c478bd9Sstevel@tonic-gate logdebug("Joining MC on interface %s\n", li->li_name); 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, 18527c478bd9Sstevel@tonic-gate (char *)&mreq, sizeof (mreq)) < 0) { 18537c478bd9Sstevel@tonic-gate logperror("setsockopt (IP_ADD_MEMBERSHIP)"); 18547c478bd9Sstevel@tonic-gate } else { 18557c478bd9Sstevel@tonic-gate li->li_physical->pi_state |= ST_JOINED; 18567c478bd9Sstevel@tonic-gate li->li_state |= ST_JOINED; 18577c478bd9Sstevel@tonic-gate } 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate } 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate /* 18627c478bd9Sstevel@tonic-gate * Leave the multicast address if this logical interface joined it. 18637c478bd9Sstevel@tonic-gate * Look for a replacement logical interface for the same physical interface. 18647c478bd9Sstevel@tonic-gate * Remove any routes which are no longer reachable. 18657c478bd9Sstevel@tonic-gate * 18667c478bd9Sstevel@tonic-gate * If newli is non-NULL, then it is likely that the address of a logical 18677c478bd9Sstevel@tonic-gate * interface has changed. In this case, the membership should be dropped using 18687c478bd9Sstevel@tonic-gate * the new address of the interface in question. 18697c478bd9Sstevel@tonic-gate * 18707c478bd9Sstevel@tonic-gate * XXX When a physical interface is being deleted by deleted_phyint(), this 18717c478bd9Sstevel@tonic-gate * routine will be called for each logical interface associated with the 18727c478bd9Sstevel@tonic-gate * physical one. This should be made more efficient as there is no point in 18737c478bd9Sstevel@tonic-gate * searching for an alternate logical interface to add group membership to as 18747c478bd9Sstevel@tonic-gate * they all are marked ST_DELETED. 18757c478bd9Sstevel@tonic-gate */ 18767c478bd9Sstevel@tonic-gate static void 18777c478bd9Sstevel@tonic-gate deleted_logint(struct logint *li, struct logint *newli, int s, 18787c478bd9Sstevel@tonic-gate struct sockaddr_in *joinaddr) 18797c478bd9Sstevel@tonic-gate { 18807c478bd9Sstevel@tonic-gate struct phyint *pi; 18817c478bd9Sstevel@tonic-gate struct logint *oli; 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate if (debug) 18847c478bd9Sstevel@tonic-gate logdebug("Deleting logical interface %s\n", li->li_name); 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate assert(li->li_state & ST_DELETED); 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate if (li->li_state & ST_JOINED) { 18897c478bd9Sstevel@tonic-gate struct ip_mreq mreq; 18907c478bd9Sstevel@tonic-gate 18917c478bd9Sstevel@tonic-gate pi = li->li_physical; 18927c478bd9Sstevel@tonic-gate assert(pi->pi_state & ST_JOINED); 18937c478bd9Sstevel@tonic-gate assert(!isbroadcast(joinaddr)); 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate mreq.imr_multiaddr = joinaddr->sin_addr; 18967c478bd9Sstevel@tonic-gate if (newli != NULL) 18977c478bd9Sstevel@tonic-gate mreq.imr_interface = newli->li_address; 18987c478bd9Sstevel@tonic-gate else 18997c478bd9Sstevel@tonic-gate mreq.imr_interface = li->li_address; 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate if (debug) 19027c478bd9Sstevel@tonic-gate logdebug("Leaving MC on interface %s\n", li->li_name); 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, 19057c478bd9Sstevel@tonic-gate (char *)&mreq, sizeof (mreq)) < 0) { 19067c478bd9Sstevel@tonic-gate /* 19077c478bd9Sstevel@tonic-gate * EADDRNOTAVAIL will be returned if the interface has 19087c478bd9Sstevel@tonic-gate * been unplumbed or if the interface no longer has 19097c478bd9Sstevel@tonic-gate * IFF_MULTICAST set. The former is the common case 19107c478bd9Sstevel@tonic-gate * while the latter is rare so don't log the error 19117c478bd9Sstevel@tonic-gate * unless some other error was returned or if debug is 19127c478bd9Sstevel@tonic-gate * set. 19137c478bd9Sstevel@tonic-gate */ 19147c478bd9Sstevel@tonic-gate if (errno != EADDRNOTAVAIL) { 19157c478bd9Sstevel@tonic-gate logperror("setsockopt (IP_DROP_MEMBERSHIP)"); 19167c478bd9Sstevel@tonic-gate } else if (debug) { 19177c478bd9Sstevel@tonic-gate logdebug("%s: %s\n", 19187c478bd9Sstevel@tonic-gate "setsockopt (IP_DROP_MEMBERSHIP)", 19197c478bd9Sstevel@tonic-gate strerror(errno)); 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate } 19227c478bd9Sstevel@tonic-gate li->li_physical->pi_state &= ~ST_JOINED; 19237c478bd9Sstevel@tonic-gate li->li_state &= ~ST_JOINED; 19247c478bd9Sstevel@tonic-gate 19257c478bd9Sstevel@tonic-gate /* Is there another interface that can join? */ 19267c478bd9Sstevel@tonic-gate for (oli = pi->pi_logical_first; oli != NULL; 19277c478bd9Sstevel@tonic-gate oli = oli->li_next) { 19287c478bd9Sstevel@tonic-gate if (oli->li_state & ST_DELETED) 19297c478bd9Sstevel@tonic-gate continue; 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate mreq.imr_multiaddr = joinaddr->sin_addr; 19327c478bd9Sstevel@tonic-gate mreq.imr_interface = oli->li_address; 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate if (debug) 19357c478bd9Sstevel@tonic-gate logdebug("Joining MC on interface %s\n", 19367c478bd9Sstevel@tonic-gate oli->li_name); 19377c478bd9Sstevel@tonic-gate 19387c478bd9Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, 19397c478bd9Sstevel@tonic-gate (char *)&mreq, sizeof (mreq)) < 0) { 19407c478bd9Sstevel@tonic-gate logperror("setsockopt (IP_ADD_MEMBERSHIP)"); 19417c478bd9Sstevel@tonic-gate } else { 19427c478bd9Sstevel@tonic-gate pi->pi_state |= ST_JOINED; 19437c478bd9Sstevel@tonic-gate oli->li_state |= ST_JOINED; 19447c478bd9Sstevel@tonic-gate break; 19457c478bd9Sstevel@tonic-gate } 19467c478bd9Sstevel@tonic-gate } 19477c478bd9Sstevel@tonic-gate } 19487c478bd9Sstevel@tonic-gate 19497c478bd9Sstevel@tonic-gate flush_unreachable_routers(); 19507c478bd9Sstevel@tonic-gate } 19517c478bd9Sstevel@tonic-gate 19527c478bd9Sstevel@tonic-gate 19537c478bd9Sstevel@tonic-gate 19547c478bd9Sstevel@tonic-gate /* 19557c478bd9Sstevel@tonic-gate * TABLES 19567c478bd9Sstevel@tonic-gate */ 19577c478bd9Sstevel@tonic-gate struct table { 19587c478bd9Sstevel@tonic-gate struct in_addr router; 19597c478bd9Sstevel@tonic-gate int preference; 19607c478bd9Sstevel@tonic-gate int remaining_time; 19617c478bd9Sstevel@tonic-gate int in_kernel; 19627c478bd9Sstevel@tonic-gate struct table *next; 19637c478bd9Sstevel@tonic-gate }; 19647c478bd9Sstevel@tonic-gate 19657c478bd9Sstevel@tonic-gate struct table *table; 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate static void 19687c478bd9Sstevel@tonic-gate report_routes(void) 19697c478bd9Sstevel@tonic-gate { 19707c478bd9Sstevel@tonic-gate struct table *tp; 19717c478bd9Sstevel@tonic-gate 19727c478bd9Sstevel@tonic-gate logdebug("\nRoutes:\n\n"); 19737c478bd9Sstevel@tonic-gate tp = table; 19747c478bd9Sstevel@tonic-gate while (tp) { 19757c478bd9Sstevel@tonic-gate logdebug("Router %s, pref 0x%x, time %d, %s kernel\n", 19767c478bd9Sstevel@tonic-gate pr_name(tp->router), tp->preference, 19777c478bd9Sstevel@tonic-gate tp->remaining_time, 19787c478bd9Sstevel@tonic-gate (tp->in_kernel ? "in" : "not in")); 19797c478bd9Sstevel@tonic-gate tp = tp->next; 19807c478bd9Sstevel@tonic-gate } 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate static struct table * 19847c478bd9Sstevel@tonic-gate find_router(struct in_addr addr) 19857c478bd9Sstevel@tonic-gate { 19867c478bd9Sstevel@tonic-gate struct table *tp; 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate tp = table; 19897c478bd9Sstevel@tonic-gate while (tp) { 19907c478bd9Sstevel@tonic-gate if (tp->router.s_addr == addr.s_addr) 19917c478bd9Sstevel@tonic-gate return (tp); 19927c478bd9Sstevel@tonic-gate tp = tp->next; 19937c478bd9Sstevel@tonic-gate } 19947c478bd9Sstevel@tonic-gate return (NULL); 19957c478bd9Sstevel@tonic-gate } 19967c478bd9Sstevel@tonic-gate 19977c478bd9Sstevel@tonic-gate static int 19987c478bd9Sstevel@tonic-gate max_preference(void) 19997c478bd9Sstevel@tonic-gate { 20007c478bd9Sstevel@tonic-gate struct table *tp; 20017c478bd9Sstevel@tonic-gate int max = (int)IGNORE_PREFERENCE; 20027c478bd9Sstevel@tonic-gate 20037c478bd9Sstevel@tonic-gate tp = table; 20047c478bd9Sstevel@tonic-gate while (tp) { 20057c478bd9Sstevel@tonic-gate if (tp->preference > max) 20067c478bd9Sstevel@tonic-gate max = tp->preference; 20077c478bd9Sstevel@tonic-gate tp = tp->next; 20087c478bd9Sstevel@tonic-gate } 20097c478bd9Sstevel@tonic-gate return (max); 20107c478bd9Sstevel@tonic-gate } 20117c478bd9Sstevel@tonic-gate 20127c478bd9Sstevel@tonic-gate 20137c478bd9Sstevel@tonic-gate /* Note: this might leave the kernel with no default route for a short time. */ 20147c478bd9Sstevel@tonic-gate static void 20157c478bd9Sstevel@tonic-gate age_table(int time) 20167c478bd9Sstevel@tonic-gate { 20177c478bd9Sstevel@tonic-gate struct table **tpp, *tp; 20187c478bd9Sstevel@tonic-gate int recalculate_max = 0; 20197c478bd9Sstevel@tonic-gate int max = max_preference(); 20207c478bd9Sstevel@tonic-gate 20217c478bd9Sstevel@tonic-gate tpp = &table; 20227c478bd9Sstevel@tonic-gate while (*tpp != NULL) { 20237c478bd9Sstevel@tonic-gate tp = *tpp; 20247c478bd9Sstevel@tonic-gate tp->remaining_time -= time; 20257c478bd9Sstevel@tonic-gate if (tp->remaining_time <= 0) { 20267c478bd9Sstevel@tonic-gate *tpp = tp->next; 20277c478bd9Sstevel@tonic-gate if (debug) { 20287c478bd9Sstevel@tonic-gate logdebug("Timed out router %s\n", 20297c478bd9Sstevel@tonic-gate pr_name(tp->router)); 20307c478bd9Sstevel@tonic-gate } 20317c478bd9Sstevel@tonic-gate if (tp->in_kernel) 20327c478bd9Sstevel@tonic-gate del_route(tp->router); 20337c478bd9Sstevel@tonic-gate if (best_preference && 20347c478bd9Sstevel@tonic-gate tp->preference == max) 20357c478bd9Sstevel@tonic-gate recalculate_max++; 20367c478bd9Sstevel@tonic-gate free((char *)tp); 20377c478bd9Sstevel@tonic-gate } else { 20387c478bd9Sstevel@tonic-gate tpp = &tp->next; 20397c478bd9Sstevel@tonic-gate } 20407c478bd9Sstevel@tonic-gate } 20417c478bd9Sstevel@tonic-gate if (recalculate_max) { 20427c478bd9Sstevel@tonic-gate int max = max_preference(); 20437c478bd9Sstevel@tonic-gate 20447c478bd9Sstevel@tonic-gate if (max != IGNORE_PREFERENCE) { 20457c478bd9Sstevel@tonic-gate tp = table; 20467c478bd9Sstevel@tonic-gate while (tp) { 20477c478bd9Sstevel@tonic-gate if (tp->preference == max && !tp->in_kernel) { 20487c478bd9Sstevel@tonic-gate add_route(tp->router); 20497c478bd9Sstevel@tonic-gate tp->in_kernel++; 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate tp = tp->next; 20527c478bd9Sstevel@tonic-gate } 20537c478bd9Sstevel@tonic-gate } 20547c478bd9Sstevel@tonic-gate } 20557c478bd9Sstevel@tonic-gate } 20567c478bd9Sstevel@tonic-gate 20577c478bd9Sstevel@tonic-gate /* 20587c478bd9Sstevel@tonic-gate * Remove any routes which are no longer directly connected. 20597c478bd9Sstevel@tonic-gate */ 20607c478bd9Sstevel@tonic-gate static void 20617c478bd9Sstevel@tonic-gate flush_unreachable_routers(void) 20627c478bd9Sstevel@tonic-gate { 20637c478bd9Sstevel@tonic-gate struct table **tpp, *tp; 20647c478bd9Sstevel@tonic-gate int recalculate_max = 0; 20657c478bd9Sstevel@tonic-gate int max = max_preference(); 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate tpp = &table; 20687c478bd9Sstevel@tonic-gate while (*tpp != NULL) { 20697c478bd9Sstevel@tonic-gate tp = *tpp; 20707c478bd9Sstevel@tonic-gate if (find_directly_connected_logint(tp->router, NULL) == NULL) { 20717c478bd9Sstevel@tonic-gate *tpp = tp->next; 20727c478bd9Sstevel@tonic-gate if (debug) { 20737c478bd9Sstevel@tonic-gate logdebug("Unreachable router %s\n", 20747c478bd9Sstevel@tonic-gate pr_name(tp->router)); 20757c478bd9Sstevel@tonic-gate } 20767c478bd9Sstevel@tonic-gate if (tp->in_kernel) 20777c478bd9Sstevel@tonic-gate del_route(tp->router); 20787c478bd9Sstevel@tonic-gate if (best_preference && 20797c478bd9Sstevel@tonic-gate tp->preference == max) 20807c478bd9Sstevel@tonic-gate recalculate_max++; 20817c478bd9Sstevel@tonic-gate free((char *)tp); 20827c478bd9Sstevel@tonic-gate } else { 20837c478bd9Sstevel@tonic-gate tpp = &tp->next; 20847c478bd9Sstevel@tonic-gate } 20857c478bd9Sstevel@tonic-gate } 20867c478bd9Sstevel@tonic-gate if (recalculate_max) { 20877c478bd9Sstevel@tonic-gate int max = max_preference(); 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate if (max != IGNORE_PREFERENCE) { 20907c478bd9Sstevel@tonic-gate tp = table; 20917c478bd9Sstevel@tonic-gate while (tp) { 20927c478bd9Sstevel@tonic-gate if (tp->preference == max && !tp->in_kernel) { 20937c478bd9Sstevel@tonic-gate add_route(tp->router); 20947c478bd9Sstevel@tonic-gate tp->in_kernel++; 20957c478bd9Sstevel@tonic-gate } 20967c478bd9Sstevel@tonic-gate tp = tp->next; 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate } 20997c478bd9Sstevel@tonic-gate } 21007c478bd9Sstevel@tonic-gate } 21017c478bd9Sstevel@tonic-gate 21027c478bd9Sstevel@tonic-gate static void 21037c478bd9Sstevel@tonic-gate record_router(struct in_addr router, long preference, int ttl) 21047c478bd9Sstevel@tonic-gate { 21057c478bd9Sstevel@tonic-gate struct table *tp; 21067c478bd9Sstevel@tonic-gate int old_max = max_preference(); 21077c478bd9Sstevel@tonic-gate int changed_up = 0; /* max preference could have increased */ 21087c478bd9Sstevel@tonic-gate int changed_down = 0; /* max preference could have decreased */ 21097c478bd9Sstevel@tonic-gate 21107c478bd9Sstevel@tonic-gate if (debug) 21117c478bd9Sstevel@tonic-gate logdebug("Recording %s, preference 0x%x\n", 21127c478bd9Sstevel@tonic-gate pr_name(router), 21137c478bd9Sstevel@tonic-gate preference); 21147c478bd9Sstevel@tonic-gate tp = find_router(router); 21157c478bd9Sstevel@tonic-gate if (tp) { 21167c478bd9Sstevel@tonic-gate if (tp->preference > preference && 21177c478bd9Sstevel@tonic-gate tp->preference == old_max) 21187c478bd9Sstevel@tonic-gate changed_down++; 21197c478bd9Sstevel@tonic-gate else if (preference > tp->preference) 21207c478bd9Sstevel@tonic-gate changed_up++; 21217c478bd9Sstevel@tonic-gate tp->preference = preference; 21227c478bd9Sstevel@tonic-gate tp->remaining_time = ttl; 21237c478bd9Sstevel@tonic-gate } else { 21247c478bd9Sstevel@tonic-gate if (preference > old_max) 21257c478bd9Sstevel@tonic-gate changed_up++; 21267c478bd9Sstevel@tonic-gate tp = (struct table *)ALIGN(malloc(sizeof (struct table))); 21277c478bd9Sstevel@tonic-gate if (tp == NULL) { 21287c478bd9Sstevel@tonic-gate logerr("Out of memory\n"); 21297c478bd9Sstevel@tonic-gate return; 21307c478bd9Sstevel@tonic-gate } 21317c478bd9Sstevel@tonic-gate tp->router = router; 21327c478bd9Sstevel@tonic-gate tp->preference = preference; 21337c478bd9Sstevel@tonic-gate tp->remaining_time = ttl; 21347c478bd9Sstevel@tonic-gate tp->in_kernel = 0; 21357c478bd9Sstevel@tonic-gate tp->next = table; 21367c478bd9Sstevel@tonic-gate table = tp; 21377c478bd9Sstevel@tonic-gate } 21387c478bd9Sstevel@tonic-gate if (!tp->in_kernel && 21397c478bd9Sstevel@tonic-gate (!best_preference || tp->preference == max_preference()) && 21407c478bd9Sstevel@tonic-gate tp->preference != IGNORE_PREFERENCE) { 21417c478bd9Sstevel@tonic-gate add_route(tp->router); 21427c478bd9Sstevel@tonic-gate tp->in_kernel++; 21437c478bd9Sstevel@tonic-gate } 21447c478bd9Sstevel@tonic-gate if (tp->preference == IGNORE_PREFERENCE && tp->in_kernel) { 21457c478bd9Sstevel@tonic-gate del_route(tp->router); 21467c478bd9Sstevel@tonic-gate tp->in_kernel = 0; 21477c478bd9Sstevel@tonic-gate } 21487c478bd9Sstevel@tonic-gate if (best_preference && changed_down) { 21497c478bd9Sstevel@tonic-gate /* Check if we should add routes */ 21507c478bd9Sstevel@tonic-gate int new_max = max_preference(); 21517c478bd9Sstevel@tonic-gate if (new_max != IGNORE_PREFERENCE) { 21527c478bd9Sstevel@tonic-gate tp = table; 21537c478bd9Sstevel@tonic-gate while (tp) { 21547c478bd9Sstevel@tonic-gate if (tp->preference == new_max && 21557c478bd9Sstevel@tonic-gate !tp->in_kernel) { 21567c478bd9Sstevel@tonic-gate add_route(tp->router); 21577c478bd9Sstevel@tonic-gate tp->in_kernel++; 21587c478bd9Sstevel@tonic-gate } 21597c478bd9Sstevel@tonic-gate tp = tp->next; 21607c478bd9Sstevel@tonic-gate } 21617c478bd9Sstevel@tonic-gate } 21627c478bd9Sstevel@tonic-gate } 21637c478bd9Sstevel@tonic-gate if (best_preference && (changed_up || changed_down)) { 21647c478bd9Sstevel@tonic-gate /* Check if we should remove routes already in the kernel */ 21657c478bd9Sstevel@tonic-gate int new_max = max_preference(); 21667c478bd9Sstevel@tonic-gate tp = table; 21677c478bd9Sstevel@tonic-gate while (tp) { 21687c478bd9Sstevel@tonic-gate if (tp->preference < new_max && tp->in_kernel) { 21697c478bd9Sstevel@tonic-gate del_route(tp->router); 21707c478bd9Sstevel@tonic-gate tp->in_kernel = 0; 21717c478bd9Sstevel@tonic-gate } 21727c478bd9Sstevel@tonic-gate tp = tp->next; 21737c478bd9Sstevel@tonic-gate } 21747c478bd9Sstevel@tonic-gate } 21757c478bd9Sstevel@tonic-gate } 21767c478bd9Sstevel@tonic-gate 21777c478bd9Sstevel@tonic-gate 21787c478bd9Sstevel@tonic-gate #include <net/route.h> 21797c478bd9Sstevel@tonic-gate 21807c478bd9Sstevel@tonic-gate static void 21817c478bd9Sstevel@tonic-gate add_route(struct in_addr addr) 21827c478bd9Sstevel@tonic-gate { 21837c478bd9Sstevel@tonic-gate if (debug) 21847c478bd9Sstevel@tonic-gate logdebug("Add default route to %s\n", pr_name(addr)); 21857c478bd9Sstevel@tonic-gate rtioctl(addr, SIOCADDRT); 21867c478bd9Sstevel@tonic-gate } 21877c478bd9Sstevel@tonic-gate 21887c478bd9Sstevel@tonic-gate static void 21897c478bd9Sstevel@tonic-gate del_route(struct in_addr addr) 21907c478bd9Sstevel@tonic-gate { 21917c478bd9Sstevel@tonic-gate if (debug) 21927c478bd9Sstevel@tonic-gate logdebug("Delete default route to %s\n", pr_name(addr)); 21937c478bd9Sstevel@tonic-gate rtioctl(addr, SIOCDELRT); 21947c478bd9Sstevel@tonic-gate } 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate static void 21977c478bd9Sstevel@tonic-gate rtioctl(struct in_addr addr, int op) 21987c478bd9Sstevel@tonic-gate { 21997c478bd9Sstevel@tonic-gate int sock; 22007c478bd9Sstevel@tonic-gate struct rtentry rt; 22017c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 22027c478bd9Sstevel@tonic-gate bzero((char *)&rt, sizeof (struct rtentry)); 22037c478bd9Sstevel@tonic-gate rt.rt_dst.sa_family = AF_INET; 22047c478bd9Sstevel@tonic-gate rt.rt_gateway.sa_family = AF_INET; 22057c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)ALIGN(&rt.rt_gateway); 22067c478bd9Sstevel@tonic-gate sin->sin_addr = addr; 22077c478bd9Sstevel@tonic-gate rt.rt_flags = RTF_UP | RTF_GATEWAY; 22087c478bd9Sstevel@tonic-gate 22097c478bd9Sstevel@tonic-gate sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 22107c478bd9Sstevel@tonic-gate if (sock < 0) { 22117c478bd9Sstevel@tonic-gate logperror("rtioctl: socket"); 22127c478bd9Sstevel@tonic-gate return; 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate if (ioctl(sock, op, (char *)&rt) < 0) { 22157c478bd9Sstevel@tonic-gate if (!(op == SIOCADDRT && errno == EEXIST)) 22167c478bd9Sstevel@tonic-gate logperror("ioctl (add/delete route)"); 22177c478bd9Sstevel@tonic-gate } 22187c478bd9Sstevel@tonic-gate (void) close(sock); 22197c478bd9Sstevel@tonic-gate } 22207c478bd9Sstevel@tonic-gate 22217c478bd9Sstevel@tonic-gate 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate /* 22247c478bd9Sstevel@tonic-gate * LOGGER 22257c478bd9Sstevel@tonic-gate */ 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate #include <syslog.h> 22287c478bd9Sstevel@tonic-gate 2229aee32e3dScarlsonj static int logging = 0; 22307c478bd9Sstevel@tonic-gate 22317c478bd9Sstevel@tonic-gate static void 22327c478bd9Sstevel@tonic-gate initlog(void) 22337c478bd9Sstevel@tonic-gate { 22347c478bd9Sstevel@tonic-gate logging++; 22357c478bd9Sstevel@tonic-gate openlog("in.rdisc", LOG_PID | LOG_CONS, LOG_DAEMON); 22367c478bd9Sstevel@tonic-gate } 22377c478bd9Sstevel@tonic-gate 22387c478bd9Sstevel@tonic-gate /* VARARGS1 */ 22397c478bd9Sstevel@tonic-gate void 22407c478bd9Sstevel@tonic-gate logerr(fmt, a, b, c, d, e, f, g, h) 22417c478bd9Sstevel@tonic-gate char *fmt; 22427c478bd9Sstevel@tonic-gate { 22437c478bd9Sstevel@tonic-gate if (logging) 22447c478bd9Sstevel@tonic-gate syslog(LOG_ERR, fmt, a, b, c, d, e, f, g, h); 22457c478bd9Sstevel@tonic-gate else 22467c478bd9Sstevel@tonic-gate (void) fprintf(stderr, fmt, a, b, c, d, e, f, g, h); 22477c478bd9Sstevel@tonic-gate } 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate /* VARARGS1 */ 22507c478bd9Sstevel@tonic-gate void 22517c478bd9Sstevel@tonic-gate logtrace(fmt, a, b, c, d, e, f, g, h) 22527c478bd9Sstevel@tonic-gate char *fmt; 22537c478bd9Sstevel@tonic-gate { 22547c478bd9Sstevel@tonic-gate if (logging) 22557c478bd9Sstevel@tonic-gate syslog(LOG_INFO, fmt, a, b, c, d, e, f, g, h); 22567c478bd9Sstevel@tonic-gate else 22577c478bd9Sstevel@tonic-gate (void) fprintf(stdout, fmt, a, b, c, d, e, f, g, h); 22587c478bd9Sstevel@tonic-gate } 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate /* VARARGS1 */ 22617c478bd9Sstevel@tonic-gate void 22627c478bd9Sstevel@tonic-gate logdebug(fmt, a, b, c, d, e, f, g, h) 22637c478bd9Sstevel@tonic-gate char *fmt; 22647c478bd9Sstevel@tonic-gate { 22657c478bd9Sstevel@tonic-gate if (logging) 22667c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG, fmt, a, b, c, d, e, f, g, h); 22677c478bd9Sstevel@tonic-gate else 22687c478bd9Sstevel@tonic-gate (void) fprintf(stdout, fmt, a, b, c, d, e, f, g, h); 22697c478bd9Sstevel@tonic-gate } 22707c478bd9Sstevel@tonic-gate 22717c478bd9Sstevel@tonic-gate void 22727c478bd9Sstevel@tonic-gate logperror(str) 22737c478bd9Sstevel@tonic-gate char *str; 22747c478bd9Sstevel@tonic-gate { 22757c478bd9Sstevel@tonic-gate if (logging) 22767c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s: %s\n", str, strerror(errno)); 22777c478bd9Sstevel@tonic-gate else 22787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", str, strerror(errno)); 22797c478bd9Sstevel@tonic-gate } 2280