xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.lib/ncaconfd/ncaconfd.c (revision 741:40027a3621ac)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*741Smasputra  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/stat.h>
310Sstevel@tonic-gate #include <sys/tihdr.h>
320Sstevel@tonic-gate #include <stropts.h>
330Sstevel@tonic-gate #include <fcntl.h>
340Sstevel@tonic-gate #include <syslog.h>
350Sstevel@tonic-gate #include <string.h>
360Sstevel@tonic-gate #include <strings.h>
370Sstevel@tonic-gate #include <errno.h>
380Sstevel@tonic-gate #include <stdio.h>
390Sstevel@tonic-gate #include <stdlib.h>
400Sstevel@tonic-gate #include <libintl.h>
410Sstevel@tonic-gate #include <locale.h>
420Sstevel@tonic-gate #include <unistd.h>
430Sstevel@tonic-gate #include <sys/varargs.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include <netinet/in.h>
460Sstevel@tonic-gate #include <sys/ethernet.h>
470Sstevel@tonic-gate #include <sys/socket.h>
480Sstevel@tonic-gate #include <sys/sockio.h>
490Sstevel@tonic-gate #include <sys/sysmacros.h>
500Sstevel@tonic-gate #include <net/if.h>
510Sstevel@tonic-gate #include <inet/mib2.h>
520Sstevel@tonic-gate #include <inet/ip.h>
530Sstevel@tonic-gate #include <net/route.h>
540Sstevel@tonic-gate #include <arpa/inet.h>
550Sstevel@tonic-gate #include "ncaconf.h"
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /* NCA does not support IPv6... */
580Sstevel@tonic-gate #ifndef	NCA_MOD_NAME
590Sstevel@tonic-gate #define	NCA_MOD_NAME	"nca"
600Sstevel@tonic-gate #endif
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #ifndef	ARP_MOD_NAME
630Sstevel@tonic-gate #define	ARP_MOD_NAME	"arp"
640Sstevel@tonic-gate #endif
650Sstevel@tonic-gate 
660Sstevel@tonic-gate #define	IF_SEPARATOR	':'
670Sstevel@tonic-gate 
680Sstevel@tonic-gate #define	ping_prog	"/usr/sbin/ping"
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /* Structure to hold info about each network interface. */
710Sstevel@tonic-gate typedef struct nif_s {
720Sstevel@tonic-gate 	char		name[LIFNAMSIZ+1];
730Sstevel@tonic-gate 	struct in_addr	local_addr;
740Sstevel@tonic-gate 	struct in_addr	router_addr;
750Sstevel@tonic-gate 	uchar_t		router_ether_addr[ETHERADDRL];
760Sstevel@tonic-gate } nif_t;
770Sstevel@tonic-gate 
780Sstevel@tonic-gate typedef struct mib_item_s {
790Sstevel@tonic-gate 	struct mib_item_s	*next_item;
800Sstevel@tonic-gate 	int			group;
810Sstevel@tonic-gate 	int			mib_id;
820Sstevel@tonic-gate 	int			length;
830Sstevel@tonic-gate 	char			*valp;
840Sstevel@tonic-gate } mib_item_t;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate /* The network interface array. */
870Sstevel@tonic-gate static nif_t *nif_list;
880Sstevel@tonic-gate /* Number of network interface to process. */
890Sstevel@tonic-gate static int num_nif;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /* Interface request to IP. */
920Sstevel@tonic-gate static struct lifreq lifr;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /* True if syslog is to be used. */
950Sstevel@tonic-gate static boolean_t logging;
960Sstevel@tonic-gate /* True if additional debugging messages are printed. */
970Sstevel@tonic-gate static boolean_t debug;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /* File descriptor to the routing socket. */
1000Sstevel@tonic-gate static int rt_fd;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static void logperror(char *);
1030Sstevel@tonic-gate static void logwarn(char *, ...);
1040Sstevel@tonic-gate static void logdebug(char *, ...);
1050Sstevel@tonic-gate static int ip_domux2fd(int *, int *);
1060Sstevel@tonic-gate static void ip_plink(int, int);
1070Sstevel@tonic-gate static int find_nca_pos(int);
1080Sstevel@tonic-gate static int nca_set_nif(int, struct in_addr, uchar_t *);
1090Sstevel@tonic-gate static void nca_setup(boolean_t *);
1100Sstevel@tonic-gate static int get_if_ip_addr(void);
1110Sstevel@tonic-gate static mib_item_t *mibget(int);
1120Sstevel@tonic-gate static int ire_process(mib2_ipRouteEntry_t *, size_t, boolean_t *);
1130Sstevel@tonic-gate static int arp_process(mib2_ipNetToMediaEntry_t *, size_t, boolean_t *);
1140Sstevel@tonic-gate static int get_router_ip_addr(mib_item_t *, boolean_t *);
1150Sstevel@tonic-gate static int get_router_ether_addr(mib_item_t *, boolean_t *);
1160Sstevel@tonic-gate static int get_if_info(boolean_t *);
1170Sstevel@tonic-gate static void daemon_init(void);
1180Sstevel@tonic-gate static void daemon_work(void);
1190Sstevel@tonic-gate static void ping_them(void);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate  * Print out system error messages, either to syslog or stderr.  Note that
1230Sstevel@tonic-gate  * syslog() should print out system error messages in the correct language
1240Sstevel@tonic-gate  * used.  There is no need to use gettext().
1250Sstevel@tonic-gate  */
1260Sstevel@tonic-gate static void
logperror(char * str)1270Sstevel@tonic-gate logperror(char *str)
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate 	if (logging) {
1300Sstevel@tonic-gate 		syslog(LOG_ERR, "%s: %m\n", str);
1310Sstevel@tonic-gate 	} else {
1320Sstevel@tonic-gate 		(void) fprintf(stderr, "ncaconfd: %s: %s\n", str,
1330Sstevel@tonic-gate 		    strerror(errno));
1340Sstevel@tonic-gate 	}
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate /*
1380Sstevel@tonic-gate  * Print out warning messages.  The caller should use gettext() to have
1390Sstevel@tonic-gate  * the message printed out in the correct language.
1400Sstevel@tonic-gate  */
1410Sstevel@tonic-gate /*PRINTFLIKE1*/
1420Sstevel@tonic-gate static void
logwarn(char * fmt,...)1430Sstevel@tonic-gate logwarn(char *fmt, ...)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate 	va_list ap;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	va_start(ap, fmt);
1480Sstevel@tonic-gate 	if (logging) {
1490Sstevel@tonic-gate 		vsyslog(LOG_WARNING, fmt, ap);
1500Sstevel@tonic-gate 	} else {
1510Sstevel@tonic-gate 		(void) fprintf(stderr, "ncaconfd: ");
1520Sstevel@tonic-gate 		(void) vfprintf(stderr, fmt, ap);
1530Sstevel@tonic-gate 	}
1540Sstevel@tonic-gate 	va_end(ap);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate /*
1580Sstevel@tonic-gate  * Print out debugging info.  Note that syslogd(1M) should be configured to
1590Sstevel@tonic-gate  * take ordinary debug info for it to get this kind of info.
1600Sstevel@tonic-gate  */
1610Sstevel@tonic-gate /*PRINTFLIKE1*/
1620Sstevel@tonic-gate static void
logdebug(char * fmt,...)1630Sstevel@tonic-gate logdebug(char *fmt, ...)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate 	va_list ap;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	va_start(ap, fmt);
1680Sstevel@tonic-gate 	if (logging) {
1690Sstevel@tonic-gate 		vsyslog(LOG_WARNING, fmt, ap);
1700Sstevel@tonic-gate 	} else {
1710Sstevel@tonic-gate 		(void) fprintf(stderr, "ncaconfd: ");
1720Sstevel@tonic-gate 		(void) vfprintf(stderr, fmt, ap);
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate 	va_end(ap);
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate /*
1780Sstevel@tonic-gate  * Helper function for nca_setup().  It gets a fd to the lower IP
1790Sstevel@tonic-gate  * stream and I_PUNLINK's the lower stream.  It also initializes the
1800Sstevel@tonic-gate  * global variable lifr.
1810Sstevel@tonic-gate  *
1820Sstevel@tonic-gate  * Param:
1830Sstevel@tonic-gate  *	int *udp_fd: (referenced) fd to /dev/udp (upper IP stream).
1840Sstevel@tonic-gate  *	int *fd: (referenced) fd to the lower IP stream.
1850Sstevel@tonic-gate  *
1860Sstevel@tonic-gate  * Return:
1870Sstevel@tonic-gate  *	-1 if operation fails, 0 otherwise.
1880Sstevel@tonic-gate  */
1890Sstevel@tonic-gate static int
ip_domux2fd(int * udp_fd,int * fd)1900Sstevel@tonic-gate ip_domux2fd(int *udp_fd, int *fd)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	int ip_fd;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	if ((ip_fd = open(IP_DEV_NAME, O_RDWR)) < 0) {
1950Sstevel@tonic-gate 		logperror("Cannot open IP");
1960Sstevel@tonic-gate 		return (-1);
1970Sstevel@tonic-gate 	}
1980Sstevel@tonic-gate 	if ((*udp_fd = open(UDP_DEV_NAME, O_RDWR)) < 0) {
1990Sstevel@tonic-gate 		logperror("Cannot open UDP");
2000Sstevel@tonic-gate 		(void) close(ip_fd);
2010Sstevel@tonic-gate 		return (-1);
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 	if (ioctl(ip_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
2040Sstevel@tonic-gate 		logperror("ioctl(SIOCGLIFMUXID) failed");
2050Sstevel@tonic-gate 		(void) close(ip_fd);
2060Sstevel@tonic-gate 		return (-1);
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate 	if (debug) {
2090Sstevel@tonic-gate 		logdebug("ARP_muxid %d IP_muxid %d\n", lifr.lifr_arp_muxid,
2100Sstevel@tonic-gate 		    lifr.lifr_ip_muxid);
2110Sstevel@tonic-gate 	}
2120Sstevel@tonic-gate 	if ((*fd = ioctl(*udp_fd, _I_MUXID2FD, lifr.lifr_ip_muxid)) < 0) {
2130Sstevel@tonic-gate 		logperror("ioctl(_I_MUXID2FD) failed");
2140Sstevel@tonic-gate 		(void) close(ip_fd);
2150Sstevel@tonic-gate 		(void) close(*udp_fd);
2160Sstevel@tonic-gate 		return (-1);
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate 	(void) close(ip_fd);
2190Sstevel@tonic-gate 	return (0);
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate /*
2230Sstevel@tonic-gate  * Helper function for nca_setup().  It I_PLINK's back the upper and
2240Sstevel@tonic-gate  * lower IP streams.  Note that this function must be called after
2250Sstevel@tonic-gate  * ip_domux2fd().  In ip_domux2fd(), the global variable lifr is initialized
2260Sstevel@tonic-gate  * and ip_plink() needs information in lifr.  So ip_domux2fd() and ip_plink()
2270Sstevel@tonic-gate  * must be called in pairs.
2280Sstevel@tonic-gate  *
2290Sstevel@tonic-gate  * Param:
2300Sstevel@tonic-gate  *	int udp_fd: fd to /dev/udp (upper IP stream).
2310Sstevel@tonic-gate  *	int fd: fd to the lower IP stream.
2320Sstevel@tonic-gate  */
2330Sstevel@tonic-gate static void
ip_plink(int udp_fd,int fd)2340Sstevel@tonic-gate ip_plink(int udp_fd, int fd)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate 	int mux_id;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	if ((mux_id = ioctl(udp_fd, I_PLINK, fd)) < 0) {
2390Sstevel@tonic-gate 		logperror("ioctl(I_PLINK) failed");
2400Sstevel@tonic-gate 		return;
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 	if (debug > 0) {
2430Sstevel@tonic-gate 		logdebug("New IP_muxid %d\n", mux_id);
2440Sstevel@tonic-gate 	}
2450Sstevel@tonic-gate 	lifr.lifr_ip_muxid = mux_id;
2460Sstevel@tonic-gate 	if (ioctl(udp_fd, SIOCSLIFMUXID, (caddr_t)&lifr) < 0) {
2470Sstevel@tonic-gate 		logperror("ioctl(SIOCSLIFMUXID) failed");
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate #define	FOUND_NCA	-1
2520Sstevel@tonic-gate #define	FOUND_NONE	-2
2530Sstevel@tonic-gate /*
2540Sstevel@tonic-gate  * Find the proper position to insert NCA, which is just below IP.
2550Sstevel@tonic-gate  *
2560Sstevel@tonic-gate  * Param:
2570Sstevel@tonic-gate  *	int fd: fd to the lower IP stream.
2580Sstevel@tonic-gate  *
2590Sstevel@tonic-gate  * Return:
2600Sstevel@tonic-gate  *	If positive, it is the position to insert NCA.
2610Sstevel@tonic-gate  *	FOUND_NCA: found NCA!  So skip this one for plumbing.  But we
2620Sstevel@tonic-gate  *		still keep it in the interface list.
2630Sstevel@tonic-gate  *	FOUND_NONE: could not find IP or encounter other errors.  Remove
2640Sstevel@tonic-gate  *		this interface from the	list.
2650Sstevel@tonic-gate  */
2660Sstevel@tonic-gate static int
find_nca_pos(int fd)2670Sstevel@tonic-gate find_nca_pos(int fd)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate 	int num_mods;
2700Sstevel@tonic-gate 	int i, pos;
2710Sstevel@tonic-gate 	struct str_list strlist;
2720Sstevel@tonic-gate 	boolean_t found_ip = B_FALSE;
2730Sstevel@tonic-gate 	boolean_t found_nca = B_FALSE;
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) {
2760Sstevel@tonic-gate 		logperror("ioctl(I_LIST) failed");
2770Sstevel@tonic-gate 		return (FOUND_NONE);
2780Sstevel@tonic-gate 	} else {
2790Sstevel@tonic-gate 		strlist.sl_nmods = num_mods;
2800Sstevel@tonic-gate 		strlist.sl_modlist = calloc(num_mods,
2810Sstevel@tonic-gate 		    sizeof (struct str_mlist));
2820Sstevel@tonic-gate 		if (strlist.sl_modlist == NULL) {
2830Sstevel@tonic-gate 			logperror("cannot malloc");
2840Sstevel@tonic-gate 			return (FOUND_NONE);
2850Sstevel@tonic-gate 		} else {
2860Sstevel@tonic-gate 			if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
2870Sstevel@tonic-gate 				logperror("ioctl(I_LIST) failed");
2880Sstevel@tonic-gate 			} else {
2890Sstevel@tonic-gate 				for (i = 0; i < strlist.sl_nmods; i++) {
2900Sstevel@tonic-gate 					if (strcmp(IP_MOD_NAME,
2910Sstevel@tonic-gate 					    strlist.sl_modlist[i].l_name)
2920Sstevel@tonic-gate 					    == 0) {
2930Sstevel@tonic-gate 						found_ip = B_TRUE;
2940Sstevel@tonic-gate 						/*
2950Sstevel@tonic-gate 						 * NCA should be just below
2960Sstevel@tonic-gate 						 * IP.
2970Sstevel@tonic-gate 						 */
2980Sstevel@tonic-gate 						pos = i + 1;
2990Sstevel@tonic-gate 					} else if (strncmp(NCA_MOD_NAME,
3000Sstevel@tonic-gate 					    strlist.sl_modlist[i].l_name,
3010Sstevel@tonic-gate 					    strlen(NCA_MOD_NAME)) == 0) {
3020Sstevel@tonic-gate 						found_nca = B_TRUE;
3030Sstevel@tonic-gate 					}
3040Sstevel@tonic-gate 				}
3050Sstevel@tonic-gate 			}
3060Sstevel@tonic-gate 			free(strlist.sl_modlist);
3070Sstevel@tonic-gate 		}
3080Sstevel@tonic-gate 	}
3090Sstevel@tonic-gate 	if (found_nca) {
3100Sstevel@tonic-gate 		return (FOUND_NCA);
3110Sstevel@tonic-gate 	} else if (found_ip) {
3120Sstevel@tonic-gate 		if (debug) {
3130Sstevel@tonic-gate 			logdebug("NCA is at position %d in the stream.\n", pos);
3140Sstevel@tonic-gate 		}
3150Sstevel@tonic-gate 		return (pos);
3160Sstevel@tonic-gate 	} else {
3170Sstevel@tonic-gate 		if (debug) {
3180Sstevel@tonic-gate 			logdebug("Cannot find IP??\n");
3190Sstevel@tonic-gate 		}
3200Sstevel@tonic-gate 		return (FOUND_NONE);
3210Sstevel@tonic-gate 	}
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate /*
3250Sstevel@tonic-gate  * To set the local IP address and default router ethernet address.
3260Sstevel@tonic-gate  *
3270Sstevel@tonic-gate  * Param:
3280Sstevel@tonic-gate  *	int fd: the fd to the lower IP stream.
3290Sstevel@tonic-gate  *	struct in_addr local_addr: the IP address for this interface.
3300Sstevel@tonic-gate  *	uchar_t *ether_addr: the ethernet address of the default router for
3310Sstevel@tonic-gate  *		for this interface.
3320Sstevel@tonic-gate  *
3330Sstevel@tonic-gate  * Return:
3340Sstevel@tonic-gate  *	-1 if the system does not support this NCA ioctl(), 0 otherwise.
3350Sstevel@tonic-gate  */
3360Sstevel@tonic-gate static int
nca_set_nif(int fd,struct in_addr local_addr,uchar_t * ether_addr)3370Sstevel@tonic-gate nca_set_nif(int fd, struct in_addr local_addr, uchar_t *ether_addr)
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate 	struct nca_set_ioctl nca_ioctl;
3400Sstevel@tonic-gate 	struct strioctl strioc;
3410Sstevel@tonic-gate 	int len;
3420Sstevel@tonic-gate 	uchar_t *dst;
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	strioc.ic_cmd = NCA_SET_IF;
3450Sstevel@tonic-gate 	strioc.ic_timout = INFTIM;
3460Sstevel@tonic-gate 	strioc.ic_len = sizeof (nca_ioctl);
3470Sstevel@tonic-gate 	strioc.ic_dp = (char *)&nca_ioctl;
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	nca_ioctl.local_addr = local_addr.s_addr;
3500Sstevel@tonic-gate 	dst = nca_ioctl.router_ether_addr;
3510Sstevel@tonic-gate 	for (len = ETHERADDRL; len > 0; len--)
3520Sstevel@tonic-gate 		*dst++ = *ether_addr++;
3530Sstevel@tonic-gate 	nca_ioctl.action = ADD_DEF_ROUTE;
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &strioc) < 0) {
3560Sstevel@tonic-gate 		logperror("ioctl(NCA_SET_IF) failed");
3570Sstevel@tonic-gate 		if (errno == EINVAL)
3580Sstevel@tonic-gate 			return (-1);
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate 	return (0);
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate /*
3640Sstevel@tonic-gate  * To setup the NCA stream.  First insert NCA into the proper position.
3650Sstevel@tonic-gate  * Then tell NCA the local IP address and default router by using the
3660Sstevel@tonic-gate  * NCA_SET_IF ioctl.
3670Sstevel@tonic-gate  *
3680Sstevel@tonic-gate  * Param:
3690Sstevel@tonic-gate  *	boolean_t *active: (referenced) B_TRUE if NCA is setup to do active
3700Sstevel@tonic-gate  *		connection.  If NCA does not support active connection,
3710Sstevel@tonic-gate  *		in return, active will be set to B_FALSE.
3720Sstevel@tonic-gate  */
3730Sstevel@tonic-gate static void
nca_setup(boolean_t * active)3740Sstevel@tonic-gate nca_setup(boolean_t *active)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate 	int i;
3770Sstevel@tonic-gate 	int udp_fd;
3780Sstevel@tonic-gate 	int fd;
3790Sstevel@tonic-gate 	struct strmodconf mod;
3800Sstevel@tonic-gate 	/* 128 is enough because interface name can only be LIFNAMSIZ long. */
3810Sstevel@tonic-gate 	char err_buf[128];
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	mod.mod_name = NCA_MOD_NAME;
3840Sstevel@tonic-gate 	lifr.lifr_addr.ss_family = AF_INET;
3850Sstevel@tonic-gate 	for (i = 0; i < num_nif; i++) {
3860Sstevel@tonic-gate 		if (debug) {
3870Sstevel@tonic-gate 			logdebug("Plumbing NCA for %s\n", nif_list[i].name);
3880Sstevel@tonic-gate 		}
3890Sstevel@tonic-gate 		/* This interface does not exist according to IP. */
3900Sstevel@tonic-gate 		if (nif_list[i].local_addr.s_addr == 0) {
3910Sstevel@tonic-gate 			continue;
3920Sstevel@tonic-gate 		}
3930Sstevel@tonic-gate 		(void) strlcpy(lifr.lifr_name, nif_list[i].name,
3940Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 		if (ip_domux2fd(&udp_fd, &fd) < 0) {
3970Sstevel@tonic-gate 			continue;
3980Sstevel@tonic-gate 		}
3990Sstevel@tonic-gate 		if (ioctl(udp_fd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) {
4000Sstevel@tonic-gate 			(void) snprintf(err_buf, sizeof (err_buf),
4010Sstevel@tonic-gate 			    "ioctl(I_PUNLINK) for %s failed", nif_list[i].name);
4020Sstevel@tonic-gate 			logperror(err_buf);
4030Sstevel@tonic-gate 			(void) close(udp_fd);
4040Sstevel@tonic-gate 			(void) close(fd);
4050Sstevel@tonic-gate 			continue;
4060Sstevel@tonic-gate 		}
4070Sstevel@tonic-gate 		if ((mod.pos = find_nca_pos(fd)) < 0) {
4080Sstevel@tonic-gate 			if (mod.pos == FOUND_NCA) {
4090Sstevel@tonic-gate 				if (debug) {
4100Sstevel@tonic-gate 					logdebug("Find NCA in the %s"
4110Sstevel@tonic-gate 					    " stream\n", nif_list[i].name);
4120Sstevel@tonic-gate 				}
4130Sstevel@tonic-gate 				/* Just skip plumbing NCA. */
4140Sstevel@tonic-gate 				goto set_nif;
4150Sstevel@tonic-gate 			}
4160Sstevel@tonic-gate 			if (debug) {
4170Sstevel@tonic-gate 				logdebug("Cannot find pos for %s\n",
4180Sstevel@tonic-gate 				    nif_list[i].name);
4190Sstevel@tonic-gate 			}
4200Sstevel@tonic-gate 			goto clean_up;
4210Sstevel@tonic-gate 		}
4220Sstevel@tonic-gate 		if (ioctl(fd, _I_INSERT, (caddr_t)&mod) < 0) {
4230Sstevel@tonic-gate 			(void) snprintf(err_buf, sizeof (err_buf),
4240Sstevel@tonic-gate 			    "ioctl(_I_INSERT) for %s failed", nif_list[i].name);
4250Sstevel@tonic-gate 			logperror(err_buf);
4260Sstevel@tonic-gate 			goto clean_up;
4270Sstevel@tonic-gate 		}
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 		/*
4300Sstevel@tonic-gate 		 * Only do the following if NCA is also used to make
4310Sstevel@tonic-gate 		 * outgoing connections, and all necessary info is
4320Sstevel@tonic-gate 		 * there.
4330Sstevel@tonic-gate 		 */
4340Sstevel@tonic-gate set_nif:
4350Sstevel@tonic-gate 		if (*active && nif_list[i].router_addr.s_addr != 0) {
4360Sstevel@tonic-gate 			if (nca_set_nif(fd, nif_list[i].local_addr,
4370Sstevel@tonic-gate 			    nif_list[i].router_ether_addr) < 0) {
4380Sstevel@tonic-gate 				/*
4390Sstevel@tonic-gate 				 * The system does not support this ioctl()!
4400Sstevel@tonic-gate 				 * Skip all active stack processing but
4410Sstevel@tonic-gate 				 * continue to plumb NCA.
4420Sstevel@tonic-gate 				 */
4430Sstevel@tonic-gate 				logwarn("NCA does not support active stack!");
4440Sstevel@tonic-gate 				*active = B_FALSE;
4450Sstevel@tonic-gate 			}
4460Sstevel@tonic-gate 		}
4470Sstevel@tonic-gate clean_up:
4480Sstevel@tonic-gate 		ip_plink(udp_fd, fd);
4490Sstevel@tonic-gate 		(void) close(udp_fd);
4500Sstevel@tonic-gate 		(void) close(fd);
4510Sstevel@tonic-gate 	}
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate /*
4550Sstevel@tonic-gate  * To get IP address of network interface from IP.
4560Sstevel@tonic-gate  */
4570Sstevel@tonic-gate static int
get_if_ip_addr(void)4580Sstevel@tonic-gate get_if_ip_addr(void)
4590Sstevel@tonic-gate {
4600Sstevel@tonic-gate 	int sock;
4610Sstevel@tonic-gate 	struct lifnum lifn;
4620Sstevel@tonic-gate 	struct lifconf lifc;
4630Sstevel@tonic-gate 	struct lifreq *lifr;
4640Sstevel@tonic-gate 	struct sockaddr_in *sin;
4650Sstevel@tonic-gate 	char *buf;
4660Sstevel@tonic-gate 	int num_lifr;
4670Sstevel@tonic-gate 	int i, j;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	/* NCA only supports IPv4... */
4700Sstevel@tonic-gate 	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
4710Sstevel@tonic-gate 		logperror(gettext("Cannot open socket"));
4720Sstevel@tonic-gate 		return (-1);
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 	lifn.lifn_family = AF_UNSPEC;
4750Sstevel@tonic-gate 	lifn.lifn_flags = 0;
4760Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
4770Sstevel@tonic-gate 		logperror(gettext("ioctl(SIOCGLIFNUM) failed"));
4780Sstevel@tonic-gate 		(void) close(sock);
4790Sstevel@tonic-gate 		return (-1);
4800Sstevel@tonic-gate 	}
4810Sstevel@tonic-gate 	buf = (char *)calloc(lifn.lifn_count, sizeof (struct lifreq));
4820Sstevel@tonic-gate 	if (buf == NULL) {
4830Sstevel@tonic-gate 		logperror(gettext("calloc() failed"));
4840Sstevel@tonic-gate 		(void) close(sock);
4850Sstevel@tonic-gate 		return (-1);
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	lifc.lifc_family = AF_UNSPEC;
4890Sstevel@tonic-gate 	lifc.lifc_flags = 0;
4900Sstevel@tonic-gate 	lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq);
4910Sstevel@tonic-gate 	lifc.lifc_buf = buf;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
4940Sstevel@tonic-gate 		/*
4950Sstevel@tonic-gate 		 * NCA is set up after all the interfaces have been
4960Sstevel@tonic-gate 		 * plumbed.  So normally we should not get any error.
4970Sstevel@tonic-gate 		 * Just abort if we encounter an error.
4980Sstevel@tonic-gate 		 */
4990Sstevel@tonic-gate 		logperror(gettext("ioctl(SIOCGLIFCONF) failed"));
5000Sstevel@tonic-gate 		free(buf);
5010Sstevel@tonic-gate 		(void) close(sock);
5020Sstevel@tonic-gate 		return (-1);
5030Sstevel@tonic-gate 	}
5040Sstevel@tonic-gate 	num_lifr = lifc.lifc_len / sizeof (struct lifreq);
5050Sstevel@tonic-gate 	/* Find the interface and copy the local IP address. */
5060Sstevel@tonic-gate 	for (i = 0; i < num_nif; i++) {
5070Sstevel@tonic-gate 		lifr = (struct lifreq *)lifc.lifc_req;
5080Sstevel@tonic-gate 		for (j = num_lifr; j > 0; j--, lifr++) {
5090Sstevel@tonic-gate 			/* Again, NCA only supports IPv4. */
5100Sstevel@tonic-gate 			if (lifr->lifr_addr.ss_family != AF_INET)
5110Sstevel@tonic-gate 				continue;
5120Sstevel@tonic-gate 			if (strncmp(nif_list[i].name, lifr->lifr_name,
5130Sstevel@tonic-gate 			    strlen(nif_list[i].name)) == 0) {
5140Sstevel@tonic-gate 				sin = (struct sockaddr_in *)&lifr->lifr_addr;
5150Sstevel@tonic-gate 				nif_list[i].local_addr = sin->sin_addr;
5160Sstevel@tonic-gate 				if (debug) {
5170Sstevel@tonic-gate 					logdebug("IP address of %s: %s\n",
5180Sstevel@tonic-gate 					    nif_list[i].name,
5190Sstevel@tonic-gate 					    inet_ntoa(sin->sin_addr));
5200Sstevel@tonic-gate 				}
5210Sstevel@tonic-gate 				break;
5220Sstevel@tonic-gate 			}
5230Sstevel@tonic-gate 		}
5240Sstevel@tonic-gate 		if (j == 0) {
5250Sstevel@tonic-gate 			/*
5260Sstevel@tonic-gate 			 * The interface does not exist according to IP!
5270Sstevel@tonic-gate 			 * Log a warning and go on.
5280Sstevel@tonic-gate 			 */
5290Sstevel@tonic-gate 			logwarn(gettext("Network interface %s"
5300Sstevel@tonic-gate 			    " does not exist!\n"), nif_list[i].name);
5310Sstevel@tonic-gate 			/*
5320Sstevel@tonic-gate 			 * Set local_addr to 0 so that nca_setup() will
5330Sstevel@tonic-gate 			 * not do anything for this interface.
5340Sstevel@tonic-gate 			 */
5350Sstevel@tonic-gate 			nif_list[i].local_addr.s_addr = 0;
5360Sstevel@tonic-gate 		}
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 	free(buf);
5390Sstevel@tonic-gate 	(void) close(sock);
5400Sstevel@tonic-gate 	return (0);
5410Sstevel@tonic-gate }
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate /*
5440Sstevel@tonic-gate  * Get MIB2 info from IP.
5450Sstevel@tonic-gate  *
5460Sstevel@tonic-gate  * Param:
5470Sstevel@tonic-gate  *	int sd: descriptor to IP to send down mib request.
5480Sstevel@tonic-gate  */
5490Sstevel@tonic-gate static mib_item_t *
mibget(int sd)5500Sstevel@tonic-gate mibget(int sd)
5510Sstevel@tonic-gate {
5520Sstevel@tonic-gate 	char			buf[1024];
5530Sstevel@tonic-gate 	int			flags;
5540Sstevel@tonic-gate 	int			i, j, getcode;
5550Sstevel@tonic-gate 	struct strbuf		ctlbuf, databuf;
5560Sstevel@tonic-gate 	/* LINTED */
5570Sstevel@tonic-gate 	struct T_optmgmt_req	*tor = (struct T_optmgmt_req *)buf;
5580Sstevel@tonic-gate 	/* LINTED */
5590Sstevel@tonic-gate 	struct T_optmgmt_ack	*toa = (struct T_optmgmt_ack *)buf;
5600Sstevel@tonic-gate 	/* LINTED */
5610Sstevel@tonic-gate 	struct T_error_ack	*tea = (struct T_error_ack *)buf;
5620Sstevel@tonic-gate 	struct opthdr		*req;
5630Sstevel@tonic-gate 	mib_item_t		*first_item = (mib_item_t *)0;
5640Sstevel@tonic-gate 	mib_item_t		*last_item  = (mib_item_t *)0;
5650Sstevel@tonic-gate 	mib_item_t		*temp;
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
5680Sstevel@tonic-gate 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
5690Sstevel@tonic-gate 	tor->OPT_length = sizeof (struct opthdr);
5700Sstevel@tonic-gate 	tor->MGMT_flags = T_CURRENT;
5710Sstevel@tonic-gate 	req = (struct opthdr *)&tor[1];
5720Sstevel@tonic-gate 	req->level = MIB2_IP;		/* any MIB2_xxx value ok here */
5730Sstevel@tonic-gate 	req->name  = 0;
5740Sstevel@tonic-gate 	req->len   = 0;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	ctlbuf.buf = buf;
5770Sstevel@tonic-gate 	ctlbuf.len = tor->OPT_length + tor->OPT_offset;
5780Sstevel@tonic-gate 	flags = 0;
5790Sstevel@tonic-gate 	if (putmsg(sd, &ctlbuf, (struct strbuf *)0, flags) == -1) {
5800Sstevel@tonic-gate 		logperror("mibget: putmsg(ctl) failed");
5810Sstevel@tonic-gate 		goto error_exit;
5820Sstevel@tonic-gate 	}
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	/*
5850Sstevel@tonic-gate 	 * Each reply consists of a ctl part for one fixed structure
5860Sstevel@tonic-gate 	 * or table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK,
5870Sstevel@tonic-gate 	 * containing an opthdr structure.  level/name identify the entry,
5880Sstevel@tonic-gate 	 * len is the size of the data part of the message.
5890Sstevel@tonic-gate 	 */
5900Sstevel@tonic-gate 	req = (struct opthdr *)&toa[1];
5910Sstevel@tonic-gate 	ctlbuf.maxlen = sizeof (buf);
5920Sstevel@tonic-gate 	j = 1;
5930Sstevel@tonic-gate 	for (;;) {
5940Sstevel@tonic-gate 		flags = 0;
5950Sstevel@tonic-gate 		getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags);
5960Sstevel@tonic-gate 		if (getcode == -1) {
5970Sstevel@tonic-gate 			logperror("mibget getmsg(ctl) failed");
5980Sstevel@tonic-gate 			if (debug) {
5990Sstevel@tonic-gate 				logdebug("#   level   name    len\n");
6000Sstevel@tonic-gate 				i = 0;
6010Sstevel@tonic-gate 				for (last_item = first_item; last_item;
6020Sstevel@tonic-gate 					last_item = last_item->next_item)
6030Sstevel@tonic-gate 					(void) printf("%d  %4d   %5d   %d\n",
6040Sstevel@tonic-gate 					    ++i,
6050Sstevel@tonic-gate 					    last_item->group,
6060Sstevel@tonic-gate 					    last_item->mib_id,
6070Sstevel@tonic-gate 					    last_item->length);
6080Sstevel@tonic-gate 			}
6090Sstevel@tonic-gate 			goto error_exit;
6100Sstevel@tonic-gate 		}
6110Sstevel@tonic-gate 		if (getcode == 0 &&
6120Sstevel@tonic-gate 		    ctlbuf.len >= sizeof (struct T_optmgmt_ack) &&
6130Sstevel@tonic-gate 		    toa->PRIM_type == T_OPTMGMT_ACK &&
6140Sstevel@tonic-gate 		    toa->MGMT_flags == T_SUCCESS &&
6150Sstevel@tonic-gate 		    req->len == 0) {
6160Sstevel@tonic-gate 			if (debug) {
6170Sstevel@tonic-gate 				logdebug("mibget getmsg() %d returned "
6180Sstevel@tonic-gate 				    "EOD (level %ld, name %ld)\n",
6190Sstevel@tonic-gate 				    j, req->level, req->name);
6200Sstevel@tonic-gate 			}
6210Sstevel@tonic-gate 			return (first_item);		/* this is EOD msg */
6220Sstevel@tonic-gate 		}
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 		if (ctlbuf.len >= sizeof (struct T_error_ack) &&
6250Sstevel@tonic-gate 		    tea->PRIM_type == T_ERROR_ACK) {
6260Sstevel@tonic-gate 			logwarn("mibget %d gives T_ERROR_ACK: TLI_error ="
6270Sstevel@tonic-gate 			    " 0x%lx, UNIX_error = 0x%lx\n",
6280Sstevel@tonic-gate 			    j, tea->TLI_error, tea->UNIX_error);
6290Sstevel@tonic-gate 			errno = (tea->TLI_error == TSYSERR) ?
6300Sstevel@tonic-gate 			    tea->UNIX_error : EPROTO;
6310Sstevel@tonic-gate 			goto error_exit;
6320Sstevel@tonic-gate 		}
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 		if (getcode != MOREDATA ||
6350Sstevel@tonic-gate 		    ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
6360Sstevel@tonic-gate 		    toa->PRIM_type != T_OPTMGMT_ACK ||
6370Sstevel@tonic-gate 		    toa->MGMT_flags != T_SUCCESS) {
6380Sstevel@tonic-gate 			logwarn("mibget getmsg(ctl) %d returned %d, "
6390Sstevel@tonic-gate 			    "ctlbuf.len = %d, PRIM_type = %ld\n",
6400Sstevel@tonic-gate 			    j, getcode, ctlbuf.len, toa->PRIM_type);
6410Sstevel@tonic-gate 			if (toa->PRIM_type == T_OPTMGMT_ACK) {
6420Sstevel@tonic-gate 				logwarn("T_OPTMGMT_ACK: "
6430Sstevel@tonic-gate 				    "MGMT_flags = 0x%lx, req->len = %ld\n",
6440Sstevel@tonic-gate 				    toa->MGMT_flags, req->len);
6450Sstevel@tonic-gate 			}
6460Sstevel@tonic-gate 			errno = ENOMSG;
6470Sstevel@tonic-gate 			goto error_exit;
6480Sstevel@tonic-gate 		}
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		temp = (mib_item_t *)malloc(sizeof (mib_item_t));
6510Sstevel@tonic-gate 		if (!temp) {
6520Sstevel@tonic-gate 			logperror("mibget malloc failed");
6530Sstevel@tonic-gate 			goto error_exit;
6540Sstevel@tonic-gate 		}
6550Sstevel@tonic-gate 		if (last_item)
6560Sstevel@tonic-gate 			last_item->next_item = temp;
6570Sstevel@tonic-gate 		else
6580Sstevel@tonic-gate 			first_item = temp;
6590Sstevel@tonic-gate 		last_item = temp;
6600Sstevel@tonic-gate 		last_item->next_item = (mib_item_t *)0;
6610Sstevel@tonic-gate 		last_item->group = req->level;
6620Sstevel@tonic-gate 		last_item->mib_id = req->name;
6630Sstevel@tonic-gate 		last_item->length = req->len;
6640Sstevel@tonic-gate 		last_item->valp = malloc((int)req->len);
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 		databuf.maxlen = last_item->length;
6670Sstevel@tonic-gate 		databuf.buf    = last_item->valp;
6680Sstevel@tonic-gate 		databuf.len    = 0;
6690Sstevel@tonic-gate 		flags = 0;
6700Sstevel@tonic-gate 		getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags);
6710Sstevel@tonic-gate 		if (getcode == -1) {
6720Sstevel@tonic-gate 			logperror("mibget getmsg(data) failed");
6730Sstevel@tonic-gate 			goto error_exit;
6740Sstevel@tonic-gate 		} else if (getcode != 0) {
6750Sstevel@tonic-gate 			logwarn("mibget getmsg(data) returned %d, "
6760Sstevel@tonic-gate 			    "databuf.maxlen = %d, databuf.len = %d\n",
6770Sstevel@tonic-gate 			    getcode, databuf.maxlen, databuf.len);
6780Sstevel@tonic-gate 			goto error_exit;
6790Sstevel@tonic-gate 		}
6800Sstevel@tonic-gate 		j++;
6810Sstevel@tonic-gate 	}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate error_exit:;
6840Sstevel@tonic-gate 	while (first_item) {
6850Sstevel@tonic-gate 		last_item = first_item;
6860Sstevel@tonic-gate 		first_item = first_item->next_item;
6870Sstevel@tonic-gate 		free(last_item);
6880Sstevel@tonic-gate 	}
6890Sstevel@tonic-gate 	return (first_item);
6900Sstevel@tonic-gate }
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate /*
6930Sstevel@tonic-gate  * Examine the IPv4 routing table for default routers.  For each interface,
6940Sstevel@tonic-gate  * find its default router.
6950Sstevel@tonic-gate  *
6960Sstevel@tonic-gate  * Param:
6970Sstevel@tonic-gate  *	mib2_ipRouteEntry_t *buf: the mib info buffer.
6980Sstevel@tonic-gate  *	size_t len: length of buffer.
6990Sstevel@tonic-gate  *	boolean_t *changed (referenced): set to B_TRUE if there is a change
7000Sstevel@tonic-gate  *		in router info.
7010Sstevel@tonic-gate  *
7020Sstevel@tonic-gate  * Return:
7030Sstevel@tonic-gate  *	number of default router found.
7040Sstevel@tonic-gate  */
7050Sstevel@tonic-gate static int
ire_process(mib2_ipRouteEntry_t * buf,size_t len,boolean_t * changed)7060Sstevel@tonic-gate ire_process(mib2_ipRouteEntry_t *buf, size_t len, boolean_t *changed)
7070Sstevel@tonic-gate {
7080Sstevel@tonic-gate 	mib2_ipRouteEntry_t 	*rp;
7090Sstevel@tonic-gate 	mib2_ipRouteEntry_t 	*rp1;
7100Sstevel@tonic-gate 	mib2_ipRouteEntry_t 	*rp2;
7110Sstevel@tonic-gate 	struct	in_addr		nexthop_v4;
7120Sstevel@tonic-gate 	mib2_ipRouteEntry_t	*endp;
7130Sstevel@tonic-gate 	char			ifname[LIFNAMSIZ + 1];
7140Sstevel@tonic-gate 	char			*cp;
7150Sstevel@tonic-gate 	int			i;
7160Sstevel@tonic-gate 	int			ifname_len;
7170Sstevel@tonic-gate 	boolean_t		found;
7180Sstevel@tonic-gate 	int			num_found = 0;
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	if (len == 0)
7210Sstevel@tonic-gate 		return (0);
7220Sstevel@tonic-gate 	endp = buf + (len / sizeof (mib2_ipRouteEntry_t));
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	for (i = 0; i < num_nif; i++) {
7250Sstevel@tonic-gate 		/*
7260Sstevel@tonic-gate 		 * Loop thru the routing table entries. Process any
7270Sstevel@tonic-gate 		 * IRE_DEFAULT ire.  Ignore the others.  For each such
7280Sstevel@tonic-gate 		 * ire, get the nexthop gateway address.
7290Sstevel@tonic-gate 		 */
7300Sstevel@tonic-gate 		found = B_FALSE;
7310Sstevel@tonic-gate 		for (rp = buf; rp < endp; rp++) {
7320Sstevel@tonic-gate 			/*
7330Sstevel@tonic-gate 			 * NCA is only interested in default routes associated
7340Sstevel@tonic-gate 			 * with an interface.
7350Sstevel@tonic-gate 			 */
7360Sstevel@tonic-gate 			if (!(rp->ipRouteInfo.re_ire_type & IRE_DEFAULT)) {
7370Sstevel@tonic-gate 				continue;
7380Sstevel@tonic-gate 			}
7390Sstevel@tonic-gate 			/*  Get the nexthop address. */
7400Sstevel@tonic-gate 			nexthop_v4.s_addr = rp->ipRouteNextHop;
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 			/*
7430Sstevel@tonic-gate 			 * Right now, not all IREs have the interface name
7440Sstevel@tonic-gate 			 * it is associated with.
7450Sstevel@tonic-gate 			 */
7460Sstevel@tonic-gate 			if (rp->ipRouteIfIndex.o_length == 0) {
7470Sstevel@tonic-gate 				/*
7480Sstevel@tonic-gate 				 * We don't have the outgoing interface in
7490Sstevel@tonic-gate 				 * this case.  Get the nexthop address. Then
7500Sstevel@tonic-gate 				 * determine the outgoing interface, by
7510Sstevel@tonic-gate 				 * examining all interface IREs, and
7520Sstevel@tonic-gate 				 * picking the match.
7530Sstevel@tonic-gate 				 */
7540Sstevel@tonic-gate 				for (rp1 = buf; rp1 < endp; rp1++) {
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 				if (!(rp1->ipRouteInfo.re_ire_type &
7570Sstevel@tonic-gate 				    IRE_INTERFACE)) {
7580Sstevel@tonic-gate 					continue;
7590Sstevel@tonic-gate 				}
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 				/*
7620Sstevel@tonic-gate 				 * Determine the interface IRE that
7630Sstevel@tonic-gate 				 * matches the nexthop. i.e.
7640Sstevel@tonic-gate 				 * (IRE addr & IRE mask) ==
7650Sstevel@tonic-gate 				 * (nexthop & IRE mask)
7660Sstevel@tonic-gate 				 */
7670Sstevel@tonic-gate 				if ((rp1->ipRouteDest & rp1->ipRouteMask) ==
7680Sstevel@tonic-gate 				    (nexthop_v4.s_addr & rp1->ipRouteMask)) {
7690Sstevel@tonic-gate 					/*
7700Sstevel@tonic-gate 					 * We found the interface to go to
7710Sstevel@tonic-gate 					 * the default router.  Check the
7720Sstevel@tonic-gate 					 * interface name.
7730Sstevel@tonic-gate 					 */
7740Sstevel@tonic-gate 					/* Can this be possible?? */
7750Sstevel@tonic-gate 					if (rp1->ipRouteIfIndex.o_length == 0)
7760Sstevel@tonic-gate 						continue;
7770Sstevel@tonic-gate 					rp2 = rp1;
7780Sstevel@tonic-gate 					break;
7790Sstevel@tonic-gate 				}
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 				} /* End inner for loop. */
7820Sstevel@tonic-gate 			} else {
7830Sstevel@tonic-gate 				rp2 = rp;
7840Sstevel@tonic-gate 			}
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 			ifname_len = MIN(rp2->ipRouteIfIndex.o_length,
7870Sstevel@tonic-gate 			    sizeof (ifname) - 1);
7880Sstevel@tonic-gate 			(void) memcpy(ifname, rp2->ipRouteIfIndex.o_bytes,
7890Sstevel@tonic-gate 			    ifname_len);
7900Sstevel@tonic-gate 			ifname[ifname_len] = '\0';
7910Sstevel@tonic-gate 			if (ifname[0] == '\0')
7920Sstevel@tonic-gate 				continue;
7930Sstevel@tonic-gate 			cp = strchr(ifname, IF_SEPARATOR);
7940Sstevel@tonic-gate 			if (cp != NULL)
7950Sstevel@tonic-gate 				*cp = '\0';
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 			/* We are sure both are NULL terminated. */
7980Sstevel@tonic-gate 			if (strcmp(nif_list[i].name, ifname) == 0) {
7990Sstevel@tonic-gate 				/* No change, do not do anything. */
8000Sstevel@tonic-gate 				if (nexthop_v4.s_addr ==
8010Sstevel@tonic-gate 				    nif_list[i].router_addr.s_addr) {
8020Sstevel@tonic-gate 					found = B_TRUE;
8030Sstevel@tonic-gate 					break;
8040Sstevel@tonic-gate 				}
8050Sstevel@tonic-gate 				nif_list[i].router_addr.s_addr =
8060Sstevel@tonic-gate 				    nexthop_v4.s_addr;
8070Sstevel@tonic-gate 				if (debug) {
8080Sstevel@tonic-gate 					logdebug("Get default"
8090Sstevel@tonic-gate 					    " router for %s: %s\n", ifname,
8100Sstevel@tonic-gate 					    inet_ntoa(nexthop_v4));
8110Sstevel@tonic-gate 				}
8120Sstevel@tonic-gate 				found = B_TRUE;
8130Sstevel@tonic-gate 				*changed = B_TRUE;
8140Sstevel@tonic-gate 				break;
8150Sstevel@tonic-gate 			}
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 		}
8180Sstevel@tonic-gate 		if (!found) {
8190Sstevel@tonic-gate 			/*
8200Sstevel@tonic-gate 			 * The interface does not have a default router.
8210Sstevel@tonic-gate 			 * Log a warning and go on.
8220Sstevel@tonic-gate 			 */
8230Sstevel@tonic-gate 			logwarn(gettext("Network interface %s"
8240Sstevel@tonic-gate 			    " does not have a default router.\n"),
8250Sstevel@tonic-gate 			    nif_list[i].name);
8260Sstevel@tonic-gate 			/*
8270Sstevel@tonic-gate 			 * Set router_addr to 0 so that we will
8280Sstevel@tonic-gate 			 * not do anything for this interface.
8290Sstevel@tonic-gate 			 */
8300Sstevel@tonic-gate 			nif_list[i].router_addr.s_addr = 0;
8310Sstevel@tonic-gate 		} else {
8320Sstevel@tonic-gate 			num_found++;
8330Sstevel@tonic-gate 		}
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 	return (num_found);
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate /*
8390Sstevel@tonic-gate  * Examine the ARP table to find ethernet address for default routers.
8400Sstevel@tonic-gate  *
8410Sstevel@tonic-gate  * Param:
8420Sstevel@tonic-gate  *	mib2_ipNetToMdeiaEntry_t *buf: the mib info buffer.
8430Sstevel@tonic-gate  *	size_t len: length of buffer.
8440Sstevel@tonic-gate  *	boolean_t *changed (referenced): set to B_TRUE if there is any change
8450Sstevel@tonic-gate  *		in ethernet address for any default router.
8460Sstevel@tonic-gate  *
8470Sstevel@tonic-gate  * Return:
8480Sstevel@tonic-gate  *	number of ethernet address found.
8490Sstevel@tonic-gate  */
8500Sstevel@tonic-gate static int
arp_process(mib2_ipNetToMediaEntry_t * buf,size_t len,boolean_t * changed)8510Sstevel@tonic-gate arp_process(mib2_ipNetToMediaEntry_t *buf, size_t len, boolean_t *changed)
8520Sstevel@tonic-gate {
8530Sstevel@tonic-gate 	mib2_ipNetToMediaEntry_t 	*rp;
8540Sstevel@tonic-gate 	mib2_ipNetToMediaEntry_t	*endp;
8550Sstevel@tonic-gate 	int				i;
8560Sstevel@tonic-gate 	boolean_t			found;
8570Sstevel@tonic-gate 	int				num_found = 0;
8580Sstevel@tonic-gate 	uchar_t				*src, *dst;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	if (len == 0)
8610Sstevel@tonic-gate 		return (0);
8620Sstevel@tonic-gate 	endp = buf + (len / sizeof (mib2_ipNetToMediaEntry_t));
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	for (i = 0; i < num_nif; i++) {
8650Sstevel@tonic-gate 		/*
8660Sstevel@tonic-gate 		 * Loop thru the arp table entries and find the ethernet
8670Sstevel@tonic-gate 		 * address of those default routers.
8680Sstevel@tonic-gate 		 */
8690Sstevel@tonic-gate 		if (nif_list[i].router_addr.s_addr == 0)
8700Sstevel@tonic-gate 			continue;
8710Sstevel@tonic-gate 		found = B_FALSE;
8720Sstevel@tonic-gate 		for (rp = buf; rp < endp; rp++) {
8730Sstevel@tonic-gate 			if (rp->ipNetToMediaNetAddress ==
8740Sstevel@tonic-gate 			    nif_list[i].router_addr.s_addr) {
8750Sstevel@tonic-gate 				/*
8760Sstevel@tonic-gate 				 * Sanity check.  Make sure that this
8770Sstevel@tonic-gate 				 * default router is only reachable thru this
8780Sstevel@tonic-gate 				 * interface.
8790Sstevel@tonic-gate 				 */
8800Sstevel@tonic-gate 				if (rp->ipNetToMediaIfIndex.o_length !=
8810Sstevel@tonic-gate 				    strlen(nif_list[i].name) ||
8820Sstevel@tonic-gate 				    strncmp(rp->ipNetToMediaIfIndex.o_bytes,
8830Sstevel@tonic-gate 					nif_list[i].name,
8840Sstevel@tonic-gate 					rp->ipNetToMediaIfIndex.o_length) !=
8850Sstevel@tonic-gate 				    0) {
8860Sstevel@tonic-gate 					break;
8870Sstevel@tonic-gate 				}
8880Sstevel@tonic-gate 				/* No change, do not do anything. */
8890Sstevel@tonic-gate 				if (bcmp(nif_list[i].router_ether_addr,
8900Sstevel@tonic-gate 				    rp->ipNetToMediaPhysAddress.o_bytes,
8910Sstevel@tonic-gate 				    ETHERADDRL) == 0) {
8920Sstevel@tonic-gate 					found = B_TRUE;
8930Sstevel@tonic-gate 					continue;
8940Sstevel@tonic-gate 				}
8950Sstevel@tonic-gate 				dst = nif_list[i].router_ether_addr;
8960Sstevel@tonic-gate 				src = (uchar_t *)
8970Sstevel@tonic-gate 				    rp->ipNetToMediaPhysAddress.o_bytes;
8980Sstevel@tonic-gate 				for (len = ETHERADDRL; len > 0; len--)
8990Sstevel@tonic-gate 					*dst++ = *src++;
9000Sstevel@tonic-gate 				if (debug) {
9010Sstevel@tonic-gate 					int j;
9020Sstevel@tonic-gate 					uchar_t *cp;
9030Sstevel@tonic-gate 					char err_buf[128];
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 					(void) snprintf(err_buf,
9060Sstevel@tonic-gate 					    sizeof (err_buf),
9070Sstevel@tonic-gate 					    "Get address for %s: ",
9080Sstevel@tonic-gate 					    inet_ntoa(nif_list[i].router_addr));
9090Sstevel@tonic-gate 					cp = (uchar_t *)
9100Sstevel@tonic-gate 					    nif_list[i].router_ether_addr;
9110Sstevel@tonic-gate 					for (j = 0; j < ETHERADDRL; j++) {
9120Sstevel@tonic-gate 						(void) sprintf(err_buf +
9130Sstevel@tonic-gate 						    strlen(err_buf),
9140Sstevel@tonic-gate 						    "%02x:", 0xff & cp[j]);
9150Sstevel@tonic-gate 					}
9160Sstevel@tonic-gate 					(void) sprintf(err_buf +
9170Sstevel@tonic-gate 					    strlen(err_buf) - 1, "\n");
9180Sstevel@tonic-gate 					logdebug(err_buf);
9190Sstevel@tonic-gate 				}
9200Sstevel@tonic-gate 				found = B_TRUE;
9210Sstevel@tonic-gate 				*changed = B_TRUE;
9220Sstevel@tonic-gate 			}
9230Sstevel@tonic-gate 		}
9240Sstevel@tonic-gate 		if (!found) {
9250Sstevel@tonic-gate 			logwarn("Cannot reach %s using %s\n",
9260Sstevel@tonic-gate 			    inet_ntoa(nif_list[i].router_addr),
9270Sstevel@tonic-gate 			    nif_list[i].name);
9280Sstevel@tonic-gate 			/* Clear this default router. */
9290Sstevel@tonic-gate 			nif_list[i].router_addr.s_addr = 0;
9300Sstevel@tonic-gate 		} else {
9310Sstevel@tonic-gate 			num_found++;
9320Sstevel@tonic-gate 		}
9330Sstevel@tonic-gate 	}
9340Sstevel@tonic-gate 	return (num_found);
9350Sstevel@tonic-gate }
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate /*
9380Sstevel@tonic-gate  * Get IP address of default routers for each interface.
9390Sstevel@tonic-gate  *
9400Sstevel@tonic-gate  * Param:
9410Sstevel@tonic-gate  *	mib_item_t *item: the mib info buffer.
9420Sstevel@tonic-gate  *	boolean_t *changed (referenced): set to B_TRUE if there is any change
9430Sstevel@tonic-gate  *		in router info.
9440Sstevel@tonic-gate  *
9450Sstevel@tonic-gate  * Return:
9460Sstevel@tonic-gate  *	-1 if there is no router found, 0 otherwise.
9470Sstevel@tonic-gate  */
9480Sstevel@tonic-gate static int
get_router_ip_addr(mib_item_t * item,boolean_t * changed)9490Sstevel@tonic-gate get_router_ip_addr(mib_item_t *item, boolean_t *changed)
9500Sstevel@tonic-gate {
9510Sstevel@tonic-gate 	int found = 0;
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	for (; item != NULL; item = item->next_item) {
9540Sstevel@tonic-gate 		/* NCA does not support IPv6... */
9550Sstevel@tonic-gate 		if (!(item->group == MIB2_IP && item->mib_id == MIB2_IP_ROUTE))
9560Sstevel@tonic-gate 			continue;
9570Sstevel@tonic-gate 		/* LINTED */
9580Sstevel@tonic-gate 		found += ire_process((mib2_ipRouteEntry_t *)item->valp,
9590Sstevel@tonic-gate 		    item->length, changed);
9600Sstevel@tonic-gate 	}
9610Sstevel@tonic-gate 	if (found == 0)
9620Sstevel@tonic-gate 		return (-1);
9630Sstevel@tonic-gate 	else
9640Sstevel@tonic-gate 		return (0);
9650Sstevel@tonic-gate }
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate /*
9680Sstevel@tonic-gate  * Get Ethernet address for each default router from ARP.
9690Sstevel@tonic-gate  *
9700Sstevel@tonic-gate  * Param:
9710Sstevel@tonic-gate  *	mib_item_t *item: the mib info buffer.
9720Sstevel@tonic-gate  *	boolean_t *changed (referenced): set to B_TRUE if there is any change
9730Sstevel@tonic-gate  *		in ethernet address of router.
9740Sstevel@tonic-gate  *
9750Sstevel@tonic-gate  * Return:
9760Sstevel@tonic-gate  *	-1 if there is no ethernet address found, 0 otherwise.
9770Sstevel@tonic-gate  */
9780Sstevel@tonic-gate static int
get_router_ether_addr(mib_item_t * item,boolean_t * changed)9790Sstevel@tonic-gate get_router_ether_addr(mib_item_t *item, boolean_t *changed)
9800Sstevel@tonic-gate {
9810Sstevel@tonic-gate 	int found = 0;
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	for (; item != NULL; item = item->next_item) {
9840Sstevel@tonic-gate 		/* NCA does not support IPv6... */
9850Sstevel@tonic-gate 		if (!(item->group == MIB2_IP && item->mib_id == MIB2_IP_MEDIA))
9860Sstevel@tonic-gate 			continue;
9870Sstevel@tonic-gate 		/* LINTED */
9880Sstevel@tonic-gate 		found += arp_process((mib2_ipNetToMediaEntry_t *)item->valp,
9890Sstevel@tonic-gate 		    item->length, changed);
9900Sstevel@tonic-gate 	}
9910Sstevel@tonic-gate 	if (found == 0)
9920Sstevel@tonic-gate 		return (-1);
9930Sstevel@tonic-gate 	else
9940Sstevel@tonic-gate 		return (0);
9950Sstevel@tonic-gate }
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate /*
9980Sstevel@tonic-gate  * Ping all default routers.  It just uses system(3F) to call
9990Sstevel@tonic-gate  * ping(1M) to do the job...
10000Sstevel@tonic-gate  */
10010Sstevel@tonic-gate static void
ping_them(void)10020Sstevel@tonic-gate ping_them(void)
10030Sstevel@tonic-gate {
10040Sstevel@tonic-gate 	int i;
10050Sstevel@tonic-gate 	char ping_cmd[128];
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	for (i = 0; i < num_nif; i++) {
10080Sstevel@tonic-gate 		if (nif_list[i].router_addr.s_addr != 0) {
10090Sstevel@tonic-gate 			(void) snprintf(ping_cmd, sizeof (ping_cmd),
10100Sstevel@tonic-gate 			    "%s %s > /dev/null 2>&1",
10110Sstevel@tonic-gate 			    ping_prog,
10120Sstevel@tonic-gate 			    inet_ntoa(nif_list[i].router_addr));
10130Sstevel@tonic-gate 			(void) system(ping_cmd);
10140Sstevel@tonic-gate 		}
10150Sstevel@tonic-gate 	}
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate /*
10190Sstevel@tonic-gate  * To get default router info (both IP address and ethernet address) for
10200Sstevel@tonic-gate  * each configured interface from IP.
10210Sstevel@tonic-gate  *
10220Sstevel@tonic-gate  * Param:
10230Sstevel@tonic-gate  *	boolean_t *changed (referenced): set to B_TRUE if there is any change
10240Sstevel@tonic-gate  *		of info.
10250Sstevel@tonic-gate  *
10260Sstevel@tonic-gate  * Return:
10270Sstevel@tonic-gate  *	-1 if there is any error, 0 if everything is fine.
10280Sstevel@tonic-gate  */
10290Sstevel@tonic-gate static int
get_if_info(boolean_t * changed)10300Sstevel@tonic-gate get_if_info(boolean_t *changed)
10310Sstevel@tonic-gate {
10320Sstevel@tonic-gate 	int mib_fd;
10330Sstevel@tonic-gate 	mib_item_t *item;
10340Sstevel@tonic-gate 	boolean_t ip_changed = B_FALSE;
10350Sstevel@tonic-gate 	boolean_t ether_changed = B_FALSE;
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	if ((mib_fd = open(IP_DEV_NAME, O_RDWR)) < 0) {
10380Sstevel@tonic-gate 		logperror("cannot open ip to get router info");
10390Sstevel@tonic-gate 		return (-1);
10400Sstevel@tonic-gate 	}
10410Sstevel@tonic-gate 	if (ioctl(mib_fd, I_PUSH, ARP_MOD_NAME) == -1) {
10420Sstevel@tonic-gate 		logperror("cannot push arp");
10430Sstevel@tonic-gate 		goto err;
10440Sstevel@tonic-gate 	}
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	if ((item = mibget(mib_fd)) == NULL) {
10470Sstevel@tonic-gate 		goto err;
10480Sstevel@tonic-gate 	}
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	if (get_router_ip_addr(item, &ip_changed) < 0) {
10510Sstevel@tonic-gate 		goto err;
10520Sstevel@tonic-gate 	}
10530Sstevel@tonic-gate 	/*
10540Sstevel@tonic-gate 	 * Ping every routers to make sure that ARP has all their ethernet
10550Sstevel@tonic-gate 	 * addresses.
10560Sstevel@tonic-gate 	 */
10570Sstevel@tonic-gate 	ping_them();
10580Sstevel@tonic-gate 	/*
10590Sstevel@tonic-gate 	 * If the router IP address is not changed, its ethernet address
10600Sstevel@tonic-gate 	 * should not be changed.  But just in case there is some IP
10610Sstevel@tonic-gate 	 * failover going on...
10620Sstevel@tonic-gate 	 */
10630Sstevel@tonic-gate 	if (get_router_ether_addr(item, &ether_changed) < 0) {
10640Sstevel@tonic-gate 		goto err;
10650Sstevel@tonic-gate 	}
10660Sstevel@tonic-gate 	(void) close(mib_fd);
10670Sstevel@tonic-gate 	*changed = ip_changed || ether_changed;
10680Sstevel@tonic-gate 	return (0);
10690Sstevel@tonic-gate err:
10700Sstevel@tonic-gate 	(void) close(mib_fd);
10710Sstevel@tonic-gate 	return (-1);
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate /*
10750Sstevel@tonic-gate  * To remove the default router from an interface.
10760Sstevel@tonic-gate  *
10770Sstevel@tonic-gate  * Param:
10780Sstevel@tonic-gate  *	struct in_addr gw_addr: the IP address of the default router to be
10790Sstevel@tonic-gate  *	removed.
10800Sstevel@tonic-gate  */
10810Sstevel@tonic-gate static void
nca_del_nif(struct in_addr gw_addr)10820Sstevel@tonic-gate nca_del_nif(struct in_addr gw_addr)
10830Sstevel@tonic-gate {
10840Sstevel@tonic-gate 	struct nca_set_ioctl nca_ioctl;
10850Sstevel@tonic-gate 	struct strioctl strioc;
10860Sstevel@tonic-gate 	int i;
10870Sstevel@tonic-gate 	int udp_fd, fd;
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	/* Search for the interface for this router. */
10900Sstevel@tonic-gate 	for (i = 0; i < num_nif; i++) {
10910Sstevel@tonic-gate 		if (nif_list[i].router_addr.s_addr == gw_addr.s_addr)
10920Sstevel@tonic-gate 			break;
10930Sstevel@tonic-gate 	}
10940Sstevel@tonic-gate 	if (i == num_nif)
10950Sstevel@tonic-gate 		return;
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	if (ip_domux2fd(&udp_fd, &fd) < 0) {
10980Sstevel@tonic-gate 		logwarn(gettext("Removing interface %s from the"
10990Sstevel@tonic-gate 		    " configuration list.\n"), nif_list[i].name);
11000Sstevel@tonic-gate 		nif_list[i].name[0] = 0;
11010Sstevel@tonic-gate 		return;
11020Sstevel@tonic-gate 	}
11030Sstevel@tonic-gate 	if (ioctl(udp_fd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) {
11040Sstevel@tonic-gate 		logwarn(gettext("Removing interface %s from the"
11050Sstevel@tonic-gate 		    " configuration list.\n"), nif_list[i].name);
11060Sstevel@tonic-gate 		nif_list[i].name[0] = 0;
11070Sstevel@tonic-gate 		(void) close(udp_fd);
11080Sstevel@tonic-gate 		(void) close(fd);
11090Sstevel@tonic-gate 		return;
11100Sstevel@tonic-gate 	}
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	strioc.ic_cmd = NCA_SET_IF;
11130Sstevel@tonic-gate 	strioc.ic_timout = INFTIM;
11140Sstevel@tonic-gate 	strioc.ic_len = sizeof (nca_ioctl);
11150Sstevel@tonic-gate 	strioc.ic_dp = (char *)&nca_ioctl;
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	nca_ioctl.local_addr = 0;
11180Sstevel@tonic-gate 	(void) memset(nca_ioctl.router_ether_addr, 0, ETHERADDRL);
11190Sstevel@tonic-gate 	nca_ioctl.action = DEL_DEF_ROUTE;
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &strioc) < 0) {
11220Sstevel@tonic-gate 		logperror("ioctl(NCA_SET_IF) failed");
11230Sstevel@tonic-gate 	}
11240Sstevel@tonic-gate 	ip_plink(udp_fd, fd);
11250Sstevel@tonic-gate 	(void) close(udp_fd);
11260Sstevel@tonic-gate 	(void) close(fd);
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	/* Clear the fields for this interface. */
11290Sstevel@tonic-gate 	nif_list[i].router_addr.s_addr = 0;
11300Sstevel@tonic-gate 	(void) memset(nif_list[i].router_ether_addr, 0, ETHERADDRL);
11310Sstevel@tonic-gate }
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate /*
11340Sstevel@tonic-gate  * Wait for any changes in the routing table.  If there are changes to
11350Sstevel@tonic-gate  * IP address or router ethernet address, send down the info to NCA.
11360Sstevel@tonic-gate  */
11370Sstevel@tonic-gate static void
daemon_work(void)11380Sstevel@tonic-gate daemon_work(void)
11390Sstevel@tonic-gate {
11400Sstevel@tonic-gate 	int n;
11410Sstevel@tonic-gate 	int i;
11420Sstevel@tonic-gate 	int udp_fd;
11430Sstevel@tonic-gate 	int fd;
11440Sstevel@tonic-gate 	int64_t msg[2048/8];
11450Sstevel@tonic-gate 	struct rt_msghdr *rtm;
11460Sstevel@tonic-gate 	boolean_t changed;
11470Sstevel@tonic-gate 	struct sockaddr_in *sin;
11480Sstevel@tonic-gate 	struct in_addr gw_addr;
11490Sstevel@tonic-gate 	uchar_t *cp;
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 	/* Loop forever waiting for any routing changes. */
11520Sstevel@tonic-gate 	for (;;) {
11530Sstevel@tonic-gate 		if (debug) {
11540Sstevel@tonic-gate 			logdebug("Waiting to read routing info...\n");
11550Sstevel@tonic-gate 		}
11560Sstevel@tonic-gate 		n = read(rt_fd, msg, sizeof (msg));
11570Sstevel@tonic-gate 		/* Don't die...  Reinitialize socket and listen again. */
11580Sstevel@tonic-gate 		if (n <= 0) {
11590Sstevel@tonic-gate 			if (debug) {
11600Sstevel@tonic-gate 				logdebug("Routing socket read error.\n");
11610Sstevel@tonic-gate 			}
11620Sstevel@tonic-gate 			(void) close(rt_fd);
11630Sstevel@tonic-gate 			rt_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET);
11640Sstevel@tonic-gate 			i = 0;
11650Sstevel@tonic-gate 			while (rt_fd < 0) {
11660Sstevel@tonic-gate 				if (i++ == 0) {
11670Sstevel@tonic-gate 					logperror(gettext("cannot reinitialize"
11680Sstevel@tonic-gate 					    " routing socket"));
11690Sstevel@tonic-gate 				} else if (i > 5) {
11700Sstevel@tonic-gate 					logwarn(gettext("Give up on trying to"
11710Sstevel@tonic-gate 					    " reinitializing routing"
11720Sstevel@tonic-gate 					    " socket\n"));
11730Sstevel@tonic-gate 					exit(1);
11740Sstevel@tonic-gate 				}
11750Sstevel@tonic-gate 				/* May be a transient error... */
11760Sstevel@tonic-gate 				(void) sleep(10);
11770Sstevel@tonic-gate 				rt_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET);
11780Sstevel@tonic-gate 			}
11790Sstevel@tonic-gate 		} else {
11800Sstevel@tonic-gate 			rtm = (struct rt_msghdr *)msg;
11810Sstevel@tonic-gate 			if (rtm->rtm_version != RTM_VERSION) {
11820Sstevel@tonic-gate 				logwarn(gettext("Do non understand routing"
11830Sstevel@tonic-gate 				    " socket info.\n"));
11840Sstevel@tonic-gate 				continue;
11850Sstevel@tonic-gate 			}
11860Sstevel@tonic-gate 			if (debug) {
11870Sstevel@tonic-gate 				logdebug("Get routing info.\n");
11880Sstevel@tonic-gate 			}
11890Sstevel@tonic-gate 			switch (rtm->rtm_type) {
11900Sstevel@tonic-gate 			case RTM_DELETE:
11910Sstevel@tonic-gate 			case RTM_OLDDEL:
11920Sstevel@tonic-gate 				sin = (struct sockaddr_in *)(rtm + 1);
11930Sstevel@tonic-gate 				cp = (uchar_t *)sin;
11940Sstevel@tonic-gate 				/* Only handle default route deletion. */
11950Sstevel@tonic-gate 				if ((rtm->rtm_addrs & RTA_DST) &&
11960Sstevel@tonic-gate 				    (sin->sin_addr.s_addr == 0)) {
11970Sstevel@tonic-gate 					if (!(rtm->rtm_addrs & RTA_GATEWAY)) {
11980Sstevel@tonic-gate 						break;
11990Sstevel@tonic-gate 					}
12000Sstevel@tonic-gate 					cp += sizeof (struct sockaddr_in);
12010Sstevel@tonic-gate 					/* LINTED */
12020Sstevel@tonic-gate 					sin = (struct sockaddr_in *)cp;
12030Sstevel@tonic-gate 					gw_addr = sin->sin_addr;
12040Sstevel@tonic-gate 					if (debug) {
12050Sstevel@tonic-gate 						logdebug("Get default route "
12060Sstevel@tonic-gate 						    "removal notice: gw %s\n",
12070Sstevel@tonic-gate 						    inet_ntoa(gw_addr));
12080Sstevel@tonic-gate 					}
12090Sstevel@tonic-gate 					nca_del_nif(gw_addr);
12100Sstevel@tonic-gate 				}
12110Sstevel@tonic-gate 				break;
12120Sstevel@tonic-gate 			case RTM_ADD:
12130Sstevel@tonic-gate 			case RTM_OLDADD:
12140Sstevel@tonic-gate 			case RTM_CHANGE:
12150Sstevel@tonic-gate 				changed = B_FALSE;
12160Sstevel@tonic-gate 				if (get_if_info(&changed) < 0) {
12170Sstevel@tonic-gate 					/* May be a transient error... */
12180Sstevel@tonic-gate 					(void) sleep(10);
12190Sstevel@tonic-gate 					break;
12200Sstevel@tonic-gate 				}
12210Sstevel@tonic-gate 				/* Nothing is changed, do nothing. */
12220Sstevel@tonic-gate 				if (!changed) {
12230Sstevel@tonic-gate 					if (debug) {
12240Sstevel@tonic-gate 						logdebug("Get route change "
12250Sstevel@tonic-gate 						    "notice, but nothing is "
12260Sstevel@tonic-gate 						    "changed for us!");
12270Sstevel@tonic-gate 					}
12280Sstevel@tonic-gate 					break;
12290Sstevel@tonic-gate 				}
12300Sstevel@tonic-gate 				lifr.lifr_addr.ss_family = AF_INET;
12310Sstevel@tonic-gate 				for (i = 0; i < num_nif; i++) {
12320Sstevel@tonic-gate 					int ret;
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 					/*
12350Sstevel@tonic-gate 					 * If name is NULL, it means that
12360Sstevel@tonic-gate 					 * we have encontered some problems
12370Sstevel@tonic-gate 					 * when configurating the interface.
12380Sstevel@tonic-gate 					 * So we remove it from the list.
12390Sstevel@tonic-gate 					 */
12400Sstevel@tonic-gate 					if (nif_list[i].name[0] == 0 ||
12410Sstevel@tonic-gate 					    nif_list[i].local_addr.s_addr == 0)
12420Sstevel@tonic-gate 						continue;
12430Sstevel@tonic-gate 					(void) strlcpy(lifr.lifr_name,
12440Sstevel@tonic-gate 					    nif_list[i].name,
12450Sstevel@tonic-gate 					    sizeof (lifr.lifr_name));
12460Sstevel@tonic-gate 					if (ip_domux2fd(&udp_fd, &fd) < 0) {
12470Sstevel@tonic-gate 						logwarn(gettext("Removing"
12480Sstevel@tonic-gate 						    " interface %s from the"
12490Sstevel@tonic-gate 						    " configuration list.\n"),
12500Sstevel@tonic-gate 						    nif_list[i].name);
12510Sstevel@tonic-gate 						nif_list[i].name[0] = 0;
12520Sstevel@tonic-gate 						continue;
12530Sstevel@tonic-gate 					}
12540Sstevel@tonic-gate 					if (ioctl(udp_fd, I_PUNLINK,
12550Sstevel@tonic-gate 					    lifr.lifr_ip_muxid) < 0) {
12560Sstevel@tonic-gate 						logwarn(gettext("Removing"
12570Sstevel@tonic-gate 						    " interface %s from the"
12580Sstevel@tonic-gate 						    " configuration list.\n"),
12590Sstevel@tonic-gate 						    nif_list[i].name);
12600Sstevel@tonic-gate 						nif_list[i].name[0] = 0;
12610Sstevel@tonic-gate 						(void) close(udp_fd);
12620Sstevel@tonic-gate 						(void) close(fd);
12630Sstevel@tonic-gate 						continue;
12640Sstevel@tonic-gate 					}
12650Sstevel@tonic-gate 					if (debug) {
12660Sstevel@tonic-gate 						logdebug("Configuring"
12670Sstevel@tonic-gate 						    " %s\n", nif_list[i].name);
12680Sstevel@tonic-gate 					}
12690Sstevel@tonic-gate 					ret = nca_set_nif(fd,
12700Sstevel@tonic-gate 					    nif_list[i].local_addr,
12710Sstevel@tonic-gate 					    nif_list[i].router_ether_addr);
12720Sstevel@tonic-gate 					ip_plink(udp_fd, fd);
12730Sstevel@tonic-gate 					if (ret < 0) {
12740Sstevel@tonic-gate 						/*
12750Sstevel@tonic-gate 						 * This should not be possible
12760Sstevel@tonic-gate 						 * since if NCA does not
12770Sstevel@tonic-gate 						 * support the ioctl, the
12780Sstevel@tonic-gate 						 * active flag should be
12790Sstevel@tonic-gate 						 * cleared already and this
12800Sstevel@tonic-gate 						 * function should not have
12810Sstevel@tonic-gate 						 * been called at all!
12820Sstevel@tonic-gate 						 */
12830Sstevel@tonic-gate 						logwarn("Daemon dies\n");
12840Sstevel@tonic-gate 						exit(1);
12850Sstevel@tonic-gate 					}
12860Sstevel@tonic-gate 					(void) close(udp_fd);
12870Sstevel@tonic-gate 					(void) close(fd);
12880Sstevel@tonic-gate 				}
12890Sstevel@tonic-gate 				break;
12900Sstevel@tonic-gate 			default:
12910Sstevel@tonic-gate 				continue;
12920Sstevel@tonic-gate 			}
12930Sstevel@tonic-gate 		}
12940Sstevel@tonic-gate 	}
12950Sstevel@tonic-gate }
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate /*
12980Sstevel@tonic-gate  * Make us a daemon.
12990Sstevel@tonic-gate  */
13000Sstevel@tonic-gate static void
daemon_init(void)13010Sstevel@tonic-gate daemon_init(void)
13020Sstevel@tonic-gate {
13030Sstevel@tonic-gate 	pid_t pid;
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	if ((pid = fork()) == -1) {
13060Sstevel@tonic-gate 		/* Write directly to terminal, instead of syslog. */
13070Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("ncaconfd: cannot fork: %s\n"),
13080Sstevel@tonic-gate 		    strerror(errno));
13090Sstevel@tonic-gate 		exit(1);
13100Sstevel@tonic-gate 	}
13110Sstevel@tonic-gate 	if (pid != 0)
13120Sstevel@tonic-gate 		exit(0);
13130Sstevel@tonic-gate 	(void) setsid();
13140Sstevel@tonic-gate 	/* Fork again so that we will never get a controlling terminal. */
13150Sstevel@tonic-gate 	if ((pid = fork()) == -1) {
13160Sstevel@tonic-gate 		/* Write directly to terminal, instead of syslog. */
13170Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("ncaconfd: cannot fork: %s\n"),
13180Sstevel@tonic-gate 		    strerror(errno));
13190Sstevel@tonic-gate 		exit(1);
13200Sstevel@tonic-gate 	}
13210Sstevel@tonic-gate 	if (pid != 0)
13220Sstevel@tonic-gate 		exit(0);
13230Sstevel@tonic-gate 	(void) chdir("/");
13240Sstevel@tonic-gate 	(void) umask(0);
13250Sstevel@tonic-gate 	(void) fclose(stdin);
13260Sstevel@tonic-gate 	(void) fclose(stdout);
13270Sstevel@tonic-gate 	(void) fclose(stderr);
13280Sstevel@tonic-gate }
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate int
main(int argc,char ** argv)13310Sstevel@tonic-gate main(int argc, char **argv)
13320Sstevel@tonic-gate {
13330Sstevel@tonic-gate 	int i, j;
13340Sstevel@tonic-gate 	int c;
13350Sstevel@tonic-gate 	boolean_t active = B_FALSE;
13360Sstevel@tonic-gate 	boolean_t as_daemon = B_TRUE;
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate 	if (argc == 1) {
13390Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Usage: %s [-al]"
13400Sstevel@tonic-gate 		    " [interface1 interface2 ...]\n"), argv[0]);
13410Sstevel@tonic-gate 		return (1);
13420Sstevel@tonic-gate 	}
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
13450Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
13460Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
13470Sstevel@tonic-gate #endif
13480Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "adcl")) != EOF) {
13510Sstevel@tonic-gate 		switch (c) {
13520Sstevel@tonic-gate 		case 'a':
13530Sstevel@tonic-gate 			active = B_TRUE;
13540Sstevel@tonic-gate 			break;
13550Sstevel@tonic-gate 		case 'd':
13560Sstevel@tonic-gate 			debug = B_TRUE;
13570Sstevel@tonic-gate 			break;
13580Sstevel@tonic-gate 		case 'c':
13590Sstevel@tonic-gate 			/* Don't run as daemon. */
13600Sstevel@tonic-gate 			as_daemon = B_FALSE;
13610Sstevel@tonic-gate 			break;
13620Sstevel@tonic-gate 		case 'l':
13630Sstevel@tonic-gate 			logging = B_TRUE;
13640Sstevel@tonic-gate 			break;
13650Sstevel@tonic-gate 		default:
13660Sstevel@tonic-gate 			/* -d and -c are "undocumented" options. */
13670Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Usage: %s [-al]"
13680Sstevel@tonic-gate 			    " [interface1 interface2 ...]\n"), argv[0]);
13690Sstevel@tonic-gate 			return (1);
13700Sstevel@tonic-gate 		}
13710Sstevel@tonic-gate 	}
13720Sstevel@tonic-gate 	num_nif = argc - optind;
13730Sstevel@tonic-gate 	if (num_nif == 0) {
13740Sstevel@tonic-gate 		/* No network interface to proces... */
13750Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Usage: %s [-al]"
13760Sstevel@tonic-gate 		    " [interface1 interface2 ...]\n"), argv[0]);
13770Sstevel@tonic-gate 		return (0);
13780Sstevel@tonic-gate 	}
13790Sstevel@tonic-gate 	nif_list = calloc(num_nif, sizeof (nif_t));
13800Sstevel@tonic-gate 	if (nif_list == NULL) {
13810Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("ncaconfd: Cannot malloc: %s\n"),
13820Sstevel@tonic-gate 		    strerror(errno));
13830Sstevel@tonic-gate 		return (1);
13840Sstevel@tonic-gate 	}
13850Sstevel@tonic-gate 	for (i = 0, j = optind; i < num_nif; i++, j++) {
13860Sstevel@tonic-gate 		(void) strlcpy(nif_list[i].name, argv[j], LIFNAMSIZ+1);
13870Sstevel@tonic-gate 	}
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 	/* Get IP address info for all the intefaces. */
13900Sstevel@tonic-gate 	if (get_if_ip_addr() < 0) {
13910Sstevel@tonic-gate 		if (debug) {
13920Sstevel@tonic-gate 			(void) fprintf(stderr, "ncaconfd: Cannot get IP"
13930Sstevel@tonic-gate 			    " addresses for interfaces.\n");
13940Sstevel@tonic-gate 		}
13950Sstevel@tonic-gate 		return (1);
13960Sstevel@tonic-gate 	}
13970Sstevel@tonic-gate 	if (logging)
13980Sstevel@tonic-gate 		openlog("ncaconfd", LOG_PID, LOG_DAEMON);
13990Sstevel@tonic-gate 	/* No need to run as daemon if NCA is not making active connections. */
14000Sstevel@tonic-gate 	if (active && as_daemon)
14010Sstevel@tonic-gate 		daemon_init();
14020Sstevel@tonic-gate 	if (active) {
14030Sstevel@tonic-gate 		boolean_t changed;
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 		/* NCA does not support IPv6... */
14060Sstevel@tonic-gate 		if ((rt_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
14070Sstevel@tonic-gate 			logperror("Cannot open routing socket");
14080Sstevel@tonic-gate 			return (1);
14090Sstevel@tonic-gate 		}
14100Sstevel@tonic-gate 		/*
14110Sstevel@tonic-gate 		 * At boot up time, the default router may not have been
14120Sstevel@tonic-gate 		 * found.  So ignore the error and check later.
14130Sstevel@tonic-gate 		 */
14140Sstevel@tonic-gate 		if (get_if_info(&changed) < 0) {
14150Sstevel@tonic-gate 			if (debug) {
14160Sstevel@tonic-gate 				(void) logwarn("Cannot get"
14170Sstevel@tonic-gate 				    " information from network interface.\n");
14180Sstevel@tonic-gate 			}
14190Sstevel@tonic-gate 		}
14200Sstevel@tonic-gate 	}
14210Sstevel@tonic-gate 	/* Do the set up as daemon (if we are) to save time at boot up... */
14220Sstevel@tonic-gate 	nca_setup(&active);
14230Sstevel@tonic-gate 	if (active)
14240Sstevel@tonic-gate 		daemon_work();
14250Sstevel@tonic-gate 	return (0);
14260Sstevel@tonic-gate }
1427