1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/stat.h> 31*0Sstevel@tonic-gate #include <sys/tihdr.h> 32*0Sstevel@tonic-gate #include <stropts.h> 33*0Sstevel@tonic-gate #include <fcntl.h> 34*0Sstevel@tonic-gate #include <syslog.h> 35*0Sstevel@tonic-gate #include <string.h> 36*0Sstevel@tonic-gate #include <strings.h> 37*0Sstevel@tonic-gate #include <errno.h> 38*0Sstevel@tonic-gate #include <stdio.h> 39*0Sstevel@tonic-gate #include <stdlib.h> 40*0Sstevel@tonic-gate #include <libintl.h> 41*0Sstevel@tonic-gate #include <locale.h> 42*0Sstevel@tonic-gate #include <unistd.h> 43*0Sstevel@tonic-gate #include <sys/varargs.h> 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate #include <netinet/in.h> 46*0Sstevel@tonic-gate #include <sys/ethernet.h> 47*0Sstevel@tonic-gate #include <sys/socket.h> 48*0Sstevel@tonic-gate #include <sys/sockio.h> 49*0Sstevel@tonic-gate #include <sys/sysmacros.h> 50*0Sstevel@tonic-gate #include <net/if.h> 51*0Sstevel@tonic-gate #include <inet/mib2.h> 52*0Sstevel@tonic-gate #include <inet/ip.h> 53*0Sstevel@tonic-gate #include <net/route.h> 54*0Sstevel@tonic-gate #include <arpa/inet.h> 55*0Sstevel@tonic-gate #include "ncaconf.h" 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate /* NCA does not support IPv6... */ 58*0Sstevel@tonic-gate #ifndef IP_DEV_NAME 59*0Sstevel@tonic-gate #define IP_DEV_NAME "/dev/ip" 60*0Sstevel@tonic-gate #endif 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate #ifndef IP_MOD_NAME 63*0Sstevel@tonic-gate #define IP_MOD_NAME "ip" 64*0Sstevel@tonic-gate #endif 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate #ifndef UDP_DEV_NAME 67*0Sstevel@tonic-gate #define UDP_DEV_NAME "/dev/udp" 68*0Sstevel@tonic-gate #endif 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate #ifndef NCA_MOD_NAME 71*0Sstevel@tonic-gate #define NCA_MOD_NAME "nca" 72*0Sstevel@tonic-gate #endif 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate #ifndef ARP_MOD_NAME 75*0Sstevel@tonic-gate #define ARP_MOD_NAME "arp" 76*0Sstevel@tonic-gate #endif 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate #define IF_SEPARATOR ':' 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate #define ping_prog "/usr/sbin/ping" 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate /* Structure to hold info about each network interface. */ 83*0Sstevel@tonic-gate typedef struct nif_s { 84*0Sstevel@tonic-gate char name[LIFNAMSIZ+1]; 85*0Sstevel@tonic-gate struct in_addr local_addr; 86*0Sstevel@tonic-gate struct in_addr router_addr; 87*0Sstevel@tonic-gate uchar_t router_ether_addr[ETHERADDRL]; 88*0Sstevel@tonic-gate } nif_t; 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate typedef struct mib_item_s { 91*0Sstevel@tonic-gate struct mib_item_s *next_item; 92*0Sstevel@tonic-gate int group; 93*0Sstevel@tonic-gate int mib_id; 94*0Sstevel@tonic-gate int length; 95*0Sstevel@tonic-gate char *valp; 96*0Sstevel@tonic-gate } mib_item_t; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate /* The network interface array. */ 99*0Sstevel@tonic-gate static nif_t *nif_list; 100*0Sstevel@tonic-gate /* Number of network interface to process. */ 101*0Sstevel@tonic-gate static int num_nif; 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate /* Interface request to IP. */ 104*0Sstevel@tonic-gate static struct lifreq lifr; 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate /* True if syslog is to be used. */ 107*0Sstevel@tonic-gate static boolean_t logging; 108*0Sstevel@tonic-gate /* True if additional debugging messages are printed. */ 109*0Sstevel@tonic-gate static boolean_t debug; 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate /* File descriptor to the routing socket. */ 112*0Sstevel@tonic-gate static int rt_fd; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate static void logperror(char *); 115*0Sstevel@tonic-gate static void logwarn(char *, ...); 116*0Sstevel@tonic-gate static void logdebug(char *, ...); 117*0Sstevel@tonic-gate static int ip_domux2fd(int *, int *); 118*0Sstevel@tonic-gate static void ip_plink(int, int); 119*0Sstevel@tonic-gate static int find_nca_pos(int); 120*0Sstevel@tonic-gate static int nca_set_nif(int, struct in_addr, uchar_t *); 121*0Sstevel@tonic-gate static void nca_setup(boolean_t *); 122*0Sstevel@tonic-gate static int get_if_ip_addr(void); 123*0Sstevel@tonic-gate static mib_item_t *mibget(int); 124*0Sstevel@tonic-gate static int ire_process(mib2_ipRouteEntry_t *, size_t, boolean_t *); 125*0Sstevel@tonic-gate static int arp_process(mib2_ipNetToMediaEntry_t *, size_t, boolean_t *); 126*0Sstevel@tonic-gate static int get_router_ip_addr(mib_item_t *, boolean_t *); 127*0Sstevel@tonic-gate static int get_router_ether_addr(mib_item_t *, boolean_t *); 128*0Sstevel@tonic-gate static int get_if_info(boolean_t *); 129*0Sstevel@tonic-gate static void daemon_init(void); 130*0Sstevel@tonic-gate static void daemon_work(void); 131*0Sstevel@tonic-gate static void ping_them(void); 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate /* 134*0Sstevel@tonic-gate * Print out system error messages, either to syslog or stderr. Note that 135*0Sstevel@tonic-gate * syslog() should print out system error messages in the correct language 136*0Sstevel@tonic-gate * used. There is no need to use gettext(). 137*0Sstevel@tonic-gate */ 138*0Sstevel@tonic-gate static void 139*0Sstevel@tonic-gate logperror(char *str) 140*0Sstevel@tonic-gate { 141*0Sstevel@tonic-gate if (logging) { 142*0Sstevel@tonic-gate syslog(LOG_ERR, "%s: %m\n", str); 143*0Sstevel@tonic-gate } else { 144*0Sstevel@tonic-gate (void) fprintf(stderr, "ncaconfd: %s: %s\n", str, 145*0Sstevel@tonic-gate strerror(errno)); 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate /* 150*0Sstevel@tonic-gate * Print out warning messages. The caller should use gettext() to have 151*0Sstevel@tonic-gate * the message printed out in the correct language. 152*0Sstevel@tonic-gate */ 153*0Sstevel@tonic-gate /*PRINTFLIKE1*/ 154*0Sstevel@tonic-gate static void 155*0Sstevel@tonic-gate logwarn(char *fmt, ...) 156*0Sstevel@tonic-gate { 157*0Sstevel@tonic-gate va_list ap; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate va_start(ap, fmt); 160*0Sstevel@tonic-gate if (logging) { 161*0Sstevel@tonic-gate vsyslog(LOG_WARNING, fmt, ap); 162*0Sstevel@tonic-gate } else { 163*0Sstevel@tonic-gate (void) fprintf(stderr, "ncaconfd: "); 164*0Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 165*0Sstevel@tonic-gate } 166*0Sstevel@tonic-gate va_end(ap); 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate /* 170*0Sstevel@tonic-gate * Print out debugging info. Note that syslogd(1M) should be configured to 171*0Sstevel@tonic-gate * take ordinary debug info for it to get this kind of info. 172*0Sstevel@tonic-gate */ 173*0Sstevel@tonic-gate /*PRINTFLIKE1*/ 174*0Sstevel@tonic-gate static void 175*0Sstevel@tonic-gate logdebug(char *fmt, ...) 176*0Sstevel@tonic-gate { 177*0Sstevel@tonic-gate va_list ap; 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate va_start(ap, fmt); 180*0Sstevel@tonic-gate if (logging) { 181*0Sstevel@tonic-gate vsyslog(LOG_WARNING, fmt, ap); 182*0Sstevel@tonic-gate } else { 183*0Sstevel@tonic-gate (void) fprintf(stderr, "ncaconfd: "); 184*0Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate va_end(ap); 187*0Sstevel@tonic-gate } 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate /* 190*0Sstevel@tonic-gate * Helper function for nca_setup(). It gets a fd to the lower IP 191*0Sstevel@tonic-gate * stream and I_PUNLINK's the lower stream. It also initializes the 192*0Sstevel@tonic-gate * global variable lifr. 193*0Sstevel@tonic-gate * 194*0Sstevel@tonic-gate * Param: 195*0Sstevel@tonic-gate * int *udp_fd: (referenced) fd to /dev/udp (upper IP stream). 196*0Sstevel@tonic-gate * int *fd: (referenced) fd to the lower IP stream. 197*0Sstevel@tonic-gate * 198*0Sstevel@tonic-gate * Return: 199*0Sstevel@tonic-gate * -1 if operation fails, 0 otherwise. 200*0Sstevel@tonic-gate */ 201*0Sstevel@tonic-gate static int 202*0Sstevel@tonic-gate ip_domux2fd(int *udp_fd, int *fd) 203*0Sstevel@tonic-gate { 204*0Sstevel@tonic-gate int ip_fd; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate if ((ip_fd = open(IP_DEV_NAME, O_RDWR)) < 0) { 207*0Sstevel@tonic-gate logperror("Cannot open IP"); 208*0Sstevel@tonic-gate return (-1); 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate if ((*udp_fd = open(UDP_DEV_NAME, O_RDWR)) < 0) { 211*0Sstevel@tonic-gate logperror("Cannot open UDP"); 212*0Sstevel@tonic-gate (void) close(ip_fd); 213*0Sstevel@tonic-gate return (-1); 214*0Sstevel@tonic-gate } 215*0Sstevel@tonic-gate if (ioctl(ip_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 216*0Sstevel@tonic-gate logperror("ioctl(SIOCGLIFMUXID) failed"); 217*0Sstevel@tonic-gate (void) close(ip_fd); 218*0Sstevel@tonic-gate return (-1); 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate if (debug) { 221*0Sstevel@tonic-gate logdebug("ARP_muxid %d IP_muxid %d\n", lifr.lifr_arp_muxid, 222*0Sstevel@tonic-gate lifr.lifr_ip_muxid); 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate if ((*fd = ioctl(*udp_fd, _I_MUXID2FD, lifr.lifr_ip_muxid)) < 0) { 225*0Sstevel@tonic-gate logperror("ioctl(_I_MUXID2FD) failed"); 226*0Sstevel@tonic-gate (void) close(ip_fd); 227*0Sstevel@tonic-gate (void) close(*udp_fd); 228*0Sstevel@tonic-gate return (-1); 229*0Sstevel@tonic-gate } 230*0Sstevel@tonic-gate (void) close(ip_fd); 231*0Sstevel@tonic-gate return (0); 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate /* 235*0Sstevel@tonic-gate * Helper function for nca_setup(). It I_PLINK's back the upper and 236*0Sstevel@tonic-gate * lower IP streams. Note that this function must be called after 237*0Sstevel@tonic-gate * ip_domux2fd(). In ip_domux2fd(), the global variable lifr is initialized 238*0Sstevel@tonic-gate * and ip_plink() needs information in lifr. So ip_domux2fd() and ip_plink() 239*0Sstevel@tonic-gate * must be called in pairs. 240*0Sstevel@tonic-gate * 241*0Sstevel@tonic-gate * Param: 242*0Sstevel@tonic-gate * int udp_fd: fd to /dev/udp (upper IP stream). 243*0Sstevel@tonic-gate * int fd: fd to the lower IP stream. 244*0Sstevel@tonic-gate */ 245*0Sstevel@tonic-gate static void 246*0Sstevel@tonic-gate ip_plink(int udp_fd, int fd) 247*0Sstevel@tonic-gate { 248*0Sstevel@tonic-gate int mux_id; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate if ((mux_id = ioctl(udp_fd, I_PLINK, fd)) < 0) { 251*0Sstevel@tonic-gate logperror("ioctl(I_PLINK) failed"); 252*0Sstevel@tonic-gate return; 253*0Sstevel@tonic-gate } 254*0Sstevel@tonic-gate if (debug > 0) { 255*0Sstevel@tonic-gate logdebug("New IP_muxid %d\n", mux_id); 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate lifr.lifr_ip_muxid = mux_id; 258*0Sstevel@tonic-gate if (ioctl(udp_fd, SIOCSLIFMUXID, (caddr_t)&lifr) < 0) { 259*0Sstevel@tonic-gate logperror("ioctl(SIOCSLIFMUXID) failed"); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate #define FOUND_NCA -1 264*0Sstevel@tonic-gate #define FOUND_NONE -2 265*0Sstevel@tonic-gate /* 266*0Sstevel@tonic-gate * Find the proper position to insert NCA, which is just below IP. 267*0Sstevel@tonic-gate * 268*0Sstevel@tonic-gate * Param: 269*0Sstevel@tonic-gate * int fd: fd to the lower IP stream. 270*0Sstevel@tonic-gate * 271*0Sstevel@tonic-gate * Return: 272*0Sstevel@tonic-gate * If positive, it is the position to insert NCA. 273*0Sstevel@tonic-gate * FOUND_NCA: found NCA! So skip this one for plumbing. But we 274*0Sstevel@tonic-gate * still keep it in the interface list. 275*0Sstevel@tonic-gate * FOUND_NONE: could not find IP or encounter other errors. Remove 276*0Sstevel@tonic-gate * this interface from the list. 277*0Sstevel@tonic-gate */ 278*0Sstevel@tonic-gate static int 279*0Sstevel@tonic-gate find_nca_pos(int fd) 280*0Sstevel@tonic-gate { 281*0Sstevel@tonic-gate int num_mods; 282*0Sstevel@tonic-gate int i, pos; 283*0Sstevel@tonic-gate struct str_list strlist; 284*0Sstevel@tonic-gate boolean_t found_ip = B_FALSE; 285*0Sstevel@tonic-gate boolean_t found_nca = B_FALSE; 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) { 288*0Sstevel@tonic-gate logperror("ioctl(I_LIST) failed"); 289*0Sstevel@tonic-gate return (FOUND_NONE); 290*0Sstevel@tonic-gate } else { 291*0Sstevel@tonic-gate strlist.sl_nmods = num_mods; 292*0Sstevel@tonic-gate strlist.sl_modlist = calloc(num_mods, 293*0Sstevel@tonic-gate sizeof (struct str_mlist)); 294*0Sstevel@tonic-gate if (strlist.sl_modlist == NULL) { 295*0Sstevel@tonic-gate logperror("cannot malloc"); 296*0Sstevel@tonic-gate return (FOUND_NONE); 297*0Sstevel@tonic-gate } else { 298*0Sstevel@tonic-gate if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) { 299*0Sstevel@tonic-gate logperror("ioctl(I_LIST) failed"); 300*0Sstevel@tonic-gate } else { 301*0Sstevel@tonic-gate for (i = 0; i < strlist.sl_nmods; i++) { 302*0Sstevel@tonic-gate if (strcmp(IP_MOD_NAME, 303*0Sstevel@tonic-gate strlist.sl_modlist[i].l_name) 304*0Sstevel@tonic-gate == 0) { 305*0Sstevel@tonic-gate found_ip = B_TRUE; 306*0Sstevel@tonic-gate /* 307*0Sstevel@tonic-gate * NCA should be just below 308*0Sstevel@tonic-gate * IP. 309*0Sstevel@tonic-gate */ 310*0Sstevel@tonic-gate pos = i + 1; 311*0Sstevel@tonic-gate } else if (strncmp(NCA_MOD_NAME, 312*0Sstevel@tonic-gate strlist.sl_modlist[i].l_name, 313*0Sstevel@tonic-gate strlen(NCA_MOD_NAME)) == 0) { 314*0Sstevel@tonic-gate found_nca = B_TRUE; 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate } 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate free(strlist.sl_modlist); 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate if (found_nca) { 322*0Sstevel@tonic-gate return (FOUND_NCA); 323*0Sstevel@tonic-gate } else if (found_ip) { 324*0Sstevel@tonic-gate if (debug) { 325*0Sstevel@tonic-gate logdebug("NCA is at position %d in the stream.\n", pos); 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate return (pos); 328*0Sstevel@tonic-gate } else { 329*0Sstevel@tonic-gate if (debug) { 330*0Sstevel@tonic-gate logdebug("Cannot find IP??\n"); 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate return (FOUND_NONE); 333*0Sstevel@tonic-gate } 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate /* 337*0Sstevel@tonic-gate * To set the local IP address and default router ethernet address. 338*0Sstevel@tonic-gate * 339*0Sstevel@tonic-gate * Param: 340*0Sstevel@tonic-gate * int fd: the fd to the lower IP stream. 341*0Sstevel@tonic-gate * struct in_addr local_addr: the IP address for this interface. 342*0Sstevel@tonic-gate * uchar_t *ether_addr: the ethernet address of the default router for 343*0Sstevel@tonic-gate * for this interface. 344*0Sstevel@tonic-gate * 345*0Sstevel@tonic-gate * Return: 346*0Sstevel@tonic-gate * -1 if the system does not support this NCA ioctl(), 0 otherwise. 347*0Sstevel@tonic-gate */ 348*0Sstevel@tonic-gate static int 349*0Sstevel@tonic-gate nca_set_nif(int fd, struct in_addr local_addr, uchar_t *ether_addr) 350*0Sstevel@tonic-gate { 351*0Sstevel@tonic-gate struct nca_set_ioctl nca_ioctl; 352*0Sstevel@tonic-gate struct strioctl strioc; 353*0Sstevel@tonic-gate int len; 354*0Sstevel@tonic-gate uchar_t *dst; 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate strioc.ic_cmd = NCA_SET_IF; 357*0Sstevel@tonic-gate strioc.ic_timout = INFTIM; 358*0Sstevel@tonic-gate strioc.ic_len = sizeof (nca_ioctl); 359*0Sstevel@tonic-gate strioc.ic_dp = (char *)&nca_ioctl; 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate nca_ioctl.local_addr = local_addr.s_addr; 362*0Sstevel@tonic-gate dst = nca_ioctl.router_ether_addr; 363*0Sstevel@tonic-gate for (len = ETHERADDRL; len > 0; len--) 364*0Sstevel@tonic-gate *dst++ = *ether_addr++; 365*0Sstevel@tonic-gate nca_ioctl.action = ADD_DEF_ROUTE; 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate if (ioctl(fd, I_STR, &strioc) < 0) { 368*0Sstevel@tonic-gate logperror("ioctl(NCA_SET_IF) failed"); 369*0Sstevel@tonic-gate if (errno == EINVAL) 370*0Sstevel@tonic-gate return (-1); 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate return (0); 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate /* 376*0Sstevel@tonic-gate * To setup the NCA stream. First insert NCA into the proper position. 377*0Sstevel@tonic-gate * Then tell NCA the local IP address and default router by using the 378*0Sstevel@tonic-gate * NCA_SET_IF ioctl. 379*0Sstevel@tonic-gate * 380*0Sstevel@tonic-gate * Param: 381*0Sstevel@tonic-gate * boolean_t *active: (referenced) B_TRUE if NCA is setup to do active 382*0Sstevel@tonic-gate * connection. If NCA does not support active connection, 383*0Sstevel@tonic-gate * in return, active will be set to B_FALSE. 384*0Sstevel@tonic-gate */ 385*0Sstevel@tonic-gate static void 386*0Sstevel@tonic-gate nca_setup(boolean_t *active) 387*0Sstevel@tonic-gate { 388*0Sstevel@tonic-gate int i; 389*0Sstevel@tonic-gate int udp_fd; 390*0Sstevel@tonic-gate int fd; 391*0Sstevel@tonic-gate struct strmodconf mod; 392*0Sstevel@tonic-gate /* 128 is enough because interface name can only be LIFNAMSIZ long. */ 393*0Sstevel@tonic-gate char err_buf[128]; 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate mod.mod_name = NCA_MOD_NAME; 396*0Sstevel@tonic-gate lifr.lifr_addr.ss_family = AF_INET; 397*0Sstevel@tonic-gate for (i = 0; i < num_nif; i++) { 398*0Sstevel@tonic-gate if (debug) { 399*0Sstevel@tonic-gate logdebug("Plumbing NCA for %s\n", nif_list[i].name); 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate /* This interface does not exist according to IP. */ 402*0Sstevel@tonic-gate if (nif_list[i].local_addr.s_addr == 0) { 403*0Sstevel@tonic-gate continue; 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate (void) strlcpy(lifr.lifr_name, nif_list[i].name, 406*0Sstevel@tonic-gate sizeof (lifr.lifr_name)); 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate if (ip_domux2fd(&udp_fd, &fd) < 0) { 409*0Sstevel@tonic-gate continue; 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate if (ioctl(udp_fd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) { 412*0Sstevel@tonic-gate (void) snprintf(err_buf, sizeof (err_buf), 413*0Sstevel@tonic-gate "ioctl(I_PUNLINK) for %s failed", nif_list[i].name); 414*0Sstevel@tonic-gate logperror(err_buf); 415*0Sstevel@tonic-gate (void) close(udp_fd); 416*0Sstevel@tonic-gate (void) close(fd); 417*0Sstevel@tonic-gate continue; 418*0Sstevel@tonic-gate } 419*0Sstevel@tonic-gate if ((mod.pos = find_nca_pos(fd)) < 0) { 420*0Sstevel@tonic-gate if (mod.pos == FOUND_NCA) { 421*0Sstevel@tonic-gate if (debug) { 422*0Sstevel@tonic-gate logdebug("Find NCA in the %s" 423*0Sstevel@tonic-gate " stream\n", nif_list[i].name); 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate /* Just skip plumbing NCA. */ 426*0Sstevel@tonic-gate goto set_nif; 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate if (debug) { 429*0Sstevel@tonic-gate logdebug("Cannot find pos for %s\n", 430*0Sstevel@tonic-gate nif_list[i].name); 431*0Sstevel@tonic-gate } 432*0Sstevel@tonic-gate goto clean_up; 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate if (ioctl(fd, _I_INSERT, (caddr_t)&mod) < 0) { 435*0Sstevel@tonic-gate (void) snprintf(err_buf, sizeof (err_buf), 436*0Sstevel@tonic-gate "ioctl(_I_INSERT) for %s failed", nif_list[i].name); 437*0Sstevel@tonic-gate logperror(err_buf); 438*0Sstevel@tonic-gate goto clean_up; 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate /* 442*0Sstevel@tonic-gate * Only do the following if NCA is also used to make 443*0Sstevel@tonic-gate * outgoing connections, and all necessary info is 444*0Sstevel@tonic-gate * there. 445*0Sstevel@tonic-gate */ 446*0Sstevel@tonic-gate set_nif: 447*0Sstevel@tonic-gate if (*active && nif_list[i].router_addr.s_addr != 0) { 448*0Sstevel@tonic-gate if (nca_set_nif(fd, nif_list[i].local_addr, 449*0Sstevel@tonic-gate nif_list[i].router_ether_addr) < 0) { 450*0Sstevel@tonic-gate /* 451*0Sstevel@tonic-gate * The system does not support this ioctl()! 452*0Sstevel@tonic-gate * Skip all active stack processing but 453*0Sstevel@tonic-gate * continue to plumb NCA. 454*0Sstevel@tonic-gate */ 455*0Sstevel@tonic-gate logwarn("NCA does not support active stack!"); 456*0Sstevel@tonic-gate *active = B_FALSE; 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate clean_up: 460*0Sstevel@tonic-gate ip_plink(udp_fd, fd); 461*0Sstevel@tonic-gate (void) close(udp_fd); 462*0Sstevel@tonic-gate (void) close(fd); 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate /* 467*0Sstevel@tonic-gate * To get IP address of network interface from IP. 468*0Sstevel@tonic-gate */ 469*0Sstevel@tonic-gate static int 470*0Sstevel@tonic-gate get_if_ip_addr(void) 471*0Sstevel@tonic-gate { 472*0Sstevel@tonic-gate int sock; 473*0Sstevel@tonic-gate struct lifnum lifn; 474*0Sstevel@tonic-gate struct lifconf lifc; 475*0Sstevel@tonic-gate struct lifreq *lifr; 476*0Sstevel@tonic-gate struct sockaddr_in *sin; 477*0Sstevel@tonic-gate char *buf; 478*0Sstevel@tonic-gate int num_lifr; 479*0Sstevel@tonic-gate int i, j; 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate /* NCA only supports IPv4... */ 482*0Sstevel@tonic-gate if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 483*0Sstevel@tonic-gate logperror(gettext("Cannot open socket")); 484*0Sstevel@tonic-gate return (-1); 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate lifn.lifn_family = AF_UNSPEC; 487*0Sstevel@tonic-gate lifn.lifn_flags = 0; 488*0Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 489*0Sstevel@tonic-gate logperror(gettext("ioctl(SIOCGLIFNUM) failed")); 490*0Sstevel@tonic-gate (void) close(sock); 491*0Sstevel@tonic-gate return (-1); 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate buf = (char *)calloc(lifn.lifn_count, sizeof (struct lifreq)); 494*0Sstevel@tonic-gate if (buf == NULL) { 495*0Sstevel@tonic-gate logperror(gettext("calloc() failed")); 496*0Sstevel@tonic-gate (void) close(sock); 497*0Sstevel@tonic-gate return (-1); 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate lifc.lifc_family = AF_UNSPEC; 501*0Sstevel@tonic-gate lifc.lifc_flags = 0; 502*0Sstevel@tonic-gate lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 503*0Sstevel@tonic-gate lifc.lifc_buf = buf; 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 506*0Sstevel@tonic-gate /* 507*0Sstevel@tonic-gate * NCA is set up after all the interfaces have been 508*0Sstevel@tonic-gate * plumbed. So normally we should not get any error. 509*0Sstevel@tonic-gate * Just abort if we encounter an error. 510*0Sstevel@tonic-gate */ 511*0Sstevel@tonic-gate logperror(gettext("ioctl(SIOCGLIFCONF) failed")); 512*0Sstevel@tonic-gate free(buf); 513*0Sstevel@tonic-gate (void) close(sock); 514*0Sstevel@tonic-gate return (-1); 515*0Sstevel@tonic-gate } 516*0Sstevel@tonic-gate num_lifr = lifc.lifc_len / sizeof (struct lifreq); 517*0Sstevel@tonic-gate /* Find the interface and copy the local IP address. */ 518*0Sstevel@tonic-gate for (i = 0; i < num_nif; i++) { 519*0Sstevel@tonic-gate lifr = (struct lifreq *)lifc.lifc_req; 520*0Sstevel@tonic-gate for (j = num_lifr; j > 0; j--, lifr++) { 521*0Sstevel@tonic-gate /* Again, NCA only supports IPv4. */ 522*0Sstevel@tonic-gate if (lifr->lifr_addr.ss_family != AF_INET) 523*0Sstevel@tonic-gate continue; 524*0Sstevel@tonic-gate if (strncmp(nif_list[i].name, lifr->lifr_name, 525*0Sstevel@tonic-gate strlen(nif_list[i].name)) == 0) { 526*0Sstevel@tonic-gate sin = (struct sockaddr_in *)&lifr->lifr_addr; 527*0Sstevel@tonic-gate nif_list[i].local_addr = sin->sin_addr; 528*0Sstevel@tonic-gate if (debug) { 529*0Sstevel@tonic-gate logdebug("IP address of %s: %s\n", 530*0Sstevel@tonic-gate nif_list[i].name, 531*0Sstevel@tonic-gate inet_ntoa(sin->sin_addr)); 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate break; 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate if (j == 0) { 537*0Sstevel@tonic-gate /* 538*0Sstevel@tonic-gate * The interface does not exist according to IP! 539*0Sstevel@tonic-gate * Log a warning and go on. 540*0Sstevel@tonic-gate */ 541*0Sstevel@tonic-gate logwarn(gettext("Network interface %s" 542*0Sstevel@tonic-gate " does not exist!\n"), nif_list[i].name); 543*0Sstevel@tonic-gate /* 544*0Sstevel@tonic-gate * Set local_addr to 0 so that nca_setup() will 545*0Sstevel@tonic-gate * not do anything for this interface. 546*0Sstevel@tonic-gate */ 547*0Sstevel@tonic-gate nif_list[i].local_addr.s_addr = 0; 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate } 550*0Sstevel@tonic-gate free(buf); 551*0Sstevel@tonic-gate (void) close(sock); 552*0Sstevel@tonic-gate return (0); 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate /* 556*0Sstevel@tonic-gate * Get MIB2 info from IP. 557*0Sstevel@tonic-gate * 558*0Sstevel@tonic-gate * Param: 559*0Sstevel@tonic-gate * int sd: descriptor to IP to send down mib request. 560*0Sstevel@tonic-gate */ 561*0Sstevel@tonic-gate static mib_item_t * 562*0Sstevel@tonic-gate mibget(int sd) 563*0Sstevel@tonic-gate { 564*0Sstevel@tonic-gate char buf[1024]; 565*0Sstevel@tonic-gate int flags; 566*0Sstevel@tonic-gate int i, j, getcode; 567*0Sstevel@tonic-gate struct strbuf ctlbuf, databuf; 568*0Sstevel@tonic-gate /* LINTED */ 569*0Sstevel@tonic-gate struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 570*0Sstevel@tonic-gate /* LINTED */ 571*0Sstevel@tonic-gate struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 572*0Sstevel@tonic-gate /* LINTED */ 573*0Sstevel@tonic-gate struct T_error_ack *tea = (struct T_error_ack *)buf; 574*0Sstevel@tonic-gate struct opthdr *req; 575*0Sstevel@tonic-gate mib_item_t *first_item = (mib_item_t *)0; 576*0Sstevel@tonic-gate mib_item_t *last_item = (mib_item_t *)0; 577*0Sstevel@tonic-gate mib_item_t *temp; 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 580*0Sstevel@tonic-gate tor->OPT_offset = sizeof (struct T_optmgmt_req); 581*0Sstevel@tonic-gate tor->OPT_length = sizeof (struct opthdr); 582*0Sstevel@tonic-gate tor->MGMT_flags = T_CURRENT; 583*0Sstevel@tonic-gate req = (struct opthdr *)&tor[1]; 584*0Sstevel@tonic-gate req->level = MIB2_IP; /* any MIB2_xxx value ok here */ 585*0Sstevel@tonic-gate req->name = 0; 586*0Sstevel@tonic-gate req->len = 0; 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate ctlbuf.buf = buf; 589*0Sstevel@tonic-gate ctlbuf.len = tor->OPT_length + tor->OPT_offset; 590*0Sstevel@tonic-gate flags = 0; 591*0Sstevel@tonic-gate if (putmsg(sd, &ctlbuf, (struct strbuf *)0, flags) == -1) { 592*0Sstevel@tonic-gate logperror("mibget: putmsg(ctl) failed"); 593*0Sstevel@tonic-gate goto error_exit; 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate /* 597*0Sstevel@tonic-gate * Each reply consists of a ctl part for one fixed structure 598*0Sstevel@tonic-gate * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK, 599*0Sstevel@tonic-gate * containing an opthdr structure. level/name identify the entry, 600*0Sstevel@tonic-gate * len is the size of the data part of the message. 601*0Sstevel@tonic-gate */ 602*0Sstevel@tonic-gate req = (struct opthdr *)&toa[1]; 603*0Sstevel@tonic-gate ctlbuf.maxlen = sizeof (buf); 604*0Sstevel@tonic-gate j = 1; 605*0Sstevel@tonic-gate for (;;) { 606*0Sstevel@tonic-gate flags = 0; 607*0Sstevel@tonic-gate getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags); 608*0Sstevel@tonic-gate if (getcode == -1) { 609*0Sstevel@tonic-gate logperror("mibget getmsg(ctl) failed"); 610*0Sstevel@tonic-gate if (debug) { 611*0Sstevel@tonic-gate logdebug("# level name len\n"); 612*0Sstevel@tonic-gate i = 0; 613*0Sstevel@tonic-gate for (last_item = first_item; last_item; 614*0Sstevel@tonic-gate last_item = last_item->next_item) 615*0Sstevel@tonic-gate (void) printf("%d %4d %5d %d\n", 616*0Sstevel@tonic-gate ++i, 617*0Sstevel@tonic-gate last_item->group, 618*0Sstevel@tonic-gate last_item->mib_id, 619*0Sstevel@tonic-gate last_item->length); 620*0Sstevel@tonic-gate } 621*0Sstevel@tonic-gate goto error_exit; 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate if (getcode == 0 && 624*0Sstevel@tonic-gate ctlbuf.len >= sizeof (struct T_optmgmt_ack) && 625*0Sstevel@tonic-gate toa->PRIM_type == T_OPTMGMT_ACK && 626*0Sstevel@tonic-gate toa->MGMT_flags == T_SUCCESS && 627*0Sstevel@tonic-gate req->len == 0) { 628*0Sstevel@tonic-gate if (debug) { 629*0Sstevel@tonic-gate logdebug("mibget getmsg() %d returned " 630*0Sstevel@tonic-gate "EOD (level %ld, name %ld)\n", 631*0Sstevel@tonic-gate j, req->level, req->name); 632*0Sstevel@tonic-gate } 633*0Sstevel@tonic-gate return (first_item); /* this is EOD msg */ 634*0Sstevel@tonic-gate } 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate if (ctlbuf.len >= sizeof (struct T_error_ack) && 637*0Sstevel@tonic-gate tea->PRIM_type == T_ERROR_ACK) { 638*0Sstevel@tonic-gate logwarn("mibget %d gives T_ERROR_ACK: TLI_error =" 639*0Sstevel@tonic-gate " 0x%lx, UNIX_error = 0x%lx\n", 640*0Sstevel@tonic-gate j, tea->TLI_error, tea->UNIX_error); 641*0Sstevel@tonic-gate errno = (tea->TLI_error == TSYSERR) ? 642*0Sstevel@tonic-gate tea->UNIX_error : EPROTO; 643*0Sstevel@tonic-gate goto error_exit; 644*0Sstevel@tonic-gate } 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate if (getcode != MOREDATA || 647*0Sstevel@tonic-gate ctlbuf.len < sizeof (struct T_optmgmt_ack) || 648*0Sstevel@tonic-gate toa->PRIM_type != T_OPTMGMT_ACK || 649*0Sstevel@tonic-gate toa->MGMT_flags != T_SUCCESS) { 650*0Sstevel@tonic-gate logwarn("mibget getmsg(ctl) %d returned %d, " 651*0Sstevel@tonic-gate "ctlbuf.len = %d, PRIM_type = %ld\n", 652*0Sstevel@tonic-gate j, getcode, ctlbuf.len, toa->PRIM_type); 653*0Sstevel@tonic-gate if (toa->PRIM_type == T_OPTMGMT_ACK) { 654*0Sstevel@tonic-gate logwarn("T_OPTMGMT_ACK: " 655*0Sstevel@tonic-gate "MGMT_flags = 0x%lx, req->len = %ld\n", 656*0Sstevel@tonic-gate toa->MGMT_flags, req->len); 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate errno = ENOMSG; 659*0Sstevel@tonic-gate goto error_exit; 660*0Sstevel@tonic-gate } 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate temp = (mib_item_t *)malloc(sizeof (mib_item_t)); 663*0Sstevel@tonic-gate if (!temp) { 664*0Sstevel@tonic-gate logperror("mibget malloc failed"); 665*0Sstevel@tonic-gate goto error_exit; 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate if (last_item) 668*0Sstevel@tonic-gate last_item->next_item = temp; 669*0Sstevel@tonic-gate else 670*0Sstevel@tonic-gate first_item = temp; 671*0Sstevel@tonic-gate last_item = temp; 672*0Sstevel@tonic-gate last_item->next_item = (mib_item_t *)0; 673*0Sstevel@tonic-gate last_item->group = req->level; 674*0Sstevel@tonic-gate last_item->mib_id = req->name; 675*0Sstevel@tonic-gate last_item->length = req->len; 676*0Sstevel@tonic-gate last_item->valp = malloc((int)req->len); 677*0Sstevel@tonic-gate 678*0Sstevel@tonic-gate databuf.maxlen = last_item->length; 679*0Sstevel@tonic-gate databuf.buf = last_item->valp; 680*0Sstevel@tonic-gate databuf.len = 0; 681*0Sstevel@tonic-gate flags = 0; 682*0Sstevel@tonic-gate getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags); 683*0Sstevel@tonic-gate if (getcode == -1) { 684*0Sstevel@tonic-gate logperror("mibget getmsg(data) failed"); 685*0Sstevel@tonic-gate goto error_exit; 686*0Sstevel@tonic-gate } else if (getcode != 0) { 687*0Sstevel@tonic-gate logwarn("mibget getmsg(data) returned %d, " 688*0Sstevel@tonic-gate "databuf.maxlen = %d, databuf.len = %d\n", 689*0Sstevel@tonic-gate getcode, databuf.maxlen, databuf.len); 690*0Sstevel@tonic-gate goto error_exit; 691*0Sstevel@tonic-gate } 692*0Sstevel@tonic-gate j++; 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate 695*0Sstevel@tonic-gate error_exit:; 696*0Sstevel@tonic-gate while (first_item) { 697*0Sstevel@tonic-gate last_item = first_item; 698*0Sstevel@tonic-gate first_item = first_item->next_item; 699*0Sstevel@tonic-gate free(last_item); 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate return (first_item); 702*0Sstevel@tonic-gate } 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate /* 705*0Sstevel@tonic-gate * Examine the IPv4 routing table for default routers. For each interface, 706*0Sstevel@tonic-gate * find its default router. 707*0Sstevel@tonic-gate * 708*0Sstevel@tonic-gate * Param: 709*0Sstevel@tonic-gate * mib2_ipRouteEntry_t *buf: the mib info buffer. 710*0Sstevel@tonic-gate * size_t len: length of buffer. 711*0Sstevel@tonic-gate * boolean_t *changed (referenced): set to B_TRUE if there is a change 712*0Sstevel@tonic-gate * in router info. 713*0Sstevel@tonic-gate * 714*0Sstevel@tonic-gate * Return: 715*0Sstevel@tonic-gate * number of default router found. 716*0Sstevel@tonic-gate */ 717*0Sstevel@tonic-gate static int 718*0Sstevel@tonic-gate ire_process(mib2_ipRouteEntry_t *buf, size_t len, boolean_t *changed) 719*0Sstevel@tonic-gate { 720*0Sstevel@tonic-gate mib2_ipRouteEntry_t *rp; 721*0Sstevel@tonic-gate mib2_ipRouteEntry_t *rp1; 722*0Sstevel@tonic-gate mib2_ipRouteEntry_t *rp2; 723*0Sstevel@tonic-gate struct in_addr nexthop_v4; 724*0Sstevel@tonic-gate mib2_ipRouteEntry_t *endp; 725*0Sstevel@tonic-gate char ifname[LIFNAMSIZ + 1]; 726*0Sstevel@tonic-gate char *cp; 727*0Sstevel@tonic-gate int i; 728*0Sstevel@tonic-gate int ifname_len; 729*0Sstevel@tonic-gate boolean_t found; 730*0Sstevel@tonic-gate int num_found = 0; 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate if (len == 0) 733*0Sstevel@tonic-gate return (0); 734*0Sstevel@tonic-gate endp = buf + (len / sizeof (mib2_ipRouteEntry_t)); 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate for (i = 0; i < num_nif; i++) { 737*0Sstevel@tonic-gate /* 738*0Sstevel@tonic-gate * Loop thru the routing table entries. Process any 739*0Sstevel@tonic-gate * IRE_DEFAULT ire. Ignore the others. For each such 740*0Sstevel@tonic-gate * ire, get the nexthop gateway address. 741*0Sstevel@tonic-gate */ 742*0Sstevel@tonic-gate found = B_FALSE; 743*0Sstevel@tonic-gate for (rp = buf; rp < endp; rp++) { 744*0Sstevel@tonic-gate /* 745*0Sstevel@tonic-gate * NCA is only interested in default routes associated 746*0Sstevel@tonic-gate * with an interface. 747*0Sstevel@tonic-gate */ 748*0Sstevel@tonic-gate if (!(rp->ipRouteInfo.re_ire_type & IRE_DEFAULT)) { 749*0Sstevel@tonic-gate continue; 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate /* Get the nexthop address. */ 752*0Sstevel@tonic-gate nexthop_v4.s_addr = rp->ipRouteNextHop; 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate /* 755*0Sstevel@tonic-gate * Right now, not all IREs have the interface name 756*0Sstevel@tonic-gate * it is associated with. 757*0Sstevel@tonic-gate */ 758*0Sstevel@tonic-gate if (rp->ipRouteIfIndex.o_length == 0) { 759*0Sstevel@tonic-gate /* 760*0Sstevel@tonic-gate * We don't have the outgoing interface in 761*0Sstevel@tonic-gate * this case. Get the nexthop address. Then 762*0Sstevel@tonic-gate * determine the outgoing interface, by 763*0Sstevel@tonic-gate * examining all interface IREs, and 764*0Sstevel@tonic-gate * picking the match. 765*0Sstevel@tonic-gate */ 766*0Sstevel@tonic-gate for (rp1 = buf; rp1 < endp; rp1++) { 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate if (!(rp1->ipRouteInfo.re_ire_type & 769*0Sstevel@tonic-gate IRE_INTERFACE)) { 770*0Sstevel@tonic-gate continue; 771*0Sstevel@tonic-gate } 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gate /* 774*0Sstevel@tonic-gate * Determine the interface IRE that 775*0Sstevel@tonic-gate * matches the nexthop. i.e. 776*0Sstevel@tonic-gate * (IRE addr & IRE mask) == 777*0Sstevel@tonic-gate * (nexthop & IRE mask) 778*0Sstevel@tonic-gate */ 779*0Sstevel@tonic-gate if ((rp1->ipRouteDest & rp1->ipRouteMask) == 780*0Sstevel@tonic-gate (nexthop_v4.s_addr & rp1->ipRouteMask)) { 781*0Sstevel@tonic-gate /* 782*0Sstevel@tonic-gate * We found the interface to go to 783*0Sstevel@tonic-gate * the default router. Check the 784*0Sstevel@tonic-gate * interface name. 785*0Sstevel@tonic-gate */ 786*0Sstevel@tonic-gate /* Can this be possible?? */ 787*0Sstevel@tonic-gate if (rp1->ipRouteIfIndex.o_length == 0) 788*0Sstevel@tonic-gate continue; 789*0Sstevel@tonic-gate rp2 = rp1; 790*0Sstevel@tonic-gate break; 791*0Sstevel@tonic-gate } 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate } /* End inner for loop. */ 794*0Sstevel@tonic-gate } else { 795*0Sstevel@tonic-gate rp2 = rp; 796*0Sstevel@tonic-gate } 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate ifname_len = MIN(rp2->ipRouteIfIndex.o_length, 799*0Sstevel@tonic-gate sizeof (ifname) - 1); 800*0Sstevel@tonic-gate (void) memcpy(ifname, rp2->ipRouteIfIndex.o_bytes, 801*0Sstevel@tonic-gate ifname_len); 802*0Sstevel@tonic-gate ifname[ifname_len] = '\0'; 803*0Sstevel@tonic-gate if (ifname[0] == '\0') 804*0Sstevel@tonic-gate continue; 805*0Sstevel@tonic-gate cp = strchr(ifname, IF_SEPARATOR); 806*0Sstevel@tonic-gate if (cp != NULL) 807*0Sstevel@tonic-gate *cp = '\0'; 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate /* We are sure both are NULL terminated. */ 810*0Sstevel@tonic-gate if (strcmp(nif_list[i].name, ifname) == 0) { 811*0Sstevel@tonic-gate /* No change, do not do anything. */ 812*0Sstevel@tonic-gate if (nexthop_v4.s_addr == 813*0Sstevel@tonic-gate nif_list[i].router_addr.s_addr) { 814*0Sstevel@tonic-gate found = B_TRUE; 815*0Sstevel@tonic-gate break; 816*0Sstevel@tonic-gate } 817*0Sstevel@tonic-gate nif_list[i].router_addr.s_addr = 818*0Sstevel@tonic-gate nexthop_v4.s_addr; 819*0Sstevel@tonic-gate if (debug) { 820*0Sstevel@tonic-gate logdebug("Get default" 821*0Sstevel@tonic-gate " router for %s: %s\n", ifname, 822*0Sstevel@tonic-gate inet_ntoa(nexthop_v4)); 823*0Sstevel@tonic-gate } 824*0Sstevel@tonic-gate found = B_TRUE; 825*0Sstevel@tonic-gate *changed = B_TRUE; 826*0Sstevel@tonic-gate break; 827*0Sstevel@tonic-gate } 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate } 830*0Sstevel@tonic-gate if (!found) { 831*0Sstevel@tonic-gate /* 832*0Sstevel@tonic-gate * The interface does not have a default router. 833*0Sstevel@tonic-gate * Log a warning and go on. 834*0Sstevel@tonic-gate */ 835*0Sstevel@tonic-gate logwarn(gettext("Network interface %s" 836*0Sstevel@tonic-gate " does not have a default router.\n"), 837*0Sstevel@tonic-gate nif_list[i].name); 838*0Sstevel@tonic-gate /* 839*0Sstevel@tonic-gate * Set router_addr to 0 so that we will 840*0Sstevel@tonic-gate * not do anything for this interface. 841*0Sstevel@tonic-gate */ 842*0Sstevel@tonic-gate nif_list[i].router_addr.s_addr = 0; 843*0Sstevel@tonic-gate } else { 844*0Sstevel@tonic-gate num_found++; 845*0Sstevel@tonic-gate } 846*0Sstevel@tonic-gate } 847*0Sstevel@tonic-gate return (num_found); 848*0Sstevel@tonic-gate } 849*0Sstevel@tonic-gate 850*0Sstevel@tonic-gate /* 851*0Sstevel@tonic-gate * Examine the ARP table to find ethernet address for default routers. 852*0Sstevel@tonic-gate * 853*0Sstevel@tonic-gate * Param: 854*0Sstevel@tonic-gate * mib2_ipNetToMdeiaEntry_t *buf: the mib info buffer. 855*0Sstevel@tonic-gate * size_t len: length of buffer. 856*0Sstevel@tonic-gate * boolean_t *changed (referenced): set to B_TRUE if there is any change 857*0Sstevel@tonic-gate * in ethernet address for any default router. 858*0Sstevel@tonic-gate * 859*0Sstevel@tonic-gate * Return: 860*0Sstevel@tonic-gate * number of ethernet address found. 861*0Sstevel@tonic-gate */ 862*0Sstevel@tonic-gate static int 863*0Sstevel@tonic-gate arp_process(mib2_ipNetToMediaEntry_t *buf, size_t len, boolean_t *changed) 864*0Sstevel@tonic-gate { 865*0Sstevel@tonic-gate mib2_ipNetToMediaEntry_t *rp; 866*0Sstevel@tonic-gate mib2_ipNetToMediaEntry_t *endp; 867*0Sstevel@tonic-gate int i; 868*0Sstevel@tonic-gate boolean_t found; 869*0Sstevel@tonic-gate int num_found = 0; 870*0Sstevel@tonic-gate uchar_t *src, *dst; 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate if (len == 0) 873*0Sstevel@tonic-gate return (0); 874*0Sstevel@tonic-gate endp = buf + (len / sizeof (mib2_ipNetToMediaEntry_t)); 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate for (i = 0; i < num_nif; i++) { 877*0Sstevel@tonic-gate /* 878*0Sstevel@tonic-gate * Loop thru the arp table entries and find the ethernet 879*0Sstevel@tonic-gate * address of those default routers. 880*0Sstevel@tonic-gate */ 881*0Sstevel@tonic-gate if (nif_list[i].router_addr.s_addr == 0) 882*0Sstevel@tonic-gate continue; 883*0Sstevel@tonic-gate found = B_FALSE; 884*0Sstevel@tonic-gate for (rp = buf; rp < endp; rp++) { 885*0Sstevel@tonic-gate if (rp->ipNetToMediaNetAddress == 886*0Sstevel@tonic-gate nif_list[i].router_addr.s_addr) { 887*0Sstevel@tonic-gate /* 888*0Sstevel@tonic-gate * Sanity check. Make sure that this 889*0Sstevel@tonic-gate * default router is only reachable thru this 890*0Sstevel@tonic-gate * interface. 891*0Sstevel@tonic-gate */ 892*0Sstevel@tonic-gate if (rp->ipNetToMediaIfIndex.o_length != 893*0Sstevel@tonic-gate strlen(nif_list[i].name) || 894*0Sstevel@tonic-gate strncmp(rp->ipNetToMediaIfIndex.o_bytes, 895*0Sstevel@tonic-gate nif_list[i].name, 896*0Sstevel@tonic-gate rp->ipNetToMediaIfIndex.o_length) != 897*0Sstevel@tonic-gate 0) { 898*0Sstevel@tonic-gate break; 899*0Sstevel@tonic-gate } 900*0Sstevel@tonic-gate /* No change, do not do anything. */ 901*0Sstevel@tonic-gate if (bcmp(nif_list[i].router_ether_addr, 902*0Sstevel@tonic-gate rp->ipNetToMediaPhysAddress.o_bytes, 903*0Sstevel@tonic-gate ETHERADDRL) == 0) { 904*0Sstevel@tonic-gate found = B_TRUE; 905*0Sstevel@tonic-gate continue; 906*0Sstevel@tonic-gate } 907*0Sstevel@tonic-gate dst = nif_list[i].router_ether_addr; 908*0Sstevel@tonic-gate src = (uchar_t *) 909*0Sstevel@tonic-gate rp->ipNetToMediaPhysAddress.o_bytes; 910*0Sstevel@tonic-gate for (len = ETHERADDRL; len > 0; len--) 911*0Sstevel@tonic-gate *dst++ = *src++; 912*0Sstevel@tonic-gate if (debug) { 913*0Sstevel@tonic-gate int j; 914*0Sstevel@tonic-gate uchar_t *cp; 915*0Sstevel@tonic-gate char err_buf[128]; 916*0Sstevel@tonic-gate 917*0Sstevel@tonic-gate (void) snprintf(err_buf, 918*0Sstevel@tonic-gate sizeof (err_buf), 919*0Sstevel@tonic-gate "Get address for %s: ", 920*0Sstevel@tonic-gate inet_ntoa(nif_list[i].router_addr)); 921*0Sstevel@tonic-gate cp = (uchar_t *) 922*0Sstevel@tonic-gate nif_list[i].router_ether_addr; 923*0Sstevel@tonic-gate for (j = 0; j < ETHERADDRL; j++) { 924*0Sstevel@tonic-gate (void) sprintf(err_buf + 925*0Sstevel@tonic-gate strlen(err_buf), 926*0Sstevel@tonic-gate "%02x:", 0xff & cp[j]); 927*0Sstevel@tonic-gate } 928*0Sstevel@tonic-gate (void) sprintf(err_buf + 929*0Sstevel@tonic-gate strlen(err_buf) - 1, "\n"); 930*0Sstevel@tonic-gate logdebug(err_buf); 931*0Sstevel@tonic-gate } 932*0Sstevel@tonic-gate found = B_TRUE; 933*0Sstevel@tonic-gate *changed = B_TRUE; 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate } 936*0Sstevel@tonic-gate if (!found) { 937*0Sstevel@tonic-gate logwarn("Cannot reach %s using %s\n", 938*0Sstevel@tonic-gate inet_ntoa(nif_list[i].router_addr), 939*0Sstevel@tonic-gate nif_list[i].name); 940*0Sstevel@tonic-gate /* Clear this default router. */ 941*0Sstevel@tonic-gate nif_list[i].router_addr.s_addr = 0; 942*0Sstevel@tonic-gate } else { 943*0Sstevel@tonic-gate num_found++; 944*0Sstevel@tonic-gate } 945*0Sstevel@tonic-gate } 946*0Sstevel@tonic-gate return (num_found); 947*0Sstevel@tonic-gate } 948*0Sstevel@tonic-gate 949*0Sstevel@tonic-gate /* 950*0Sstevel@tonic-gate * Get IP address of default routers for each interface. 951*0Sstevel@tonic-gate * 952*0Sstevel@tonic-gate * Param: 953*0Sstevel@tonic-gate * mib_item_t *item: the mib info buffer. 954*0Sstevel@tonic-gate * boolean_t *changed (referenced): set to B_TRUE if there is any change 955*0Sstevel@tonic-gate * in router info. 956*0Sstevel@tonic-gate * 957*0Sstevel@tonic-gate * Return: 958*0Sstevel@tonic-gate * -1 if there is no router found, 0 otherwise. 959*0Sstevel@tonic-gate */ 960*0Sstevel@tonic-gate static int 961*0Sstevel@tonic-gate get_router_ip_addr(mib_item_t *item, boolean_t *changed) 962*0Sstevel@tonic-gate { 963*0Sstevel@tonic-gate int found = 0; 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 966*0Sstevel@tonic-gate /* NCA does not support IPv6... */ 967*0Sstevel@tonic-gate if (!(item->group == MIB2_IP && item->mib_id == MIB2_IP_ROUTE)) 968*0Sstevel@tonic-gate continue; 969*0Sstevel@tonic-gate /* LINTED */ 970*0Sstevel@tonic-gate found += ire_process((mib2_ipRouteEntry_t *)item->valp, 971*0Sstevel@tonic-gate item->length, changed); 972*0Sstevel@tonic-gate } 973*0Sstevel@tonic-gate if (found == 0) 974*0Sstevel@tonic-gate return (-1); 975*0Sstevel@tonic-gate else 976*0Sstevel@tonic-gate return (0); 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate /* 980*0Sstevel@tonic-gate * Get Ethernet address for each default router from ARP. 981*0Sstevel@tonic-gate * 982*0Sstevel@tonic-gate * Param: 983*0Sstevel@tonic-gate * mib_item_t *item: the mib info buffer. 984*0Sstevel@tonic-gate * boolean_t *changed (referenced): set to B_TRUE if there is any change 985*0Sstevel@tonic-gate * in ethernet address of router. 986*0Sstevel@tonic-gate * 987*0Sstevel@tonic-gate * Return: 988*0Sstevel@tonic-gate * -1 if there is no ethernet address found, 0 otherwise. 989*0Sstevel@tonic-gate */ 990*0Sstevel@tonic-gate static int 991*0Sstevel@tonic-gate get_router_ether_addr(mib_item_t *item, boolean_t *changed) 992*0Sstevel@tonic-gate { 993*0Sstevel@tonic-gate int found = 0; 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 996*0Sstevel@tonic-gate /* NCA does not support IPv6... */ 997*0Sstevel@tonic-gate if (!(item->group == MIB2_IP && item->mib_id == MIB2_IP_MEDIA)) 998*0Sstevel@tonic-gate continue; 999*0Sstevel@tonic-gate /* LINTED */ 1000*0Sstevel@tonic-gate found += arp_process((mib2_ipNetToMediaEntry_t *)item->valp, 1001*0Sstevel@tonic-gate item->length, changed); 1002*0Sstevel@tonic-gate } 1003*0Sstevel@tonic-gate if (found == 0) 1004*0Sstevel@tonic-gate return (-1); 1005*0Sstevel@tonic-gate else 1006*0Sstevel@tonic-gate return (0); 1007*0Sstevel@tonic-gate } 1008*0Sstevel@tonic-gate 1009*0Sstevel@tonic-gate /* 1010*0Sstevel@tonic-gate * Ping all default routers. It just uses system(3F) to call 1011*0Sstevel@tonic-gate * ping(1M) to do the job... 1012*0Sstevel@tonic-gate */ 1013*0Sstevel@tonic-gate static void 1014*0Sstevel@tonic-gate ping_them(void) 1015*0Sstevel@tonic-gate { 1016*0Sstevel@tonic-gate int i; 1017*0Sstevel@tonic-gate char ping_cmd[128]; 1018*0Sstevel@tonic-gate 1019*0Sstevel@tonic-gate for (i = 0; i < num_nif; i++) { 1020*0Sstevel@tonic-gate if (nif_list[i].router_addr.s_addr != 0) { 1021*0Sstevel@tonic-gate (void) snprintf(ping_cmd, sizeof (ping_cmd), 1022*0Sstevel@tonic-gate "%s %s > /dev/null 2>&1", 1023*0Sstevel@tonic-gate ping_prog, 1024*0Sstevel@tonic-gate inet_ntoa(nif_list[i].router_addr)); 1025*0Sstevel@tonic-gate (void) system(ping_cmd); 1026*0Sstevel@tonic-gate } 1027*0Sstevel@tonic-gate } 1028*0Sstevel@tonic-gate } 1029*0Sstevel@tonic-gate 1030*0Sstevel@tonic-gate /* 1031*0Sstevel@tonic-gate * To get default router info (both IP address and ethernet address) for 1032*0Sstevel@tonic-gate * each configured interface from IP. 1033*0Sstevel@tonic-gate * 1034*0Sstevel@tonic-gate * Param: 1035*0Sstevel@tonic-gate * boolean_t *changed (referenced): set to B_TRUE if there is any change 1036*0Sstevel@tonic-gate * of info. 1037*0Sstevel@tonic-gate * 1038*0Sstevel@tonic-gate * Return: 1039*0Sstevel@tonic-gate * -1 if there is any error, 0 if everything is fine. 1040*0Sstevel@tonic-gate */ 1041*0Sstevel@tonic-gate static int 1042*0Sstevel@tonic-gate get_if_info(boolean_t *changed) 1043*0Sstevel@tonic-gate { 1044*0Sstevel@tonic-gate int mib_fd; 1045*0Sstevel@tonic-gate mib_item_t *item; 1046*0Sstevel@tonic-gate boolean_t ip_changed = B_FALSE; 1047*0Sstevel@tonic-gate boolean_t ether_changed = B_FALSE; 1048*0Sstevel@tonic-gate 1049*0Sstevel@tonic-gate if ((mib_fd = open(IP_DEV_NAME, O_RDWR)) < 0) { 1050*0Sstevel@tonic-gate logperror("cannot open ip to get router info"); 1051*0Sstevel@tonic-gate return (-1); 1052*0Sstevel@tonic-gate } 1053*0Sstevel@tonic-gate if (ioctl(mib_fd, I_PUSH, ARP_MOD_NAME) == -1) { 1054*0Sstevel@tonic-gate logperror("cannot push arp"); 1055*0Sstevel@tonic-gate goto err; 1056*0Sstevel@tonic-gate } 1057*0Sstevel@tonic-gate 1058*0Sstevel@tonic-gate if ((item = mibget(mib_fd)) == NULL) { 1059*0Sstevel@tonic-gate goto err; 1060*0Sstevel@tonic-gate } 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate if (get_router_ip_addr(item, &ip_changed) < 0) { 1063*0Sstevel@tonic-gate goto err; 1064*0Sstevel@tonic-gate } 1065*0Sstevel@tonic-gate /* 1066*0Sstevel@tonic-gate * Ping every routers to make sure that ARP has all their ethernet 1067*0Sstevel@tonic-gate * addresses. 1068*0Sstevel@tonic-gate */ 1069*0Sstevel@tonic-gate ping_them(); 1070*0Sstevel@tonic-gate /* 1071*0Sstevel@tonic-gate * If the router IP address is not changed, its ethernet address 1072*0Sstevel@tonic-gate * should not be changed. But just in case there is some IP 1073*0Sstevel@tonic-gate * failover going on... 1074*0Sstevel@tonic-gate */ 1075*0Sstevel@tonic-gate if (get_router_ether_addr(item, ðer_changed) < 0) { 1076*0Sstevel@tonic-gate goto err; 1077*0Sstevel@tonic-gate } 1078*0Sstevel@tonic-gate (void) close(mib_fd); 1079*0Sstevel@tonic-gate *changed = ip_changed || ether_changed; 1080*0Sstevel@tonic-gate return (0); 1081*0Sstevel@tonic-gate err: 1082*0Sstevel@tonic-gate (void) close(mib_fd); 1083*0Sstevel@tonic-gate return (-1); 1084*0Sstevel@tonic-gate } 1085*0Sstevel@tonic-gate 1086*0Sstevel@tonic-gate /* 1087*0Sstevel@tonic-gate * To remove the default router from an interface. 1088*0Sstevel@tonic-gate * 1089*0Sstevel@tonic-gate * Param: 1090*0Sstevel@tonic-gate * struct in_addr gw_addr: the IP address of the default router to be 1091*0Sstevel@tonic-gate * removed. 1092*0Sstevel@tonic-gate */ 1093*0Sstevel@tonic-gate static void 1094*0Sstevel@tonic-gate nca_del_nif(struct in_addr gw_addr) 1095*0Sstevel@tonic-gate { 1096*0Sstevel@tonic-gate struct nca_set_ioctl nca_ioctl; 1097*0Sstevel@tonic-gate struct strioctl strioc; 1098*0Sstevel@tonic-gate int i; 1099*0Sstevel@tonic-gate int udp_fd, fd; 1100*0Sstevel@tonic-gate 1101*0Sstevel@tonic-gate /* Search for the interface for this router. */ 1102*0Sstevel@tonic-gate for (i = 0; i < num_nif; i++) { 1103*0Sstevel@tonic-gate if (nif_list[i].router_addr.s_addr == gw_addr.s_addr) 1104*0Sstevel@tonic-gate break; 1105*0Sstevel@tonic-gate } 1106*0Sstevel@tonic-gate if (i == num_nif) 1107*0Sstevel@tonic-gate return; 1108*0Sstevel@tonic-gate 1109*0Sstevel@tonic-gate if (ip_domux2fd(&udp_fd, &fd) < 0) { 1110*0Sstevel@tonic-gate logwarn(gettext("Removing interface %s from the" 1111*0Sstevel@tonic-gate " configuration list.\n"), nif_list[i].name); 1112*0Sstevel@tonic-gate nif_list[i].name[0] = 0; 1113*0Sstevel@tonic-gate return; 1114*0Sstevel@tonic-gate } 1115*0Sstevel@tonic-gate if (ioctl(udp_fd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) { 1116*0Sstevel@tonic-gate logwarn(gettext("Removing interface %s from the" 1117*0Sstevel@tonic-gate " configuration list.\n"), nif_list[i].name); 1118*0Sstevel@tonic-gate nif_list[i].name[0] = 0; 1119*0Sstevel@tonic-gate (void) close(udp_fd); 1120*0Sstevel@tonic-gate (void) close(fd); 1121*0Sstevel@tonic-gate return; 1122*0Sstevel@tonic-gate } 1123*0Sstevel@tonic-gate 1124*0Sstevel@tonic-gate strioc.ic_cmd = NCA_SET_IF; 1125*0Sstevel@tonic-gate strioc.ic_timout = INFTIM; 1126*0Sstevel@tonic-gate strioc.ic_len = sizeof (nca_ioctl); 1127*0Sstevel@tonic-gate strioc.ic_dp = (char *)&nca_ioctl; 1128*0Sstevel@tonic-gate 1129*0Sstevel@tonic-gate nca_ioctl.local_addr = 0; 1130*0Sstevel@tonic-gate (void) memset(nca_ioctl.router_ether_addr, 0, ETHERADDRL); 1131*0Sstevel@tonic-gate nca_ioctl.action = DEL_DEF_ROUTE; 1132*0Sstevel@tonic-gate 1133*0Sstevel@tonic-gate if (ioctl(fd, I_STR, &strioc) < 0) { 1134*0Sstevel@tonic-gate logperror("ioctl(NCA_SET_IF) failed"); 1135*0Sstevel@tonic-gate } 1136*0Sstevel@tonic-gate ip_plink(udp_fd, fd); 1137*0Sstevel@tonic-gate (void) close(udp_fd); 1138*0Sstevel@tonic-gate (void) close(fd); 1139*0Sstevel@tonic-gate 1140*0Sstevel@tonic-gate /* Clear the fields for this interface. */ 1141*0Sstevel@tonic-gate nif_list[i].router_addr.s_addr = 0; 1142*0Sstevel@tonic-gate (void) memset(nif_list[i].router_ether_addr, 0, ETHERADDRL); 1143*0Sstevel@tonic-gate } 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate /* 1146*0Sstevel@tonic-gate * Wait for any changes in the routing table. If there are changes to 1147*0Sstevel@tonic-gate * IP address or router ethernet address, send down the info to NCA. 1148*0Sstevel@tonic-gate */ 1149*0Sstevel@tonic-gate static void 1150*0Sstevel@tonic-gate daemon_work(void) 1151*0Sstevel@tonic-gate { 1152*0Sstevel@tonic-gate int n; 1153*0Sstevel@tonic-gate int i; 1154*0Sstevel@tonic-gate int udp_fd; 1155*0Sstevel@tonic-gate int fd; 1156*0Sstevel@tonic-gate int64_t msg[2048/8]; 1157*0Sstevel@tonic-gate struct rt_msghdr *rtm; 1158*0Sstevel@tonic-gate boolean_t changed; 1159*0Sstevel@tonic-gate struct sockaddr_in *sin; 1160*0Sstevel@tonic-gate struct in_addr gw_addr; 1161*0Sstevel@tonic-gate uchar_t *cp; 1162*0Sstevel@tonic-gate 1163*0Sstevel@tonic-gate /* Loop forever waiting for any routing changes. */ 1164*0Sstevel@tonic-gate for (;;) { 1165*0Sstevel@tonic-gate if (debug) { 1166*0Sstevel@tonic-gate logdebug("Waiting to read routing info...\n"); 1167*0Sstevel@tonic-gate } 1168*0Sstevel@tonic-gate n = read(rt_fd, msg, sizeof (msg)); 1169*0Sstevel@tonic-gate /* Don't die... Reinitialize socket and listen again. */ 1170*0Sstevel@tonic-gate if (n <= 0) { 1171*0Sstevel@tonic-gate if (debug) { 1172*0Sstevel@tonic-gate logdebug("Routing socket read error.\n"); 1173*0Sstevel@tonic-gate } 1174*0Sstevel@tonic-gate (void) close(rt_fd); 1175*0Sstevel@tonic-gate rt_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET); 1176*0Sstevel@tonic-gate i = 0; 1177*0Sstevel@tonic-gate while (rt_fd < 0) { 1178*0Sstevel@tonic-gate if (i++ == 0) { 1179*0Sstevel@tonic-gate logperror(gettext("cannot reinitialize" 1180*0Sstevel@tonic-gate " routing socket")); 1181*0Sstevel@tonic-gate } else if (i > 5) { 1182*0Sstevel@tonic-gate logwarn(gettext("Give up on trying to" 1183*0Sstevel@tonic-gate " reinitializing routing" 1184*0Sstevel@tonic-gate " socket\n")); 1185*0Sstevel@tonic-gate exit(1); 1186*0Sstevel@tonic-gate } 1187*0Sstevel@tonic-gate /* May be a transient error... */ 1188*0Sstevel@tonic-gate (void) sleep(10); 1189*0Sstevel@tonic-gate rt_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET); 1190*0Sstevel@tonic-gate } 1191*0Sstevel@tonic-gate } else { 1192*0Sstevel@tonic-gate rtm = (struct rt_msghdr *)msg; 1193*0Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 1194*0Sstevel@tonic-gate logwarn(gettext("Do non understand routing" 1195*0Sstevel@tonic-gate " socket info.\n")); 1196*0Sstevel@tonic-gate continue; 1197*0Sstevel@tonic-gate } 1198*0Sstevel@tonic-gate if (debug) { 1199*0Sstevel@tonic-gate logdebug("Get routing info.\n"); 1200*0Sstevel@tonic-gate } 1201*0Sstevel@tonic-gate switch (rtm->rtm_type) { 1202*0Sstevel@tonic-gate case RTM_DELETE: 1203*0Sstevel@tonic-gate case RTM_OLDDEL: 1204*0Sstevel@tonic-gate sin = (struct sockaddr_in *)(rtm + 1); 1205*0Sstevel@tonic-gate cp = (uchar_t *)sin; 1206*0Sstevel@tonic-gate /* Only handle default route deletion. */ 1207*0Sstevel@tonic-gate if ((rtm->rtm_addrs & RTA_DST) && 1208*0Sstevel@tonic-gate (sin->sin_addr.s_addr == 0)) { 1209*0Sstevel@tonic-gate if (!(rtm->rtm_addrs & RTA_GATEWAY)) { 1210*0Sstevel@tonic-gate break; 1211*0Sstevel@tonic-gate } 1212*0Sstevel@tonic-gate cp += sizeof (struct sockaddr_in); 1213*0Sstevel@tonic-gate /* LINTED */ 1214*0Sstevel@tonic-gate sin = (struct sockaddr_in *)cp; 1215*0Sstevel@tonic-gate gw_addr = sin->sin_addr; 1216*0Sstevel@tonic-gate if (debug) { 1217*0Sstevel@tonic-gate logdebug("Get default route " 1218*0Sstevel@tonic-gate "removal notice: gw %s\n", 1219*0Sstevel@tonic-gate inet_ntoa(gw_addr)); 1220*0Sstevel@tonic-gate } 1221*0Sstevel@tonic-gate nca_del_nif(gw_addr); 1222*0Sstevel@tonic-gate } 1223*0Sstevel@tonic-gate break; 1224*0Sstevel@tonic-gate case RTM_ADD: 1225*0Sstevel@tonic-gate case RTM_OLDADD: 1226*0Sstevel@tonic-gate case RTM_CHANGE: 1227*0Sstevel@tonic-gate changed = B_FALSE; 1228*0Sstevel@tonic-gate if (get_if_info(&changed) < 0) { 1229*0Sstevel@tonic-gate /* May be a transient error... */ 1230*0Sstevel@tonic-gate (void) sleep(10); 1231*0Sstevel@tonic-gate break; 1232*0Sstevel@tonic-gate } 1233*0Sstevel@tonic-gate /* Nothing is changed, do nothing. */ 1234*0Sstevel@tonic-gate if (!changed) { 1235*0Sstevel@tonic-gate if (debug) { 1236*0Sstevel@tonic-gate logdebug("Get route change " 1237*0Sstevel@tonic-gate "notice, but nothing is " 1238*0Sstevel@tonic-gate "changed for us!"); 1239*0Sstevel@tonic-gate } 1240*0Sstevel@tonic-gate break; 1241*0Sstevel@tonic-gate } 1242*0Sstevel@tonic-gate lifr.lifr_addr.ss_family = AF_INET; 1243*0Sstevel@tonic-gate for (i = 0; i < num_nif; i++) { 1244*0Sstevel@tonic-gate int ret; 1245*0Sstevel@tonic-gate 1246*0Sstevel@tonic-gate /* 1247*0Sstevel@tonic-gate * If name is NULL, it means that 1248*0Sstevel@tonic-gate * we have encontered some problems 1249*0Sstevel@tonic-gate * when configurating the interface. 1250*0Sstevel@tonic-gate * So we remove it from the list. 1251*0Sstevel@tonic-gate */ 1252*0Sstevel@tonic-gate if (nif_list[i].name[0] == 0 || 1253*0Sstevel@tonic-gate nif_list[i].local_addr.s_addr == 0) 1254*0Sstevel@tonic-gate continue; 1255*0Sstevel@tonic-gate (void) strlcpy(lifr.lifr_name, 1256*0Sstevel@tonic-gate nif_list[i].name, 1257*0Sstevel@tonic-gate sizeof (lifr.lifr_name)); 1258*0Sstevel@tonic-gate if (ip_domux2fd(&udp_fd, &fd) < 0) { 1259*0Sstevel@tonic-gate logwarn(gettext("Removing" 1260*0Sstevel@tonic-gate " interface %s from the" 1261*0Sstevel@tonic-gate " configuration list.\n"), 1262*0Sstevel@tonic-gate nif_list[i].name); 1263*0Sstevel@tonic-gate nif_list[i].name[0] = 0; 1264*0Sstevel@tonic-gate continue; 1265*0Sstevel@tonic-gate } 1266*0Sstevel@tonic-gate if (ioctl(udp_fd, I_PUNLINK, 1267*0Sstevel@tonic-gate lifr.lifr_ip_muxid) < 0) { 1268*0Sstevel@tonic-gate logwarn(gettext("Removing" 1269*0Sstevel@tonic-gate " interface %s from the" 1270*0Sstevel@tonic-gate " configuration list.\n"), 1271*0Sstevel@tonic-gate nif_list[i].name); 1272*0Sstevel@tonic-gate nif_list[i].name[0] = 0; 1273*0Sstevel@tonic-gate (void) close(udp_fd); 1274*0Sstevel@tonic-gate (void) close(fd); 1275*0Sstevel@tonic-gate continue; 1276*0Sstevel@tonic-gate } 1277*0Sstevel@tonic-gate if (debug) { 1278*0Sstevel@tonic-gate logdebug("Configuring" 1279*0Sstevel@tonic-gate " %s\n", nif_list[i].name); 1280*0Sstevel@tonic-gate } 1281*0Sstevel@tonic-gate ret = nca_set_nif(fd, 1282*0Sstevel@tonic-gate nif_list[i].local_addr, 1283*0Sstevel@tonic-gate nif_list[i].router_ether_addr); 1284*0Sstevel@tonic-gate ip_plink(udp_fd, fd); 1285*0Sstevel@tonic-gate if (ret < 0) { 1286*0Sstevel@tonic-gate /* 1287*0Sstevel@tonic-gate * This should not be possible 1288*0Sstevel@tonic-gate * since if NCA does not 1289*0Sstevel@tonic-gate * support the ioctl, the 1290*0Sstevel@tonic-gate * active flag should be 1291*0Sstevel@tonic-gate * cleared already and this 1292*0Sstevel@tonic-gate * function should not have 1293*0Sstevel@tonic-gate * been called at all! 1294*0Sstevel@tonic-gate */ 1295*0Sstevel@tonic-gate logwarn("Daemon dies\n"); 1296*0Sstevel@tonic-gate exit(1); 1297*0Sstevel@tonic-gate } 1298*0Sstevel@tonic-gate (void) close(udp_fd); 1299*0Sstevel@tonic-gate (void) close(fd); 1300*0Sstevel@tonic-gate } 1301*0Sstevel@tonic-gate break; 1302*0Sstevel@tonic-gate default: 1303*0Sstevel@tonic-gate continue; 1304*0Sstevel@tonic-gate } 1305*0Sstevel@tonic-gate } 1306*0Sstevel@tonic-gate } 1307*0Sstevel@tonic-gate } 1308*0Sstevel@tonic-gate 1309*0Sstevel@tonic-gate /* 1310*0Sstevel@tonic-gate * Make us a daemon. 1311*0Sstevel@tonic-gate */ 1312*0Sstevel@tonic-gate static void 1313*0Sstevel@tonic-gate daemon_init(void) 1314*0Sstevel@tonic-gate { 1315*0Sstevel@tonic-gate pid_t pid; 1316*0Sstevel@tonic-gate 1317*0Sstevel@tonic-gate if ((pid = fork()) == -1) { 1318*0Sstevel@tonic-gate /* Write directly to terminal, instead of syslog. */ 1319*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("ncaconfd: cannot fork: %s\n"), 1320*0Sstevel@tonic-gate strerror(errno)); 1321*0Sstevel@tonic-gate exit(1); 1322*0Sstevel@tonic-gate } 1323*0Sstevel@tonic-gate if (pid != 0) 1324*0Sstevel@tonic-gate exit(0); 1325*0Sstevel@tonic-gate (void) setsid(); 1326*0Sstevel@tonic-gate /* Fork again so that we will never get a controlling terminal. */ 1327*0Sstevel@tonic-gate if ((pid = fork()) == -1) { 1328*0Sstevel@tonic-gate /* Write directly to terminal, instead of syslog. */ 1329*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("ncaconfd: cannot fork: %s\n"), 1330*0Sstevel@tonic-gate strerror(errno)); 1331*0Sstevel@tonic-gate exit(1); 1332*0Sstevel@tonic-gate } 1333*0Sstevel@tonic-gate if (pid != 0) 1334*0Sstevel@tonic-gate exit(0); 1335*0Sstevel@tonic-gate (void) chdir("/"); 1336*0Sstevel@tonic-gate (void) umask(0); 1337*0Sstevel@tonic-gate (void) fclose(stdin); 1338*0Sstevel@tonic-gate (void) fclose(stdout); 1339*0Sstevel@tonic-gate (void) fclose(stderr); 1340*0Sstevel@tonic-gate } 1341*0Sstevel@tonic-gate 1342*0Sstevel@tonic-gate int 1343*0Sstevel@tonic-gate main(int argc, char **argv) 1344*0Sstevel@tonic-gate { 1345*0Sstevel@tonic-gate int i, j; 1346*0Sstevel@tonic-gate int c; 1347*0Sstevel@tonic-gate boolean_t active = B_FALSE; 1348*0Sstevel@tonic-gate boolean_t as_daemon = B_TRUE; 1349*0Sstevel@tonic-gate 1350*0Sstevel@tonic-gate if (argc == 1) { 1351*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Usage: %s [-al]" 1352*0Sstevel@tonic-gate " [interface1 interface2 ...]\n"), argv[0]); 1353*0Sstevel@tonic-gate return (1); 1354*0Sstevel@tonic-gate } 1355*0Sstevel@tonic-gate 1356*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1357*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 1358*0Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 1359*0Sstevel@tonic-gate #endif 1360*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1361*0Sstevel@tonic-gate 1362*0Sstevel@tonic-gate while ((c = getopt(argc, argv, "adcl")) != EOF) { 1363*0Sstevel@tonic-gate switch (c) { 1364*0Sstevel@tonic-gate case 'a': 1365*0Sstevel@tonic-gate active = B_TRUE; 1366*0Sstevel@tonic-gate break; 1367*0Sstevel@tonic-gate case 'd': 1368*0Sstevel@tonic-gate debug = B_TRUE; 1369*0Sstevel@tonic-gate break; 1370*0Sstevel@tonic-gate case 'c': 1371*0Sstevel@tonic-gate /* Don't run as daemon. */ 1372*0Sstevel@tonic-gate as_daemon = B_FALSE; 1373*0Sstevel@tonic-gate break; 1374*0Sstevel@tonic-gate case 'l': 1375*0Sstevel@tonic-gate logging = B_TRUE; 1376*0Sstevel@tonic-gate break; 1377*0Sstevel@tonic-gate default: 1378*0Sstevel@tonic-gate /* -d and -c are "undocumented" options. */ 1379*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Usage: %s [-al]" 1380*0Sstevel@tonic-gate " [interface1 interface2 ...]\n"), argv[0]); 1381*0Sstevel@tonic-gate return (1); 1382*0Sstevel@tonic-gate } 1383*0Sstevel@tonic-gate } 1384*0Sstevel@tonic-gate num_nif = argc - optind; 1385*0Sstevel@tonic-gate if (num_nif == 0) { 1386*0Sstevel@tonic-gate /* No network interface to proces... */ 1387*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Usage: %s [-al]" 1388*0Sstevel@tonic-gate " [interface1 interface2 ...]\n"), argv[0]); 1389*0Sstevel@tonic-gate return (0); 1390*0Sstevel@tonic-gate } 1391*0Sstevel@tonic-gate nif_list = calloc(num_nif, sizeof (nif_t)); 1392*0Sstevel@tonic-gate if (nif_list == NULL) { 1393*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("ncaconfd: Cannot malloc: %s\n"), 1394*0Sstevel@tonic-gate strerror(errno)); 1395*0Sstevel@tonic-gate return (1); 1396*0Sstevel@tonic-gate } 1397*0Sstevel@tonic-gate for (i = 0, j = optind; i < num_nif; i++, j++) { 1398*0Sstevel@tonic-gate (void) strlcpy(nif_list[i].name, argv[j], LIFNAMSIZ+1); 1399*0Sstevel@tonic-gate } 1400*0Sstevel@tonic-gate 1401*0Sstevel@tonic-gate /* Get IP address info for all the intefaces. */ 1402*0Sstevel@tonic-gate if (get_if_ip_addr() < 0) { 1403*0Sstevel@tonic-gate if (debug) { 1404*0Sstevel@tonic-gate (void) fprintf(stderr, "ncaconfd: Cannot get IP" 1405*0Sstevel@tonic-gate " addresses for interfaces.\n"); 1406*0Sstevel@tonic-gate } 1407*0Sstevel@tonic-gate return (1); 1408*0Sstevel@tonic-gate } 1409*0Sstevel@tonic-gate if (logging) 1410*0Sstevel@tonic-gate openlog("ncaconfd", LOG_PID, LOG_DAEMON); 1411*0Sstevel@tonic-gate /* No need to run as daemon if NCA is not making active connections. */ 1412*0Sstevel@tonic-gate if (active && as_daemon) 1413*0Sstevel@tonic-gate daemon_init(); 1414*0Sstevel@tonic-gate if (active) { 1415*0Sstevel@tonic-gate boolean_t changed; 1416*0Sstevel@tonic-gate 1417*0Sstevel@tonic-gate /* NCA does not support IPv6... */ 1418*0Sstevel@tonic-gate if ((rt_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { 1419*0Sstevel@tonic-gate logperror("Cannot open routing socket"); 1420*0Sstevel@tonic-gate return (1); 1421*0Sstevel@tonic-gate } 1422*0Sstevel@tonic-gate /* 1423*0Sstevel@tonic-gate * At boot up time, the default router may not have been 1424*0Sstevel@tonic-gate * found. So ignore the error and check later. 1425*0Sstevel@tonic-gate */ 1426*0Sstevel@tonic-gate if (get_if_info(&changed) < 0) { 1427*0Sstevel@tonic-gate if (debug) { 1428*0Sstevel@tonic-gate (void) logwarn("Cannot get" 1429*0Sstevel@tonic-gate " information from network interface.\n"); 1430*0Sstevel@tonic-gate } 1431*0Sstevel@tonic-gate } 1432*0Sstevel@tonic-gate } 1433*0Sstevel@tonic-gate /* Do the set up as daemon (if we are) to save time at boot up... */ 1434*0Sstevel@tonic-gate nca_setup(&active); 1435*0Sstevel@tonic-gate if (active) 1436*0Sstevel@tonic-gate daemon_work(); 1437*0Sstevel@tonic-gate return (0); 1438*0Sstevel@tonic-gate } 1439