Home | History | Annotate | Download | only in ifconfig
      1 /*
      2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 /*
      6  * Copyright (c) 1983 Regents of the University of California.
      7  * All rights reserved.  The Berkeley software License Agreement
      8  * specifies the terms and conditions for redistribution.
      9  */
     10 
     11 #include "defs.h"
     12 #include "strings.h"
     13 #include "ifconfig.h"
     14 #include <compat.h>
     15 #include <libdlpi.h>
     16 #include <libdllink.h>
     17 #include <libdliptun.h>
     18 #include <libdllink.h>
     19 #include <inet/ip.h>
     20 #include <inet/ipsec_impl.h>
     21 
     22 #define	LOOPBACK_IF	"lo0"
     23 #define	NONE_STR	"none"
     24 #define	ARP_MOD_NAME	"arp"
     25 #define	IPMPSTUB	(void *)-1
     26 
     27 typedef struct if_flags {
     28 	uint64_t iff_value;
     29 	char	*iff_name;
     30 } if_flags_t;
     31 
     32 static if_flags_t	if_flags_tbl[] = {
     33 	{ IFF_UP,		"UP" },
     34 	{ IFF_BROADCAST,	"BROADCAST" },
     35 	{ IFF_DEBUG,		"DEBUG" },
     36 	{ IFF_LOOPBACK,		"LOOPBACK" },
     37 	{ IFF_POINTOPOINT,	"POINTOPOINT" },
     38 	{ IFF_NOTRAILERS,	"NOTRAILERS" },
     39 	{ IFF_RUNNING,		"RUNNING" },
     40 	{ IFF_NOARP,		"NOARP" },
     41 	{ IFF_PROMISC,		"PROMISC" },
     42 	{ IFF_ALLMULTI,		"ALLMULTI" },
     43 	{ IFF_INTELLIGENT,	"INTELLIGENT" },
     44 	{ IFF_MULTICAST,	"MULTICAST" },
     45 	{ IFF_MULTI_BCAST,	"MULTI_BCAST" },
     46 	{ IFF_UNNUMBERED,	"UNNUMBERED" },
     47 	{ IFF_DHCPRUNNING,	"DHCP" },
     48 	{ IFF_PRIVATE,		"PRIVATE" },
     49 	{ IFF_NOXMIT,		"NOXMIT" },
     50 	{ IFF_NOLOCAL,		"NOLOCAL" },
     51 	{ IFF_DEPRECATED,	"DEPRECATED" },
     52 	{ IFF_ADDRCONF,		"ADDRCONF" },
     53 	{ IFF_ROUTER,		"ROUTER" },
     54 	{ IFF_NONUD,		"NONUD" },
     55 	{ IFF_ANYCAST,		"ANYCAST" },
     56 	{ IFF_NORTEXCH,		"NORTEXCH" },
     57 	{ IFF_IPV4,		"IPv4" },
     58 	{ IFF_IPV6,		"IPv6" },
     59 	{ IFF_NOFAILOVER,	"NOFAILOVER" },
     60 	{ IFF_FAILED,		"FAILED" },
     61 	{ IFF_STANDBY,		"STANDBY" },
     62 	{ IFF_INACTIVE,		"INACTIVE" },
     63 	{ IFF_OFFLINE,		"OFFLINE" },
     64 	{ IFF_XRESOLV,		"XRESOLV" },
     65 	{ IFF_COS_ENABLED,	"CoS" },
     66 	{ IFF_PREFERRED,	"PREFERRED" },
     67 	{ IFF_TEMPORARY,	"TEMPORARY" },
     68 	{ IFF_FIXEDMTU,		"FIXEDMTU" },
     69 	{ IFF_VIRTUAL,		"VIRTUAL" },
     70 	{ IFF_DUPLICATE,	"DUPLICATE" },
     71 	{ IFF_IPMP,		"IPMP"},
     72 	{ IFF_VRRP,		"VRRP"},
     73 	{ IFF_NOACCEPT,		"NOACCEPT"}
     74 };
     75 
     76 typedef struct {
     77 	const char		*ia_app;
     78 	uint64_t		ia_flag;
     79 	uint_t			ia_tries;
     80 } if_appflags_t;
     81 
     82 static const if_appflags_t if_appflags_tbl[] = {
     83 	{ "dhcpagent(1M)",	IFF_DHCPRUNNING,	1 },
     84 	{ "in.ndpd(1M)",	IFF_ADDRCONF,		3 },
     85 	{  NULL,		0,			0 }
     86 };
     87 
     88 static dladm_handle_t	dlh;
     89 boolean_t		dlh_opened;
     90 static struct		lifreq lifr;
     91 /* current interface name a particular function is accessing */
     92 static char		name[LIFNAMSIZ];
     93 /* foreach interface saved name */
     94 static char		origname[LIFNAMSIZ];
     95 static int		setaddr;
     96 static boolean_t	ipsec_policy_set;
     97 static boolean_t	ipsec_auth_covered;
     98 
     99 /*
    100  * Make sure the algorithm variables hold more than the sizeof an algorithm
    101  * in PF_KEY.  (For now, more than a uint8_t.)  The NO_***_?ALG indicates that
    102  * there was no algorithm requested, and in the ipsec_req that service should
    103  * be disabled.  (E.g. if ah_aalg remains NO_AH_AALG, then AH will be
    104  * disabled on that tunnel.)
    105  */
    106 #define	NO_AH_AALG 256
    107 #define	NO_ESP_AALG 256
    108 #define	NO_ESP_EALG 256
    109 
    110 int	s, s4, s6;
    111 int	af = AF_INET;	/* default address family */
    112 int	debug = 0;
    113 int	all = 0;	/* setifdhcp() needs to know this */
    114 int	verbose = 0;
    115 int	v4compat = 0;	/* Compatible printing format */
    116 
    117 /*
    118  * Function prototypes for command functions.
    119  */
    120 static int	addif(char *arg, int64_t param);
    121 static int	inetipmp(char *arg, int64_t param);
    122 static int	inetplumb(char *arg, int64_t param);
    123 static int	inetunplumb(char *arg, int64_t param);
    124 static int	removeif(char *arg, int64_t param);
    125 static int	setdebugflag(char *arg, int64_t param);
    126 static int	setifaddr(char *arg, int64_t param);
    127 static int	setifbroadaddr(char *arg, int64_t param);
    128 static int	setifdstaddr(char *arg, int64_t param);
    129 static int	setifether(char *arg, int64_t param);
    130 static int	setifflags(char *arg, int64_t param);
    131 static int	setifindex(char *arg, int64_t param);
    132 static int	setifmetric(char *arg, int64_t param);
    133 static int	setifmtu(char *arg, int64_t param);
    134 static int	setifnetmask(char *arg, int64_t param);
    135 static int	setifprefixlen(char *arg, int64_t param);
    136 static int	setifrevarp(char *arg, int64_t param);
    137 static int	setifsubnet(char *arg, int64_t param);
    138 static int	setiftdst(char *arg, int64_t param);
    139 static int	setiftoken(char *arg, int64_t param);
    140 static int	setiftsrc(char *arg, int64_t param);
    141 static int	setverboseflag(char *arg, int64_t param);
    142 static int	set_tun_ah_alg(char *arg, int64_t param);
    143 static int	set_tun_esp_auth_alg(char *arg, int64_t param);
    144 static int	set_tun_esp_encr_alg(char *arg, int64_t param);
    145 static int	modlist(char *arg, int64_t param);
    146 static int	modinsert(char *arg, int64_t param);
    147 static int	modremove(char *arg, int64_t param);
    148 static int	setifgroupname(char *arg, int64_t param);
    149 static int	configinfo(char *arg, int64_t param);
    150 static void	print_config_flags(int af, uint64_t flags);
    151 static void	print_flags(uint64_t flags);
    152 static void	print_ifether(char *ifname);
    153 static int	set_tun_encap_limit(char *arg, int64_t param);
    154 static int	clr_tun_encap_limit(char *arg, int64_t param);
    155 static int	set_tun_hop_limit(char *arg, int64_t param);
    156 static int	setzone(char *arg, int64_t param);
    157 static int	setallzones(char *arg, int64_t param);
    158 static int	setifsrc(char *arg, int64_t param);
    159 static int	lifnum(const char *ifname);
    160 
    161 /*
    162  * Address family specific function prototypes.
    163  */
    164 static void	in_getaddr(char *s, struct sockaddr *saddr, int *plenp);
    165 static void	in_status(int force, uint64_t flags);
    166 static void	in_configinfo(int force, uint64_t flags);
    167 static void	in6_getaddr(char *s, struct sockaddr *saddr, int *plenp);
    168 static void	in6_status(int force, uint64_t flags);
    169 static void	in6_configinfo(int force, uint64_t flags);
    170 
    171 /*
    172  * Misc support functions
    173  */
    174 static boolean_t	ni_entry(const char *, void *);
    175 static void	foreachinterface(void (*func)(), int argc, char *argv[],
    176 		    int af, int64_t onflags, int64_t offflags,
    177 		    int64_t lifc_flags);
    178 static void	ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp);
    179 static boolean_t	in_getmask(struct sockaddr_in *saddr,
    180 			    boolean_t addr_set);
    181 static int	in_getprefixlen(char *addr, boolean_t slash, int plen);
    182 static boolean_t	in_prefixlentomask(int prefixlen, int maxlen,
    183 			    uchar_t *mask);
    184 static void	status(void);
    185 static void	ifstatus(const char *);
    186 static void	tun_status(datalink_id_t);
    187 static void	usage(void);
    188 static int	strioctl(int s, int cmd, void *buf, int buflen);
    189 static int	setifdhcp(const char *caller, const char *ifname,
    190 		    int argc, char *argv[]);
    191 static int	ip_domux2fd(int *, int *, int *, int *, int *);
    192 static int	ip_plink(int, int, int, int, int);
    193 static int	modop(char *arg, char op);
    194 static int	find_all_interfaces(struct lifconf *lifcp, char **buf,
    195 		    int64_t lifc_flags);
    196 static int	create_ipmp(const char *grname, int af, const char *ifname,
    197 		    boolean_t implicit);
    198 static int	create_ipmp_peer(int af, const char *ifname);
    199 static void	start_ipmp_daemon(void);
    200 static boolean_t ifaddr_up(ifaddrlistx_t *ifaddrp);
    201 static boolean_t ifaddr_down(ifaddrlistx_t *ifaddrp);
    202 static dladm_status_t	ifconfig_dladm_open(const char *, datalink_class_t,
    203 		    datalink_id_t *);
    204 static void	dladmerr_exit(dladm_status_t status, const char *str);
    205 
    206 #define	max(a, b)	((a) < (b) ? (b) : (a))
    207 
    208 /*
    209  * DHCP_EXIT_IF_FAILURE indicates that the operation failed, but if there
    210  * are more interfaces to act on (i.e., ifconfig was invoked with -a), keep
    211  * on going rather than exit with an error.
    212  */
    213 
    214 #define	DHCP_EXIT_IF_FAILURE	-1
    215 
    216 #define	NEXTARG		0xffffff	/* command takes an argument */
    217 #define	OPTARG		0xfffffe 	/* command takes an optional argument */
    218 #define	AF_ANY		(-1)
    219 
    220 /* Refer to the comments in ifconfig() on the netmask "hack" */
    221 #define	NETMASK_CMD	"netmask"
    222 struct sockaddr_storage	g_netmask;
    223 enum { G_NETMASK_NIL, G_NETMASK_PENDING, G_NETMASK_SET }
    224     g_netmask_set = G_NETMASK_NIL;
    225 
    226 struct	cmd {
    227 	char		*c_name;
    228 	int64_t		c_parameter;	/* NEXTARG means next argv */
    229 	int		(*c_func)(char *, int64_t);
    230 	int		c_abortonfail;	/* don't continue parsing args */
    231 					/* for the current interface */
    232 	int	c_af;			/* address family restrictions */
    233 } cmds[] = {
    234 	{ "up",		IFF_UP,		setifflags,	0,	AF_ANY },
    235 	{ "down",	-IFF_UP,	setifflags,	0,	AF_ANY },
    236 	{ "trailers",	-IFF_NOTRAILERS, setifflags,	0,	AF_ANY },
    237 	{ "-trailers",	IFF_NOTRAILERS,	setifflags,	0,	AF_ANY },
    238 	{ "arp",	-IFF_NOARP,	setifflags,	0,	AF_INET },
    239 	{ "-arp",	IFF_NOARP,	setifflags,	0,	AF_INET },
    240 	{ "router",	IFF_ROUTER,	setifflags,	0,	AF_ANY },
    241 	{ "-router",	-IFF_ROUTER,	setifflags,	0,	AF_ANY },
    242 	{ "private",	IFF_PRIVATE,	setifflags,	0,	AF_ANY },
    243 	{ "-private",	-IFF_PRIVATE,	setifflags,	0,	AF_ANY },
    244 	{ "xmit",	-IFF_NOXMIT,	setifflags,	0,	AF_ANY },
    245 	{ "-xmit",	IFF_NOXMIT,	setifflags,	0,	AF_ANY },
    246 	{ "-nud",	IFF_NONUD,	setifflags,	0,	AF_INET6 },
    247 	{ "nud",	-IFF_NONUD,	setifflags,	0,	AF_INET6 },
    248 	{ "anycast",	IFF_ANYCAST,	setifflags,	0,	AF_ANY },
    249 	{ "-anycast",	-IFF_ANYCAST,	setifflags,	0,	AF_ANY },
    250 	{ "local",	-IFF_NOLOCAL,	setifflags,	0,	AF_ANY },
    251 	{ "-local",	IFF_NOLOCAL,	setifflags,	0,	AF_ANY },
    252 	{ "deprecated",	IFF_DEPRECATED,	setifflags,	0,	AF_ANY },
    253 	{ "-deprecated", -IFF_DEPRECATED, setifflags,	0,	AF_ANY },
    254 	{ "preferred",	IFF_PREFERRED,	setifflags,	0,	AF_INET6 },
    255 	{ "-preferred",	-IFF_PREFERRED,	setifflags,	0,	AF_INET6 },
    256 	{ "debug",	0,		setdebugflag,	0,	AF_ANY },
    257 	{ "verbose",	0,		setverboseflag,	0,	AF_ANY },
    258 	{ NETMASK_CMD,	NEXTARG,	setifnetmask,	0,	AF_INET },
    259 	{ "metric",	NEXTARG,	setifmetric,	0,	AF_ANY },
    260 	{ "mtu",	NEXTARG,	setifmtu,	0,	AF_ANY },
    261 	{ "index",	NEXTARG,	setifindex,	0,	AF_ANY },
    262 	{ "broadcast",	NEXTARG,	setifbroadaddr,	0,	AF_INET },
    263 	{ "auto-revarp", 0,		setifrevarp,	1,	AF_INET },
    264 	{ "ipmp",	0,		inetipmp,	1,	AF_ANY },
    265 	{ "plumb",	0,		inetplumb,	1,	AF_ANY },
    266 	{ "unplumb",	0,		inetunplumb,	0,	AF_ANY },
    267 	{ "subnet",	NEXTARG,	setifsubnet,	0,	AF_ANY },
    268 	{ "token",	NEXTARG,	setiftoken,	0,	AF_INET6 },
    269 	{ "tsrc",	NEXTARG,	setiftsrc,	0,	AF_ANY },
    270 	{ "tdst",	NEXTARG,	setiftdst,	0,	AF_ANY },
    271 	{ "encr_auth_algs", NEXTARG,	set_tun_esp_auth_alg, 0, AF_ANY },
    272 	{ "encr_algs",	NEXTARG,	set_tun_esp_encr_alg, 0, AF_ANY },
    273 	{ "auth_algs",	NEXTARG,	set_tun_ah_alg,	0,	AF_ANY },
    274 	{ "addif",	NEXTARG,	addif,		1,	AF_ANY },
    275 	{ "removeif",	NEXTARG,	removeif,	1,	AF_ANY },
    276 	{ "modlist",	0,		modlist,	1,	AF_ANY },
    277 	{ "modinsert",	NEXTARG,	modinsert,	1,	AF_ANY },
    278 	{ "modremove",	NEXTARG,	modremove,	1,	AF_ANY },
    279 	{ "failover",	-IFF_NOFAILOVER, setifflags,	1,	AF_ANY },
    280 	{ "-failover",	IFF_NOFAILOVER, setifflags,	1,	AF_ANY },
    281 	{ "standby",	IFF_STANDBY,	setifflags,	1,	AF_ANY },
    282 	{ "-standby",	-IFF_STANDBY,	setifflags,	1,	AF_ANY },
    283 	{ "failed",	IFF_FAILED,	setifflags,	1,	AF_ANY },
    284 	{ "-failed",	-IFF_FAILED,	setifflags,	1,	AF_ANY },
    285 	{ "group",	NEXTARG,	setifgroupname,	1,	AF_ANY },
    286 	{ "configinfo",	0,		configinfo,	1,	AF_ANY },
    287 	{ "encaplimit",	NEXTARG,	set_tun_encap_limit,	0, AF_ANY },
    288 	{ "-encaplimit", 0,		clr_tun_encap_limit,	0, AF_ANY },
    289 	{ "thoplimit",	NEXTARG,	set_tun_hop_limit,	0, AF_ANY },
    290 	{ "set",	NEXTARG,	setifaddr,	0,	AF_ANY },
    291 	{ "destination", NEXTARG,	setifdstaddr,	0,	AF_ANY },
    292 	{ "zone",	NEXTARG,	setzone,	0,	AF_ANY },
    293 	{ "-zone",	0,		setzone,	0,	AF_ANY },
    294 	{ "all-zones",	0,		setallzones,	0,	AF_ANY },
    295 	{ "ether",	OPTARG,		setifether,	0,	AF_ANY },
    296 	{ "usesrc",	NEXTARG,	setifsrc,	0,	AF_ANY },
    297 
    298 	/*
    299 	 * NOTE: any additions to this table must also be applied to ifparse
    300 	 *	(usr/src/cmd/cmd-inet/sbin/ifparse/ifparse.c)
    301 	 */
    302 
    303 	{ 0,		0,		setifaddr,	0,	AF_ANY },
    304 	{ 0,		0,		setifdstaddr,	0,	AF_ANY },
    305 	{ 0,		0,		0,		0,	0 },
    306 };
    307 
    308 
    309 typedef struct if_config_cmd {
    310 	uint64_t	iff_flag;
    311 	int		iff_af;
    312 	char		*iff_name;
    313 } if_config_cmd_t;
    314 
    315 /*
    316  * NOTE: print_config_flags() processes this table in order, so we put "up"
    317  * last so that we can be sure "-failover" will take effect first.  Otherwise,
    318  * IPMP test addresses will erroneously migrate to the IPMP interface.
    319  */
    320 static if_config_cmd_t	if_config_cmd_tbl[] = {
    321 	{ IFF_NOTRAILERS,	AF_UNSPEC,	"-trailers"	},
    322 	{ IFF_PRIVATE,		AF_UNSPEC,	"private"	},
    323 	{ IFF_NOXMIT,		AF_UNSPEC,	"-xmit"		},
    324 	{ IFF_ANYCAST,		AF_INET6,	"anycast"	},
    325 	{ IFF_NOLOCAL,		AF_UNSPEC,	"-local"	},
    326 	{ IFF_DEPRECATED,	AF_UNSPEC,	"deprecated"	},
    327 	{ IFF_NOFAILOVER,	AF_UNSPEC,	"-failover"	},
    328 	{ IFF_STANDBY,		AF_UNSPEC,	"standby"	},
    329 	{ IFF_FAILED,		AF_UNSPEC,	"failed"	},
    330 	{ IFF_PREFERRED,	AF_UNSPEC,	"preferred"	},
    331 	{ IFF_NONUD,		AF_INET6,	"-nud"		},
    332 	{ IFF_NOARP,		AF_INET,	"-arp"		},
    333 	{ IFF_UP,		AF_UNSPEC, 	"up" 		},
    334 	{ 0,			0,		NULL		},
    335 };
    336 
    337 typedef struct ni {
    338 	char		ni_name[LIFNAMSIZ];
    339 	struct ni	*ni_next;
    340 } ni_t;
    341 
    342 static ni_t	*ni_list = NULL;
    343 static int	num_ni = 0;
    344 
    345 /* End defines and structure definitions for ifconfig -a plumb */
    346 
    347 /* Known address families */
    348 struct afswtch {
    349 	char *af_name;
    350 	short af_af;
    351 	void (*af_status)();
    352 	void (*af_getaddr)();
    353 	void (*af_configinfo)();
    354 } afs[] = {
    355 	{ "inet", AF_INET, in_status, in_getaddr, in_configinfo },
    356 	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_configinfo },
    357 	{ 0, 0,	0, 0, 0 }
    358 };
    359 
    360 #define	SOCKET_AF(af)	(((af) == AF_UNSPEC) ? AF_INET : (af))
    361 
    362 struct afswtch *afp;	/* the address family being set or asked about */
    363 
    364 int
    365 main(int argc, char *argv[])
    366 {
    367 	int64_t		lifc_flags;
    368 	char		*default_ip_str;
    369 
    370 	lifc_flags = LIFC_NOXMIT|LIFC_TEMPORARY|LIFC_ALLZONES|LIFC_UNDER_IPMP;
    371 
    372 	if (argc < 2) {
    373 		usage();
    374 		exit(1);
    375 	}
    376 	argc--, argv++;
    377 	if (strlen(*argv) > sizeof (name) - 1) {
    378 		(void) fprintf(stderr, "%s: interface name too long\n", *argv);
    379 		exit(1);
    380 	}
    381 	(void) strncpy(name, *argv, sizeof (name));
    382 	name[sizeof (name) - 1] = '\0';
    383 	(void) strncpy(origname, name, sizeof (origname));	/* For addif */
    384 	default_ip_str = NULL;
    385 	v4compat = get_compat_flag(&default_ip_str);
    386 	if (v4compat == DEFAULT_PROT_BAD_VALUE) {
    387 		(void) fprintf(stderr,
    388 		    "ifconfig: %s: Bad value for %s in %s\n", default_ip_str,
    389 		    DEFAULT_IP, INET_DEFAULT_FILE);
    390 		free(default_ip_str);
    391 		exit(2);
    392 	}
    393 	free(default_ip_str);
    394 	argc--, argv++;
    395 	if (argc > 0) {
    396 		struct afswtch *myafp;
    397 
    398 		for (myafp = afp = afs; myafp->af_name; myafp++) {
    399 			if (strcmp(myafp->af_name, *argv) == 0) {
    400 				afp = myafp; argc--; argv++;
    401 				break;
    402 			}
    403 		}
    404 		af = lifr.lifr_addr.ss_family = afp->af_af;
    405 		if (af == AF_INET6) {
    406 			v4compat = 0;
    407 		}
    408 	}
    409 
    410 	s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
    411 	s4 = socket(AF_INET, SOCK_DGRAM, 0);
    412 	s6 = socket(AF_INET6, SOCK_DGRAM, 0);
    413 	if (s == -1 || s4 == -1 || s6 == -1)
    414 		Perror0_exit("socket");
    415 
    416 	/*
    417 	 * Special interface names is any combination of these flags.
    418 	 * Note that due to the ifconfig syntax they have to be combined
    419 	 * as a single '-' option.
    420 	 *	-a	All interfaces
    421 	 *	-u	"up" interfaces
    422 	 *	-d	"down" interfaces
    423 	 *	-D	Interfaces not controlled by DHCP
    424 	 *	-4	IPv4 interfaces
    425 	 *	-6	IPv6 interfaces
    426 	 *	-X	Turn on debug (not documented)
    427 	 *	-v	Turn on verbose
    428 	 *	-Z	Only interfaces in caller's zone
    429 	 */
    430 
    431 	if (name[0] == '-') {
    432 		/* One or more options */
    433 		int64_t onflags = 0;
    434 		int64_t offflags = 0;
    435 		int c;
    436 		char *av[2] = { "ifconfig", name };
    437 
    438 		while ((c = getopt(2, av, "audDXZ46v")) != -1) {
    439 			switch ((char)c) {
    440 			case 'a':
    441 				all = 1;
    442 				break;
    443 			case 'u':
    444 				onflags |= IFF_UP;
    445 				break;
    446 			case 'd':
    447 				offflags |= IFF_UP;
    448 				break;
    449 			case 'D':
    450 				offflags |= IFF_DHCPRUNNING;
    451 				break;
    452 			case 'X':
    453 				debug += 3;
    454 				break;
    455 			case 'Z':
    456 				lifc_flags &= ~LIFC_ALLZONES;
    457 				break;
    458 			case '4':
    459 				/*
    460 				 * -4 is not a compatable flag, therefore
    461 				 * we assume they want v4compat turned off
    462 				 */
    463 				v4compat = 0;
    464 				onflags |= IFF_IPV4;
    465 				break;
    466 			case '6':
    467 				/*
    468 				 * If they want IPv6, well then we'll assume
    469 				 * they don't want IPv4 compat
    470 				 */
    471 				v4compat = 0;
    472 				onflags |= IFF_IPV6;
    473 				break;
    474 			case 'v':
    475 				verbose = 1;
    476 				break;
    477 			case '?':
    478 				usage();
    479 				exit(1);
    480 			}
    481 		}
    482 		if (!all) {
    483 			(void) fprintf(stderr,
    484 			    "ifconfig: %s: no such interface\n", name);
    485 			exit(1);
    486 		}
    487 		foreachinterface(ifconfig, argc, argv, af, onflags, offflags,
    488 		    lifc_flags);
    489 	} else {
    490 		ifconfig(argc, argv, af, (struct lifreq *)NULL);
    491 	}
    492 	return (0);
    493 }
    494 
    495 /*
    496  * For each interface, call (*func)(argc, argv, af, lifrp).
    497  * Only call function if onflags and offflags are set or clear, respectively,
    498  * in the interfaces flags field.
    499  */
    500 static void
    501 foreachinterface(void (*func)(), int argc, char *argv[], int af,
    502     int64_t onflags, int64_t offflags, int64_t lifc_flags)
    503 {
    504 	int n;
    505 	char *buf;
    506 	struct lifnum lifn;
    507 	struct lifconf lifc;
    508 	struct lifreq *lifrp;
    509 	struct lifreq lifrl;	/* Local lifreq struct */
    510 	int numifs;
    511 	unsigned bufsize;
    512 	int plumball = 0;
    513 	int save_af = af;
    514 
    515 	buf = NULL;
    516 	/*
    517 	 * Special case:
    518 	 * ifconfig -a plumb should find all network interfaces in the current
    519 	 * zone.
    520 	 */
    521 	if (argc > 0 && (strcmp(*argv, "plumb") == 0)) {
    522 		if (find_all_interfaces(&lifc, &buf, lifc_flags) != 0 ||
    523 		    lifc.lifc_len == 0)
    524 			return;
    525 		plumball = 1;
    526 	} else {
    527 		lifn.lifn_family = AF_UNSPEC;
    528 		lifn.lifn_flags = lifc_flags;
    529 		if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
    530 			Perror0_exit("Could not determine number"
    531 			    " of interfaces");
    532 		}
    533 		numifs = lifn.lifn_count;
    534 		if (debug)
    535 			(void) printf("ifconfig: %d interfaces\n",  numifs);
    536 
    537 		bufsize = numifs * sizeof (struct lifreq);
    538 		if ((buf = malloc(bufsize)) == NULL) {
    539 			Perror0("out of memory\n");
    540 			(void) close(s);
    541 			return;
    542 		}
    543 
    544 		lifc.lifc_family = AF_UNSPEC;
    545 		lifc.lifc_flags = lifc_flags;
    546 		lifc.lifc_len = bufsize;
    547 		lifc.lifc_buf = buf;
    548 
    549 		if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
    550 			Perror0("SIOCGLIFCONF");
    551 			(void) close(s);
    552 			free(buf);
    553 			return;
    554 		}
    555 	}
    556 
    557 	lifrp = lifc.lifc_req;
    558 	for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
    559 
    560 		if (!plumball) {
    561 			/*
    562 			 * We must close and recreate the socket each time
    563 			 * since we don't know what type of socket it is now
    564 			 * (each status function may change it).
    565 			 */
    566 
    567 			(void) close(s);
    568 
    569 			af = lifrp->lifr_addr.ss_family;
    570 			s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
    571 			if (s == -1) {
    572 				/*
    573 				 * Perror0() assumes the name to be in the
    574 				 * globally defined lifreq structure.
    575 				 */
    576 				(void) strncpy(lifr.lifr_name,
    577 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
    578 				Perror0_exit("socket");
    579 			}
    580 		}
    581 
    582 		/*
    583 		 * Only service interfaces that match the on and off
    584 		 * flags masks.
    585 		 */
    586 		if (onflags || offflags) {
    587 			(void) memset(&lifrl, 0, sizeof (lifrl));
    588 			(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
    589 			    sizeof (lifrl.lifr_name));
    590 			if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) {
    591 				/*
    592 				 * Perror0() assumes the name to be in the
    593 				 * globally defined lifreq structure.
    594 				 */
    595 				(void) strncpy(lifr.lifr_name,
    596 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
    597 				Perror0_exit("foreachinterface: SIOCGLIFFLAGS");
    598 			}
    599 			if ((lifrl.lifr_flags & onflags) != onflags)
    600 				continue;
    601 			if ((~lifrl.lifr_flags & offflags) != offflags)
    602 				continue;
    603 		}
    604 
    605 		if (!plumball) {
    606 			(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
    607 			    sizeof (lifrl.lifr_name));
    608 			if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifrl) < 0) {
    609 				/*
    610 				 * Perror0() assumes the name to be in the
    611 				 * globally defined lifreq structure.
    612 				 */
    613 				(void) strncpy(lifr.lifr_name,
    614 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
    615 				Perror0("foreachinterface: SIOCGLIFADDR");
    616 				continue;
    617 			}
    618 			if (lifrl.lifr_addr.ss_family != af) {
    619 				/* Switch address family */
    620 				af = lifrl.lifr_addr.ss_family;
    621 				(void) close(s);
    622 
    623 				s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
    624 				if (s == -1) {
    625 					/*
    626 					 * Perror0() assumes the name to be in
    627 					 * the globally defined lifreq
    628 					 * structure.
    629 					 */
    630 					(void) strncpy(lifr.lifr_name,
    631 					    lifrp->lifr_name,
    632 					    sizeof (lifr.lifr_name));
    633 					Perror0_exit("socket");
    634 				}
    635 			}
    636 		}
    637 
    638 		/*
    639 		 * Reset global state
    640 		 * setaddr: Used by parser to tear apart source and dest
    641 		 * name and origname contain the name of the 'current'
    642 		 * interface.
    643 		 */
    644 		setaddr = 0;
    645 		(void) strncpy(name, lifrp->lifr_name, sizeof (name));
    646 		(void) strncpy(origname, name, sizeof (origname));
    647 
    648 		(*func)(argc, argv, save_af, lifrp);
    649 		/* the func could have overwritten origname, so restore */
    650 		(void) strncpy(name, origname, sizeof (name));
    651 	}
    652 	if (buf != NULL)
    653 		free(buf);
    654 }
    655 
    656 /*
    657  * for the specified interface call (*func)(argc, argv, af, lifrp).
    658  */
    659 
    660 static void
    661 ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp)
    662 {
    663 	static boolean_t scan_netmask = _B_FALSE;
    664 	int ret;
    665 
    666 	if (argc == 0) {
    667 		status();
    668 		return;
    669 	}
    670 
    671 	if (strcmp(*argv, "auto-dhcp") == 0 || strcmp(*argv, "dhcp") == 0) {
    672 		/*
    673 		 * Some errors are ignored in the case where more than one
    674 		 * interface is being operated on.
    675 		 */
    676 		ret = setifdhcp("ifconfig", name, argc, argv);
    677 		if (ret == DHCP_EXIT_IF_FAILURE) {
    678 			if (!all)
    679 				exit(DHCP_EXIT_FAILURE);
    680 		} else if (ret != DHCP_EXIT_SUCCESS) {
    681 			exit(ret);
    682 		}
    683 		return;
    684 	}
    685 
    686 	/*
    687 	 * The following is a "hack" to get around the existing interface
    688 	 * setting mechanism.  Currently, each interface attribute,
    689 	 * such as address, netmask, broadcast, ... is set separately.  But
    690 	 * sometimes two or more attributes must be set together.  For
    691 	 * example, setting an address without a netmask does not make sense.
    692 	 * Yet they can be set separately for IPv4 address using the current
    693 	 * ifconfig(1M) syntax.  The kernel then "infers" the correct netmask
    694 	 * using the deprecated "IP address classes."  This is simply not
    695 	 * correct.
    696 	 *
    697 	 * The "hack" below is to go thru the whole command list looking for
    698 	 * the netmask command first.  Then use this netmask to set the
    699 	 * address.  This does not provide an extensible way to accommodate
    700 	 * future need for setting more than one attributes together.
    701 	 *
    702 	 * Note that if the "netmask" command argument is a "+", we need
    703 	 * to save this info and do the query after we know the address to
    704 	 * be set.  The reason is that if "addif" is used, the working
    705 	 * interface name will be changed later when the logical interface
    706 	 * is created.  In in_getmask(), if an address is not provided,
    707 	 * it will use the working interface's address to do the query.
    708 	 * It will be wrong now as we don't know the logical interface's name.
    709 	 *
    710 	 * ifconfig(1M) is too overloaded and the code is so convoluted
    711 	 * that it is "safer" not to re-architect the code to fix the above
    712 	 * issue, hence this "hack."  We may be better off to have a new
    713 	 * command with better syntax for configuring network interface
    714 	 * parameters...
    715 	 */
    716 	if (!scan_netmask && afp->af_af == AF_INET) {
    717 		int	largc;
    718 		char	**largv;
    719 
    720 		/* Only go thru the command list once to find the netmask. */
    721 		scan_netmask = _B_TRUE;
    722 
    723 		/*
    724 		 * Currently, if multiple netmask commands are specified, the
    725 		 * last one will be used as the final netmask.  So we need
    726 		 * to scan the whole list to preserve this behavior.
    727 		 */
    728 		for (largc = argc, largv = argv; largc > 0; largc--, largv++) {
    729 			if (strcmp(*largv, NETMASK_CMD) == 0) {
    730 				if (--largc == 0)
    731 					break;
    732 				largv++;
    733 				if (strcmp(*largv, "+") == 0) {
    734 					g_netmask_set = G_NETMASK_PENDING;
    735 				} else {
    736 					in_getaddr(*largv, (struct sockaddr *)
    737 					    &g_netmask, NULL);
    738 					g_netmask_set = G_NETMASK_SET;
    739 				}
    740 				/* Continue the scan. */
    741 			}
    742 		}
    743 	}
    744 
    745 	while (argc > 0) {
    746 		struct cmd *p;
    747 		boolean_t found_cmd;
    748 
    749 		if (debug)
    750 			(void) printf("ifconfig: argv %s\n", *argv);
    751 
    752 		found_cmd = _B_FALSE;
    753 		for (p = cmds; p->c_func; p++) {
    754 			if (p->c_name) {
    755 				if (strcmp(*argv, p->c_name) == 0) {
    756 					/*
    757 					 * indicate that the command was
    758 					 * found and check to see if
    759 					 * the address family is valid
    760 					 */
    761 					found_cmd = _B_TRUE;
    762 					if (p->c_af == AF_ANY ||
    763 					    af == p->c_af)
    764 						break;
    765 				}
    766 			} else {
    767 				if (p->c_af == AF_ANY ||
    768 				    af == p->c_af)
    769 					break;
    770 			}
    771 		}
    772 		/*
    773 		 * If we found the keyword, but the address family
    774 		 * did not match spit out an error
    775 		 */
    776 		if (found_cmd && p->c_name == 0) {
    777 			(void) fprintf(stderr, "ifconfig: Operation %s not"
    778 			    " supported for %s\n", *argv, afp->af_name);
    779 			exit(1);
    780 		}
    781 		/*
    782 		 * else (no keyword found), we assume it's an address
    783 		 * of some sort
    784 		 */
    785 		if (p->c_name == 0 && setaddr)
    786 			p++;	/* got src, do dst */
    787 		if (p->c_func) {
    788 			if (p->c_af == AF_INET6) {
    789 				v4compat = 0;
    790 			}
    791 			if (p->c_parameter == NEXTARG ||
    792 			    p->c_parameter == OPTARG) {
    793 				argc--, argv++;
    794 				if (argc == 0 && p->c_parameter == NEXTARG) {
    795 					(void) fprintf(stderr,
    796 					    "ifconfig: no argument for %s\n",
    797 					    p->c_name);
    798 					exit(1);
    799 				}
    800 			}
    801 			/*
    802 			 *	Call the function if:
    803 			 *
    804 			 *		there's no address family
    805 			 *		restriction
    806 			 *	OR
    807 			 *		we don't know the address yet
    808 			 *		(because we were called from
    809 			 *		main)
    810 			 *	OR
    811 			 *		there is a restriction AND
    812 			 *		the address families match
    813 			 */
    814 			if ((p->c_af == AF_ANY)	||
    815 			    (lifrp == (struct lifreq *)NULL) ||
    816 			    (lifrp->lifr_addr.ss_family == p->c_af)) {
    817 				ret = (*p->c_func)(*argv, p->c_parameter);
    818 				/*
    819 				 *	If c_func failed and we should
    820 				 *	abort processing for this
    821 				 *	interface on failure, return
    822 				 *	now rather than going on to
    823 				 *	process other commands for
    824 				 *	the same interface.
    825 				 */
    826 				if (ret != 0 && p->c_abortonfail)
    827 					return;
    828 			}
    829 		}
    830 		argc--, argv++;
    831 	}
    832 
    833 	/* Check to see if there's a security hole in the tunnel setup. */
    834 	if (ipsec_policy_set && !ipsec_auth_covered) {
    835 		(void) fprintf(stderr, "ifconfig: WARNING: tunnel with only "
    836 		    "ESP and no authentication.\n");
    837 	}
    838 }
    839 
    840 /* ARGSUSED */
    841 static int
    842 setdebugflag(char *val, int64_t arg)
    843 {
    844 	debug++;
    845 	return (0);
    846 }
    847 
    848 /* ARGSUSED */
    849 static int
    850 setverboseflag(char *val, int64_t arg)
    851 {
    852 	verbose++;
    853 	return (0);
    854 }
    855 
    856 /*
    857  * This function fills in the given lifreq's lifr_addr field based on
    858  * g_netmask_set.
    859  */
    860 static void
    861 set_mask_lifreq(struct lifreq *lifr, struct sockaddr_storage *addr,
    862     struct sockaddr_storage *mask)
    863 {
    864 	assert(addr != NULL);
    865 	assert(mask != NULL);
    866 
    867 	switch (g_netmask_set) {
    868 	case G_NETMASK_SET:
    869 		lifr->lifr_addr = g_netmask;
    870 		break;
    871 
    872 	case G_NETMASK_PENDING:
    873 		/*
    874 		 * "+" is used as the argument to "netmask" command.  Query
    875 		 * the database on the correct netmask based on the address to
    876 		 * be set.
    877 		 */
    878 		assert(afp->af_af == AF_INET);
    879 		g_netmask = *addr;
    880 		if (!in_getmask((struct sockaddr_in *)&g_netmask, _B_TRUE)) {
    881 			lifr->lifr_addr = *mask;
    882 			g_netmask_set = G_NETMASK_NIL;
    883 		} else {
    884 			lifr->lifr_addr = g_netmask;
    885 			g_netmask_set = G_NETMASK_SET;
    886 		}
    887 		break;
    888 
    889 	case G_NETMASK_NIL:
    890 	default:
    891 		lifr->lifr_addr = *mask;
    892 		break;
    893 	}
    894 }
    895 
    896 /*
    897  * Set the interface address. Handles <addr>, <addr>/<n> as well as /<n>
    898  * syntax for setting the address, the address plus netmask, and just
    899  * the netmask respectively.
    900  */
    901 /* ARGSUSED */
    902 static int
    903 setifaddr(char *addr, int64_t param)
    904 {
    905 	int prefixlen = 0;
    906 	struct	sockaddr_storage laddr;
    907 	struct	sockaddr_storage netmask;
    908 	struct	sockaddr_in6 *sin6;
    909 	struct	sockaddr_in *sin;
    910 	struct	sockaddr_storage sav_netmask;
    911 
    912 	if (addr[0] == '/')
    913 		return (setifprefixlen(addr, 0));
    914 
    915 	(*afp->af_getaddr)(addr, (struct sockaddr *)&laddr, &prefixlen);
    916 
    917 	(void) memset(&netmask, 0, sizeof (netmask));
    918 	netmask.ss_family = afp->af_af;
    919 	switch (prefixlen) {
    920 	case NO_PREFIX:
    921 		/* Nothing there - ok */
    922 		break;
    923 	case BAD_ADDR:
    924 		(void) fprintf(stderr, "ifconfig: Bad prefix length in %s\n",
    925 		    addr);
    926 		exit(1);
    927 	default:
    928 		if (afp->af_af == AF_INET6) {
    929 			sin6 = (struct sockaddr_in6 *)&netmask;
    930 			if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
    931 			    (uchar_t *)&sin6->sin6_addr)) {
    932 				(void) fprintf(stderr, "ifconfig: "
    933 				    "Bad prefix length: %d\n",
    934 				    prefixlen);
    935 				exit(1);
    936 			}
    937 		} else {
    938 			sin = (struct sockaddr_in *)&netmask;
    939 			if (!in_prefixlentomask(prefixlen, IP_ABITS,
    940 			    (uchar_t *)&sin->sin_addr)) {
    941 				(void) fprintf(stderr, "ifconfig: "
    942 				    "Bad prefix length: %d\n",
    943 				    prefixlen);
    944 				exit(1);
    945 			}
    946 		}
    947 		/*
    948 		 * Just in case of funny setting of both prefix and netmask,
    949 		 * prefix should override the netmask command.
    950 		 */
    951 		g_netmask_set = G_NETMASK_NIL;
    952 		break;
    953 	}
    954 	/* Tell parser that an address was set */
    955 	setaddr++;
    956 	/* save copy of netmask to restore in case of error */
    957 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
    958 	if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0)
    959 		Perror0_exit("SIOCGLIFNETMASK");
    960 	sav_netmask = lifr.lifr_addr;
    961 
    962 	/*
    963 	 * If setting the address and not the mask, clear any existing mask
    964 	 * and the kernel will then assign the default (netmask has been set
    965 	 * to 0 in this case).  If setting both (either by using a prefix or
    966 	 * using the netmask command), set the mask first, so the address will
    967 	 * be interpreted correctly.
    968 	 */
    969 	set_mask_lifreq(&lifr, &laddr, &netmask);
    970 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
    971 		Perror0_exit("SIOCSLIFNETMASK");
    972 
    973 	if (debug) {
    974 		char abuf[INET6_ADDRSTRLEN];
    975 		void *addr = (afp->af_af == AF_INET) ?
    976 		    (void *)&((struct sockaddr_in *)&laddr)->sin_addr :
    977 		    (void *)&((struct sockaddr_in6 *)&laddr)->sin6_addr;
    978 
    979 		(void) printf("Setting %s af %d addr %s\n",
    980 		    lifr.lifr_name, afp->af_af,
    981 		    inet_ntop(afp->af_af, addr, abuf, sizeof (abuf)));
    982 	}
    983 	lifr.lifr_addr = laddr;
    984 	lifr.lifr_addr.ss_family = afp->af_af;
    985 	if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
    986 		/*
    987 		 * Restore the netmask
    988 		 */
    989 		int saverr = errno;
    990 
    991 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
    992 		lifr.lifr_addr = sav_netmask;
    993 		(void) ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr);
    994 		errno = saverr;
    995 		Perror0_exit("SIOCSLIFADDR");
    996 	}
    997 
    998 	return (0);
    999 }
   1000 
   1001 /*
   1002  * The following functions are stolen from the ipseckey(1m) program.
   1003  * Perhaps they should be somewhere common, but for now, we just maintain
   1004  * two versions.  We do this because of the different semantics for which
   1005  * algorithms we select ("requested" for ifconfig vs. "actual" for key).
   1006  */
   1007 
   1008 static ulong_t
   1009 parsenum(char *num)
   1010 {
   1011 	ulong_t rc;
   1012 	char *end = NULL;
   1013 
   1014 	errno = 0;
   1015 	rc = strtoul(num, &end, 0);
   1016 	if (errno != 0 || end == num || *end != '\0') {
   1017 		rc = (ulong_t)-1;
   1018 	}
   1019 
   1020 	return (rc);
   1021 }
   1022 
   1023 /*
   1024  * Parse and reverse parse possible algorithm values, include numbers.
   1025  * Mostly stolen from ipseckey.c. See the comments above parsenum() for why
   1026  * this isn't common to ipseckey.c.
   1027  *
   1028  * NOTE: Static buffer in this function for the return value.  Since ifconfig
   1029  *       isn't multithreaded, this isn't a huge problem.
   1030  */
   1031 
   1032 #define	NBUF_SIZE 20	/* Enough to print a large integer. */
   1033 
   1034 static char *
   1035 rparsealg(uint8_t alg_value, int proto_num)
   1036 {
   1037 	struct ipsecalgent *alg;
   1038 	static char numprint[128];	/* Enough to hold an algorithm name. */
   1039 
   1040 	/*
   1041 	 * Special cases for "any" and "none"
   1042 	 * The kernel needs to be able to distinguish between "any"
   1043 	 * and "none" and the APIs are underdefined in this area for auth.
   1044 	 */
   1045 	if (proto_num == IPSEC_PROTO_AH) {
   1046 		if (alg_value == SADB_AALG_NONE)
   1047 			return ("none");
   1048 		if (alg_value == SADB_AALG_ANY)
   1049 			return ("any");
   1050 	}
   1051 
   1052 	alg = getipsecalgbynum(alg_value, proto_num, NULL);
   1053 	if (alg != NULL) {
   1054 		(void) strlcpy(numprint, alg->a_names[0], sizeof (numprint));
   1055 		freeipsecalgent(alg);
   1056 	} else {
   1057 		(void) snprintf(numprint, sizeof (numprint), "%d", alg_value);
   1058 	}
   1059 
   1060 	return (numprint);
   1061 }
   1062 
   1063 static uint_t
   1064 parsealg(char *algname, int proto_num)
   1065 {
   1066 	struct ipsecalgent *alg;
   1067 	ulong_t invalue;
   1068 
   1069 	if (algname == NULL) {
   1070 		(void) fprintf(stderr, "ifconfig: Unexpected end of command "
   1071 		    "line.\n");
   1072 		exit(1);
   1073 	}
   1074 
   1075 	/*
   1076 	 * Special-case "none" and "any".
   1077 	 * Use strcasecmp because its length is bounded.
   1078 	 */
   1079 	if (strcasecmp("none", algname) == 0) {
   1080 		return ((proto_num == IPSEC_PROTO_ESP) ?
   1081 		    NO_ESP_EALG : NO_ESP_AALG);
   1082 	}
   1083 	if ((strcasecmp("any", algname) == 0) && (proto_num == IPSEC_PROTO_AH))
   1084 		return (SADB_AALG_ANY);
   1085 
   1086 	alg = getipsecalgbyname(algname, proto_num, NULL);
   1087 	if (alg != NULL) {
   1088 		invalue = alg->a_alg_num;
   1089 		freeipsecalgent(alg);
   1090 		return ((uint_t)invalue);
   1091 	}
   1092 
   1093 	/*
   1094 	 * Since algorithms can be loaded during kernel run-time, check for
   1095 	 * numeric algorithm values too.
   1096 	 */
   1097 	invalue = parsenum(algname);
   1098 	if ((invalue & (ulong_t)0xff) == invalue)
   1099 		return ((uint_t)invalue);
   1100 
   1101 	(void) fprintf(stderr, "ifconfig: %s algorithm type %s unknown.\n",
   1102 	    (proto_num == IPSEC_PROTO_ESP) ?
   1103 	    "Encryption" : "Authentication", algname);
   1104 	exit(1);
   1105 	/* NOTREACHED */
   1106 }
   1107 
   1108 /*
   1109  * Actual ifconfig functions to set tunnel security properties.
   1110  */
   1111 
   1112 enum ipsec_alg_type { ESP_ENCR_ALG = 1, ESP_AUTH_ALG, AH_AUTH_ALG };
   1113 
   1114 static int
   1115 set_tun_algs(int which_alg, int alg)
   1116 {
   1117 	boolean_t	encr_alg_set = _B_FALSE;
   1118 	iptun_params_t	params;
   1119 	dladm_status_t	status;
   1120 	ipsec_req_t	*ipsr;
   1121 
   1122 	if ((status = ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN,
   1123 	    &params.iptun_param_linkid)) != DLADM_STATUS_OK)
   1124 		goto done;
   1125 
   1126 	status = dladm_iptun_getparams(dlh, &params, DLADM_OPT_ACTIVE);
   1127 	if (status != DLADM_STATUS_OK)
   1128 		goto done;
   1129 
   1130 	ipsr = &params.iptun_param_secinfo;
   1131 
   1132 	/*
   1133 	 * If I'm just starting off this ifconfig, I want a clean slate,
   1134 	 * otherwise, I've captured the current tunnel security settings.
   1135 	 * In the case of continuation, I merely add to the settings.
   1136 	 */
   1137 	if (!(params.iptun_param_flags & IPTUN_PARAM_SECINFO))
   1138 		(void) memset(ipsr, 0, sizeof (*ipsr));
   1139 
   1140 	/* We're only modifying the IPsec information */
   1141 	params.iptun_param_flags = IPTUN_PARAM_SECINFO;
   1142 
   1143 	switch (which_alg) {
   1144 	case ESP_ENCR_ALG:
   1145 		if (alg == NO_ESP_EALG) {
   1146 			if (ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE)
   1147 				ipsr->ipsr_esp_req = 0;
   1148 			ipsr->ipsr_esp_alg = SADB_EALG_NONE;
   1149 
   1150 			/* Let the user specify NULL encryption implicitly. */
   1151 			if (ipsr->ipsr_esp_auth_alg != SADB_AALG_NONE) {
   1152 				encr_alg_set = _B_TRUE;
   1153 				ipsr->ipsr_esp_alg = SADB_EALG_NULL;
   1154 			}
   1155 		} else {
   1156 			encr_alg_set = _B_TRUE;
   1157 			ipsr->ipsr_esp_req =
   1158 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
   1159 			ipsr->ipsr_esp_alg = alg;
   1160 		}
   1161 		break;
   1162 	case ESP_AUTH_ALG:
   1163 		if (alg == NO_ESP_AALG) {
   1164 			if ((ipsr->ipsr_esp_alg == SADB_EALG_NONE ||
   1165 			    ipsr->ipsr_esp_alg == SADB_EALG_NULL) &&
   1166 			    !encr_alg_set)
   1167 				ipsr->ipsr_esp_req = 0;
   1168 			ipsr->ipsr_esp_auth_alg = SADB_AALG_NONE;
   1169 		} else {
   1170 			ipsr->ipsr_esp_req =
   1171 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
   1172 			ipsr->ipsr_esp_auth_alg = alg;
   1173 
   1174 			/* Let the user specify NULL encryption implicitly. */
   1175 			if (ipsr->ipsr_esp_alg == SADB_EALG_NONE &&
   1176 			    !encr_alg_set)
   1177 				ipsr->ipsr_esp_alg = SADB_EALG_NULL;
   1178 		}
   1179 		break;
   1180 	case AH_AUTH_ALG:
   1181 		if (alg == NO_AH_AALG) {
   1182 			ipsr->ipsr_ah_req = 0;
   1183 			ipsr->ipsr_auth_alg = SADB_AALG_NONE;
   1184 		} else {
   1185 			ipsr->ipsr_ah_req =
   1186 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
   1187 			ipsr->ipsr_auth_alg = alg;
   1188 		}
   1189 		break;
   1190 		/* Will never hit DEFAULT */
   1191 	}
   1192 
   1193 	status = dladm_iptun_modify(dlh, &params, DLADM_OPT_ACTIVE);
   1194 
   1195 done:
   1196 	if (status != DLADM_STATUS_OK)
   1197 		dladmerr_exit(status, name);
   1198 	else {
   1199 		ipsec_policy_set = _B_TRUE;
   1200 		if ((ipsr->ipsr_esp_req != 0 &&
   1201 		    ipsr->ipsr_esp_auth_alg != SADB_AALG_NONE) ||
   1202 		    (ipsr->ipsr_ah_req != 0 &&
   1203 		    ipsr->ipsr_auth_alg != SADB_AALG_NONE))
   1204 			ipsec_auth_covered = _B_TRUE;
   1205 	}
   1206 	return (0);
   1207 }
   1208 
   1209 /* ARGSUSED */
   1210 static int
   1211 set_tun_esp_encr_alg(char *addr, int64_t param)
   1212 {
   1213 	return (set_tun_algs(ESP_ENCR_ALG,
   1214 	    parsealg(addr, IPSEC_PROTO_ESP)));
   1215 }
   1216 
   1217 /* ARGSUSED */
   1218 static int
   1219 set_tun_esp_auth_alg(char *addr, int64_t param)
   1220 {
   1221 	return (set_tun_algs(ESP_AUTH_ALG,
   1222 	    parsealg(addr, IPSEC_PROTO_AH)));
   1223 }
   1224 
   1225 /* ARGSUSED */
   1226 static int
   1227 set_tun_ah_alg(char *addr, int64_t param)
   1228 {
   1229 	return (set_tun_algs(AH_AUTH_ALG,
   1230 	    parsealg(addr, IPSEC_PROTO_AH)));
   1231 }
   1232 
   1233 /* ARGSUSED */
   1234 static int
   1235 setifrevarp(char *arg, int64_t param)
   1236 {
   1237 	struct sockaddr_in	laddr;
   1238 
   1239 	if (afp->af_af == AF_INET6) {
   1240 		(void) fprintf(stderr,
   1241 		    "ifconfig: revarp not possible on IPv6 interface %s\n",
   1242 		    name);
   1243 		exit(1);
   1244 	}
   1245 	if (doifrevarp(name, &laddr)) {
   1246 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1247 		laddr.sin_family = AF_INET;
   1248 		(void) memcpy(&lifr.lifr_addr, &laddr, sizeof (laddr));
   1249 		if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
   1250 			Perror0_exit("SIOCSLIFADDR");
   1251 	}
   1252 	return (0);
   1253 }
   1254 
   1255 /* ARGSUSED */
   1256 static int
   1257 setifsubnet(char *addr, int64_t param)
   1258 {
   1259 	int prefixlen = 0;
   1260 	struct	sockaddr_storage subnet;
   1261 
   1262 	(*afp->af_getaddr)(addr, &subnet, &prefixlen);
   1263 
   1264 	switch (prefixlen) {
   1265 	case NO_PREFIX:
   1266 		(void) fprintf(stderr,
   1267 		    "ifconfig: Missing prefix length in subnet %s\n", addr);
   1268 		exit(1);
   1269 		/* NOTREACHED */
   1270 	case BAD_ADDR:
   1271 		(void) fprintf(stderr,
   1272 		    "ifconfig: Bad prefix length in %s\n", addr);
   1273 		exit(1);
   1274 	default:
   1275 		break;
   1276 	}
   1277 
   1278 	lifr.lifr_addr = subnet;
   1279 	lifr.lifr_addrlen = prefixlen;
   1280 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1281 	if (ioctl(s, SIOCSLIFSUBNET, (caddr_t)&lifr) < 0)
   1282 		Perror0_exit("SIOCSLIFSUBNET");
   1283 
   1284 	return (0);
   1285 }
   1286 
   1287 /* ARGSUSED */
   1288 static int
   1289 setifnetmask(char *addr, int64_t param)
   1290 {
   1291 	struct sockaddr_in netmask;
   1292 
   1293 	assert(afp->af_af != AF_INET6);
   1294 
   1295 	if (strcmp(addr, "+") == 0) {
   1296 		if (!in_getmask(&netmask, _B_FALSE))
   1297 			return (0);
   1298 		(void) printf("Setting netmask of %s to %s\n", name,
   1299 		    inet_ntoa(netmask.sin_addr));
   1300 	} else {
   1301 		in_getaddr(addr, (struct sockaddr *)&netmask, NULL);
   1302 	}
   1303 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1304 	(void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask));
   1305 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
   1306 		Perror0_exit("SIOCSLIFNETMASK");
   1307 	return (0);
   1308 }
   1309 
   1310 /*
   1311  * Parse '/<n>' as a netmask.
   1312  */
   1313 /* ARGSUSED */
   1314 static int
   1315 setifprefixlen(char *addr, int64_t param)
   1316 {
   1317 	int prefixlen;
   1318 	int af = afp->af_af;
   1319 
   1320 	prefixlen = in_getprefixlen(addr, _B_TRUE,
   1321 	    (af == AF_INET) ? IP_ABITS : IPV6_ABITS);
   1322 	if (prefixlen < 0) {
   1323 		(void) fprintf(stderr,
   1324 		    "ifconfig: Bad prefix length in %s\n", addr);
   1325 		exit(1);
   1326 	}
   1327 	(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
   1328 	lifr.lifr_addr.ss_family = af;
   1329 	if (af == AF_INET6) {
   1330 		struct sockaddr_in6 *sin6;
   1331 
   1332 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
   1333 		if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
   1334 		    (uchar_t *)&sin6->sin6_addr)) {
   1335 			(void) fprintf(stderr, "ifconfig: "
   1336 			    "Bad prefix length: %d\n",
   1337 			    prefixlen);
   1338 			exit(1);
   1339 		}
   1340 	} else if (af == AF_INET) {
   1341 		struct sockaddr_in *sin;
   1342 
   1343 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
   1344 		if (!in_prefixlentomask(prefixlen, IP_ABITS,
   1345 		    (uchar_t *)&sin->sin_addr)) {
   1346 			(void) fprintf(stderr, "ifconfig: "
   1347 			    "Bad prefix length: %d\n",
   1348 			    prefixlen);
   1349 			exit(1);
   1350 		}
   1351 	} else {
   1352 		(void) fprintf(stderr, "ifconfig: setting prefix only supported"
   1353 		    " for address family inet or inet6\n");
   1354 		exit(1);
   1355 	}
   1356 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1357 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
   1358 		Perror0_exit("SIOCSLIFNETMASK");
   1359 	return (0);
   1360 }
   1361 
   1362 /* ARGSUSED */
   1363 static int
   1364 setifbroadaddr(char *addr, int64_t param)
   1365 {
   1366 	struct	sockaddr_in broadaddr;
   1367 
   1368 	assert(afp->af_af != AF_INET6);
   1369 
   1370 	if (strcmp(addr, "+") == 0) {
   1371 		/*
   1372 		 * This doesn't set the broadcast address at all. Rather, it
   1373 		 * gets, then sets the interface's address, relying on the fact
   1374 		 * that resetting the address will reset the broadcast address.
   1375 		 */
   1376 		(void) strncpy(lifr.lifr_name, name,
   1377 		    sizeof (lifr.lifr_name));
   1378 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
   1379 			if (errno != EADDRNOTAVAIL)
   1380 				Perror0_exit("SIOCGLIFADDR");
   1381 			return (0);
   1382 		}
   1383 		if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
   1384 			Perror0_exit("SIOCGLIFADDR");
   1385 
   1386 		return (0);
   1387 	}
   1388 	in_getaddr(addr, (struct sockaddr *)&broadaddr, NULL);
   1389 
   1390 	(void) memcpy(&lifr.lifr_addr, &broadaddr, sizeof (broadaddr));
   1391 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1392 	if (ioctl(s, SIOCSLIFBRDADDR, (caddr_t)&lifr) < 0)
   1393 		Perror0_exit("SIOCSLIFBRDADDR");
   1394 	return (0);
   1395 }
   1396 
   1397 /*
   1398  * set interface destination address
   1399  */
   1400 /* ARGSUSED */
   1401 static int
   1402 setifdstaddr(char *addr, int64_t param)
   1403 {
   1404 	(*afp->af_getaddr)(addr, (struct sockaddr *)&lifr.lifr_addr, NULL);
   1405 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1406 	if (ioctl(s, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0)
   1407 		Perror0_exit("setifdstaddr: SIOCSLIFDSTADDR");
   1408 	return (0);
   1409 }
   1410 
   1411 /* ARGSUSED */
   1412 static int
   1413 setifflags(char *val, int64_t value)
   1414 {
   1415 	struct lifreq lifrl;	/* local lifreq struct */
   1416 	boolean_t bringup = _B_FALSE;
   1417 
   1418 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1419 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0)
   1420 		Perror0_exit("setifflags: SIOCGLIFFLAGS");
   1421 
   1422 	if (value < 0) {
   1423 		value = -value;
   1424 
   1425 		if ((value & IFF_NOFAILOVER) && (lifr.lifr_flags & IFF_UP)) {
   1426 			/*
   1427 			 * The kernel does not allow administratively up test
   1428 			 * addresses to be converted to data addresses.  Bring
   1429 			 * the address down first, then bring it up after it's
   1430 			 * been converted to a data address.
   1431 			 */
   1432 			lifr.lifr_flags &= ~IFF_UP;
   1433 			(void) ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr);
   1434 			bringup = _B_TRUE;
   1435 		}
   1436 
   1437 		lifr.lifr_flags &= ~value;
   1438 		if ((value & (IFF_UP | IFF_NOFAILOVER)) &&
   1439 		    (lifr.lifr_flags & IFF_DUPLICATE)) {
   1440 			/*
   1441 			 * If the user is trying to mark an interface with a
   1442 			 * duplicate address as "down," or convert a duplicate
   1443 			 * test address to a data address, then fetch the
   1444 			 * address and set it.  This will cause IP to clear
   1445 			 * the IFF_DUPLICATE flag and stop the automatic
   1446 			 * recovery timer.
   1447 			 */
   1448 			value = lifr.lifr_flags;
   1449 			if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
   1450 				(void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr);
   1451 			lifr.lifr_flags = value;
   1452 		}
   1453 	} else {
   1454 		lifr.lifr_flags |= value;
   1455 	}
   1456 
   1457 	/*
   1458 	 * If we're about to bring up an underlying physical IPv6 interface in
   1459 	 * an IPMP group, ensure the IPv6 IPMP interface is also up.  This is
   1460 	 * for backward compatibility with legacy configurations in which
   1461 	 * there are no explicit hostname files for IPMP interfaces.  (For
   1462 	 * IPv4, this is automatically handled by the kernel when migrating
   1463 	 * the underlying interface's data address to the IPMP interface.)
   1464 	 */
   1465 	(void) strlcpy(lifrl.lifr_name, name, LIFNAMSIZ);
   1466 
   1467 	if (lifnum(lifr.lifr_name) == 0 &&
   1468 	    (lifr.lifr_flags & (IFF_UP|IFF_IPV6)) == (IFF_UP|IFF_IPV6) &&
   1469 	    ioctl(s, SIOCGLIFGROUPNAME, &lifrl) == 0 &&
   1470 	    lifrl.lifr_groupname[0] != '\0') {
   1471 		lifgroupinfo_t lifgr;
   1472 
   1473 		(void) strlcpy(lifgr.gi_grname, lifrl.lifr_groupname,
   1474 		    LIFGRNAMSIZ);
   1475 		if (ioctl(s, SIOCGLIFGROUPINFO, &lifgr) == -1)
   1476 			Perror0_exit("setifflags: SIOCGLIFGROUPINFO");
   1477 
   1478 		(void) strlcpy(lifrl.lifr_name, lifgr.gi_grifname, LIFNAMSIZ);
   1479 		if (ioctl(s, SIOCGLIFFLAGS, &lifrl) == -1)
   1480 			Perror0_exit("setifflags: SIOCGLIFFLAGS");
   1481 		if (!(lifrl.lifr_flags & IFF_UP)) {
   1482 			lifrl.lifr_flags |= IFF_UP;
   1483 			if (ioctl(s, SIOCSLIFFLAGS, &lifrl) == -1)
   1484 				Perror0_exit("setifflags: SIOCSLIFFLAGS");
   1485 		}
   1486 	}
   1487 
   1488 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1489 	if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0)
   1490 		Perror0_exit("setifflags: SIOCSLIFFLAGS");
   1491 
   1492 	if (bringup) {
   1493 		lifr.lifr_flags |= IFF_UP;
   1494 		if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0)
   1495 			Perror0_exit("setifflags: SIOCSLIFFLAGS IFF_UP");
   1496 	}
   1497 
   1498 	return (0);
   1499 }
   1500 
   1501 /* ARGSUSED */
   1502 static int
   1503 setifmetric(char *val, int64_t param)
   1504 {
   1505 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1506 	lifr.lifr_metric = atoi(val);
   1507 	if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0)
   1508 		Perror0_exit("setifmetric: SIOCSLIFMETRIC");
   1509 	return (0);
   1510 }
   1511 
   1512 /* ARGSUSED */
   1513 static int
   1514 setifmtu(char *val, int64_t param)
   1515 {
   1516 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1517 	lifr.lifr_mtu = atoi(val);
   1518 	if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0)
   1519 		Perror0_exit("setifmtu: SIOCSLIFMTU");
   1520 	return (0);
   1521 }
   1522 
   1523 /* ARGSUSED */
   1524 static int
   1525 setifindex(char *val, int64_t param)
   1526 {
   1527 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1528 	lifr.lifr_index = atoi(val);
   1529 	if (ioctl(s, SIOCSLIFINDEX, (caddr_t)&lifr) < 0)
   1530 		Perror0_exit("setifindex: SIOCSLIFINDEX");
   1531 	return (0);
   1532 }
   1533 
   1534 /* ARGSUSED */
   1535 static void
   1536 notifycb(dlpi_handle_t dh, dlpi_notifyinfo_t *dnip, void *arg)
   1537 {
   1538 }
   1539 
   1540 /* ARGSUSED */
   1541 static int
   1542 setifether(char *addr, int64_t param)
   1543 {
   1544 	uchar_t		*hwaddr;
   1545 	int		hwaddrlen;
   1546 	int		retval;
   1547 	ifaddrlistx_t	*ifaddrp, *ifaddrs = NULL;
   1548 	dlpi_handle_t	dh;
   1549 	dlpi_notifyid_t id;
   1550 
   1551 	if (addr == NULL) {
   1552 		ifstatus(name);
   1553 		print_ifether(name);
   1554 		return (0);
   1555 	}
   1556 
   1557 	/*
   1558 	 * if the IP interface in the arguments is a logical
   1559 	 * interface, exit with an error now.
   1560 	 */
   1561 	if (strchr(name, ':') != NULL) {
   1562 		(void) fprintf(stderr, "ifconfig: cannot change"
   1563 		    " ethernet address of a logical interface\n");
   1564 		exit(1);
   1565 	}
   1566 
   1567 	if ((hwaddr = _link_aton(addr, &hwaddrlen)) == NULL) {
   1568 		if (hwaddrlen == -1)
   1569 			(void) fprintf(stderr,
   1570 			    "ifconfig: %s: bad address\n", hwaddr);
   1571 		else
   1572 			(void) fprintf(stderr, "ifconfig: malloc() failed\n");
   1573 		exit(1);
   1574 	}
   1575 
   1576 	if ((retval = dlpi_open(name, &dh, 0)) != DLPI_SUCCESS)
   1577 		Perrdlpi_exit("cannot dlpi_open() link", name, retval);
   1578 
   1579 	retval = dlpi_enabnotify(dh, DL_NOTE_PHYS_ADDR, notifycb, NULL, &id);
   1580 	if (retval == DLPI_SUCCESS) {
   1581 		(void) dlpi_disabnotify(dh, id, NULL);
   1582 	} else {
   1583 		/*
   1584 		 * This link does not support DL_NOTE_PHYS_ADDR: bring down
   1585 		 * all of the addresses to flush the old hardware address
   1586 		 * information out of IP.
   1587 		 *
   1588 		 * NOTE: Skipping this when DL_NOTE_PHYS_ADDR is supported is
   1589 		 * more than an optimization: in.mpathd will set IFF_OFFLINE
   1590 		 * if it's notified and the new address is a duplicate of
   1591 		 * another in the group -- but the flags manipulation in
   1592 		 * ifaddr_{down,up}() cannot be atomic and thus might clobber
   1593 		 * IFF_OFFLINE, confusing in.mpathd.
   1594 		 */
   1595 		if (ifaddrlistx(name, IFF_UP, 0, &ifaddrs) == -1)
   1596 			Perror2_exit(name, "cannot get address list");
   1597 
   1598 		ifaddrp = ifaddrs;
   1599 		for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
   1600 			if (!ifaddr_down(ifaddrp)) {
   1601 				Perror2_exit(ifaddrp->ia_name,
   1602 				    "cannot bring down");
   1603 			}
   1604 		}
   1605 	}
   1606 
   1607 	/*
   1608 	 * Change the hardware address.
   1609 	 */
   1610 	retval = dlpi_set_physaddr(dh, DL_CURR_PHYS_ADDR, hwaddr, hwaddrlen);
   1611 	if (retval != DLPI_SUCCESS) {
   1612 		(void) fprintf(stderr,
   1613 		    "ifconfig: failed setting mac address on %s\n", name);
   1614 	}
   1615 	dlpi_close(dh);
   1616 
   1617 	/*
   1618 	 * If any addresses were brought down before changing the hardware
   1619 	 * address, bring them up again.
   1620 	 */
   1621 	for (ifaddrp = ifaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
   1622 		if (!ifaddr_up(ifaddrp))
   1623 			Perror2_exit(ifaddrp->ia_name, "cannot bring up");
   1624 	}
   1625 	ifaddrlistx_free(ifaddrs);
   1626 
   1627 	return (0);
   1628 }
   1629 
   1630 /*
   1631  * Print an interface's Ethernet address, if it has one.
   1632  */
   1633 static void
   1634 print_ifether(char *ifname)
   1635 {
   1636 	int fd;
   1637 
   1638 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1639 
   1640 	fd = socket(AF_INET, SOCK_DGRAM, 0);
   1641 	if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) {
   1642 		/*
   1643 		 * It's possible the interface is only configured for
   1644 		 * IPv6; check again with AF_INET6.
   1645 		 */
   1646 		(void) close(fd);
   1647 		fd = socket(AF_INET6, SOCK_DGRAM, 0);
   1648 		if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) {
   1649 			(void) close(fd);
   1650 			return;
   1651 		}
   1652 	}
   1653 	(void) close(fd);
   1654 
   1655 	/* VNI and IPMP interfaces don't have MAC addresses */
   1656 	if (lifr.lifr_flags & (IFF_VIRTUAL|IFF_IPMP))
   1657 		return;
   1658 
   1659 	/* IP tunnels also don't have Ethernet-like MAC addresses */
   1660 	if (ifconfig_dladm_open(ifname, DATALINK_CLASS_IPTUN, NULL) ==
   1661 	    DLADM_STATUS_OK)
   1662 		return;
   1663 
   1664 	dlpi_print_address(ifname);
   1665 }
   1666 
   1667 /*
   1668  * static int find_all_interfaces(struct lifconf *lifcp, char **buf,
   1669  *     int64_t lifc_flags)
   1670  *
   1671  * It finds all active data links.
   1672  *
   1673  * It takes in input a pointer to struct lifconf to receive interfaces
   1674  * informations, a **char to hold allocated buffer, and a lifc_flags.
   1675  *
   1676  * Return values:
   1677  *  0 = everything OK
   1678  * -1 = problem
   1679  */
   1680 static int
   1681 find_all_interfaces(struct lifconf *lifcp, char **buf, int64_t lifc_flags)
   1682 {
   1683 	unsigned bufsize;
   1684 	int n;
   1685 	ni_t *nip;
   1686 	struct lifreq *lifrp;
   1687 	dladm_status_t status;
   1688 
   1689 	if (!dlh_opened) {
   1690 		status = ifconfig_dladm_open(NULL, 0, NULL);
   1691 		if (status != DLADM_STATUS_OK)
   1692 			dladmerr_exit(status, "unable to open dladm handle");
   1693 	}
   1694 
   1695 	(void) dlpi_walk(ni_entry, dlh, 0);
   1696 
   1697 	/* Now, translate the linked list into a struct lifreq buffer */
   1698 	if (num_ni == 0) {
   1699 		lifcp->lifc_family = AF_UNSPEC;
   1700 		lifcp->lifc_flags = lifc_flags;
   1701 		lifcp->lifc_len = 0;
   1702 		lifcp->lifc_buf = NULL;
   1703 		return (0);
   1704 	}
   1705 
   1706 	bufsize = num_ni * sizeof (struct lifreq);
   1707 	if ((*buf = malloc(bufsize)) == NULL)
   1708 		Perror0_exit("find_all_interfaces: malloc failed");
   1709 
   1710 	lifcp->lifc_family = AF_UNSPEC;
   1711 	lifcp->lifc_flags = lifc_flags;
   1712 	lifcp->lifc_len = bufsize;
   1713 	lifcp->lifc_buf = *buf;
   1714 
   1715 	for (n = 0, lifrp = lifcp->lifc_req; n < num_ni; n++, lifrp++) {
   1716 		nip = ni_list;
   1717 		(void) strncpy(lifrp->lifr_name, nip->ni_name,
   1718 		    sizeof (lifr.lifr_name));
   1719 		ni_list = nip->ni_next;
   1720 		free(nip);
   1721 	}
   1722 	return (0);
   1723 }
   1724 
   1725 /*
   1726  * Create the next unused logical interface using the original name
   1727  * and assign the address (and mask if '/<n>' is part of the address).
   1728  * Use the new logical interface for subsequent subcommands by updating
   1729  * the name variable.
   1730  *
   1731  * This allows syntax like:
   1732  *	ifconfig le0 addif 109.106.86.130 netmask + up \
   1733  *	addif 109.106.86.131 netmask + up
   1734  */
   1735 /* ARGSUSED */
   1736 static int
   1737 addif(char *str, int64_t param)
   1738 {
   1739 	int prefixlen = 0;
   1740 	struct sockaddr_storage laddr;
   1741 	struct sockaddr_storage mask;
   1742 
   1743 	(void) strncpy(name, origname, sizeof (name));
   1744 
   1745 	if (strchr(name, ':') != NULL) {
   1746 		(void) fprintf(stderr,
   1747 		    "ifconfig: addif: bad physical interface name %s\n",
   1748 		    name);
   1749 		exit(1);
   1750 	}
   1751 
   1752 	/*
   1753 	 * clear so parser will interpret next address as source followed
   1754 	 * by possible dest
   1755 	 */
   1756 	setaddr = 0;
   1757 	(*afp->af_getaddr)(str, (struct sockaddr *)&laddr, &prefixlen);
   1758 
   1759 	switch (prefixlen) {
   1760 	case NO_PREFIX:
   1761 		/* Nothing there - ok */
   1762 		break;
   1763 	case BAD_ADDR:
   1764 		(void) fprintf(stderr,
   1765 		    "ifconfig: Bad prefix length in %s\n", str);
   1766 		exit(1);
   1767 	default:
   1768 		(void) memset(&mask, 0, sizeof (mask));
   1769 		mask.ss_family = afp->af_af;
   1770 		if (afp->af_af == AF_INET6) {
   1771 			struct sockaddr_in6 *sin6;
   1772 			sin6 = (struct sockaddr_in6 *)&mask;
   1773 			if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
   1774 			    (uchar_t *)&sin6->sin6_addr)) {
   1775 				(void) fprintf(stderr, "ifconfig: "
   1776 				    "Bad prefix length: %d\n",
   1777 				    prefixlen);
   1778 				exit(1);
   1779 			}
   1780 		} else {
   1781 			struct sockaddr_in *sin;
   1782 
   1783 			sin = (struct sockaddr_in *)&mask;
   1784 			if (!in_prefixlentomask(prefixlen, IP_ABITS,
   1785 			    (uchar_t *)&sin->sin_addr)) {
   1786 				(void) fprintf(stderr, "ifconfig: "
   1787 				    "Bad prefix length: %d\n",
   1788 				    prefixlen);
   1789 				exit(1);
   1790 			}
   1791 		}
   1792 		g_netmask_set = G_NETMASK_NIL;
   1793 		break;
   1794 	}
   1795 
   1796 	/*
   1797 	 * This is a "hack" to get around the problem of SIOCLIFADDIF.  The
   1798 	 * problem is that this ioctl does not include the netmask when
   1799 	 * adding a logical interface.  This is the same problem described
   1800 	 * in the ifconfig() comments.  To get around this problem, we first
   1801 	 * add the logical interface with a 0 address.  After that, we set
   1802 	 * the netmask if provided.  Finally we set the interface address.
   1803 	 */
   1804 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1805 	(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
   1806 
   1807 	/* Note: no need to do DAD here since the interface isn't up yet. */
   1808 
   1809 	if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
   1810 		Perror0_exit("addif: SIOCLIFADDIF");
   1811 
   1812 	(void) printf("Created new logical interface %s\n",
   1813 	    lifr.lifr_name);
   1814 	(void) strncpy(name, lifr.lifr_name, sizeof (name));
   1815 
   1816 	/*
   1817 	 * Check and see if any "netmask" command is used and perform the
   1818 	 * necessary operation.
   1819 	 */
   1820 	set_mask_lifreq(&lifr, &laddr, &mask);
   1821 	/*
   1822 	 * Only set the netmask if "netmask" command is used or a prefix is
   1823 	 * provided.
   1824 	 */
   1825 	if (g_netmask_set == G_NETMASK_SET || prefixlen >= 0) {
   1826 		if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
   1827 			Perror0_exit("addif: SIOCSLIFNETMASK");
   1828 	}
   1829 
   1830 	/* Finally, we set the interface address. */
   1831 	lifr.lifr_addr = laddr;
   1832 	if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
   1833 		Perror0_exit("SIOCSLIFADDR");
   1834 
   1835 	/*
   1836 	 * let parser know we got a source.
   1837 	 * Next address, if given, should be dest
   1838 	 */
   1839 	setaddr++;
   1840 	return (0);
   1841 }
   1842 
   1843 /*
   1844  * Remove a logical interface based on its IP address. Unlike addif
   1845  * there is no '/<n>' here.
   1846  * Verifies that the interface is down before it is removed.
   1847  */
   1848 /* ARGSUSED */
   1849 static int
   1850 removeif(char *str, int64_t param)
   1851 {
   1852 	struct sockaddr_storage laddr;
   1853 
   1854 	if (strchr(name, ':') != NULL) {
   1855 		(void) fprintf(stderr,
   1856 		    "ifconfig: removeif: bad physical interface name %s\n",
   1857 		    name);
   1858 		exit(1);
   1859 	}
   1860 
   1861 	(*afp->af_getaddr)(str, &laddr, NULL);
   1862 	lifr.lifr_addr = laddr;
   1863 
   1864 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1865 	if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
   1866 		if (errno == EBUSY) {
   1867 			/* This can only happen if ipif_id = 0 */
   1868 			(void) fprintf(stderr,
   1869 			    "ifconfig: removeif: can't remove interface: %s\n",
   1870 			    name);
   1871 			exit(1);
   1872 		}
   1873 		Perror0_exit("removeif: SIOCLIFREMOVEIF");
   1874 	}
   1875 	return (0);
   1876 }
   1877 
   1878 /*
   1879  * Set the address token for IPv6.
   1880  */
   1881 /* ARGSUSED */
   1882 static int
   1883 setiftoken(char *addr, int64_t param)
   1884 {
   1885 	int prefixlen = 0;
   1886 	struct sockaddr_in6 token;
   1887 
   1888 	in6_getaddr(addr, (struct sockaddr *)&token, &prefixlen);
   1889 	switch (prefixlen) {
   1890 	case NO_PREFIX:
   1891 		(void) fprintf(stderr,
   1892 		    "ifconfig: Missing prefix length in subnet %s\n", addr);
   1893 		exit(1);
   1894 		/* NOTREACHED */
   1895 	case BAD_ADDR:
   1896 		(void) fprintf(stderr,
   1897 		    "ifconfig: Bad prefix length in %s\n", addr);
   1898 		exit(1);
   1899 	default:
   1900 		break;
   1901 	}
   1902 	(void) memcpy(&lifr.lifr_addr, &token, sizeof (token));
   1903 	lifr.lifr_addrlen = prefixlen;
   1904 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1905 	if (ioctl(s, SIOCSLIFTOKEN, (caddr_t)&lifr) < 0)  {
   1906 		Perror0_exit("setiftoken: SIOCSLIFTOKEN");
   1907 	}
   1908 	return (0);
   1909 }
   1910 
   1911 /* ARGSUSED */
   1912 static int
   1913 setifgroupname(char *grname, int64_t param)
   1914 {
   1915 	lifgroupinfo_t		lifgr;
   1916 	struct lifreq		lifrl;
   1917 	ifaddrlistx_t		*ifaddrp, *nextifaddrp;
   1918 	ifaddrlistx_t		*ifaddrs = NULL, *downaddrs = NULL;
   1919 	int			af;
   1920 
   1921 	if (debug) {
   1922 		(void) printf("Setting groupname %s on interface %s\n",
   1923 		    grname, name);
   1924 	}
   1925 
   1926 	(void) strlcpy(lifrl.lifr_name, name, LIFNAMSIZ);
   1927 	(void) strlcpy(lifrl.lifr_groupname, grname, LIFGRNAMSIZ);
   1928 
   1929 	while (ioctl(s, SIOCSLIFGROUPNAME, &lifrl) == -1) {
   1930 		switch (errno) {
   1931 		case ENOENT:
   1932 			/*
   1933 			 * The group doesn't yet exist; create it and repeat.
   1934 			 */
   1935 			af = afp->af_af;
   1936 			if (create_ipmp(grname, af, NULL, _B_TRUE) == -1) {
   1937 				if (errno == EEXIST)
   1938 					continue;
   1939 
   1940 				Perror2(grname, "cannot create IPMP group");
   1941 				goto fail;
   1942 			}
   1943 			continue;
   1944 
   1945 		case EALREADY:
   1946 			/*
   1947 			 * The interface is already in another group; must
   1948 			 * remove existing membership first.
   1949 			 */
   1950 			lifrl.lifr_groupname[0] = '\0';
   1951 			if (ioctl(s, SIOCSLIFGROUPNAME, &lifrl) == -1) {
   1952 				Perror2(name, "cannot remove existing "
   1953 				    "IPMP group membership");
   1954 				goto fail;
   1955 			}
   1956 			(void) strlcpy(lifrl.lifr_groupname, grname,
   1957 			    LIFGRNAMSIZ);
   1958 			continue;
   1959 
   1960 		case EAFNOSUPPORT:
   1961 			/*
   1962 			 * The group exists, but it's not configured with the
   1963 			 * address families the interface needs.  Since only
   1964 			 * two address families are currently supported, just
   1965 			 * configure the "other" address family.  Note that we
   1966 			 * may race with group deletion or creation by another
   1967 			 * process (ENOENT or EEXIST); in such cases we repeat
   1968 			 * our original SIOCSLIFGROUPNAME.
   1969 			 */
   1970 			(void) strlcpy(lifgr.gi_grname, grname, LIFGRNAMSIZ);
   1971 			if (ioctl(s, SIOCGLIFGROUPINFO, &lifgr) == -1) {
   1972 				if (errno == ENOENT)
   1973 					continue;
   1974 
   1975 				Perror2(grname, "SIOCGLIFGROUPINFO");
   1976 				goto fail;
   1977 			}
   1978 
   1979 			af = lifgr.gi_v4 ? AF_INET6 : AF_INET;
   1980 			if (create_ipmp(grname, af, lifgr.gi_grifname,
   1981 			    _B_TRUE) == -1) {
   1982 				if (errno == EEXIST)
   1983 					continue;
   1984 
   1985 				Perror2(grname, "cannot configure IPMP group");
   1986 				goto fail;
   1987 			}
   1988 			continue;
   1989 
   1990 		case EADDRINUSE:
   1991 			/*
   1992 			 * Some addresses are in-use (or under control of DAD).
   1993 			 * Bring them down and retry the group join operation.
   1994 			 * We will bring them back up after the interface has
   1995 			 * been placed in the group.
   1996 			 */
   1997 			if (ifaddrlistx(lifrl.lifr_name, IFF_UP|IFF_DUPLICATE,
   1998 			    0, &ifaddrs) == -1) {
   1999 				Perror2(grname, "cannot get address list");
   2000 				goto fail;
   2001 			}
   2002 
   2003 			ifaddrp = ifaddrs;
   2004 			for (; ifaddrp != NULL; ifaddrp = nextifaddrp) {
   2005 				if (!ifaddr_down(ifaddrp)) {
   2006 					ifaddrs = ifaddrp;
   2007 					goto fail;
   2008 				}
   2009 				nextifaddrp = ifaddrp->ia_next;
   2010 				ifaddrp->ia_next = downaddrs;
   2011 				downaddrs = ifaddrp;
   2012 			}
   2013 			ifaddrs = NULL;
   2014 			continue;
   2015 
   2016 		case EADDRNOTAVAIL: {
   2017 			/*
   2018 			 * Some data addresses are under application control.
   2019 			 * For some of these (e.g., ADDRCONF), the application
   2020 			 * should remove the address, in which case we retry a
   2021 			 * few times (since the application's action is not
   2022 			 * atomic with respect to us) before bailing out and
   2023 			 * informing the user.
   2024 			 */
   2025 			int ntries, nappaddr = 0;
   2026 			const if_appflags_t *iap = if_appflags_tbl;
   2027 
   2028 			for (; iap->ia_app != NULL; iap++) {
   2029 				ntries = 0;
   2030 again:
   2031 				if (ifaddrlistx(lifrl.lifr_name, iap->ia_flag,
   2032 				    IFF_NOFAILOVER, &ifaddrs) == -1) {
   2033 					(void) fprintf(stderr, "ifconfig: %s: "
   2034 					    "cannot get data addresses managed "
   2035 					    "by %s\n", lifrl.lifr_name,
   2036 					    iap->ia_app);
   2037 					goto fail;
   2038 				}
   2039 
   2040 				if (ifaddrs == NULL)
   2041 					continue;
   2042 
   2043 				ifaddrlistx_free(ifaddrs);
   2044 				ifaddrs = NULL;
   2045 
   2046 				if (++ntries < iap->ia_tries) {
   2047 					(void) poll(NULL, 0, 100);
   2048 					goto again;
   2049 				}
   2050 
   2051 				(void) fprintf(stderr, "ifconfig: cannot join "
   2052 				    "IPMP group: %s has data addresses managed "
   2053 				    "by %s\n", lifrl.lifr_name, iap->ia_app);
   2054 				nappaddr++;
   2055 			}
   2056 			if (nappaddr > 0)
   2057 				goto fail;
   2058 			continue;
   2059 		}
   2060 		default:
   2061 			Perror2(name, "SIOCSLIFGROUPNAME");
   2062 			goto fail;
   2063 		}
   2064 	}
   2065 
   2066 	/*
   2067 	 * If there were addresses that we had to bring down, it's time to
   2068 	 * bring them up again.  As part of bringing them up, the kernel will
   2069 	 * automatically move them to the new IPMP interface.
   2070 	 */
   2071 	for (ifaddrp = downaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
   2072 		if (!ifaddr_up(ifaddrp) && errno != ENXIO) {
   2073 			(void) fprintf(stderr, "ifconfig: cannot bring back up "
   2074 			    "%s: %s\n", ifaddrp->ia_name, strerror(errno));
   2075 		}
   2076 	}
   2077 	ifaddrlistx_free(downaddrs);
   2078 	return (0);
   2079 fail:
   2080 	/*
   2081 	 * Attempt to bring back up any interfaces that we downed.
   2082 	 */
   2083 	for (ifaddrp = downaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
   2084 		if (!ifaddr_up(ifaddrp) && errno != ENXIO) {
   2085 			(void) fprintf(stderr, "ifconfig: cannot bring back up "
   2086 			    "%s: %s\n", ifaddrp->ia_name, strerror(errno));
   2087 		}
   2088 	}
   2089 	ifaddrlistx_free(downaddrs);
   2090 	ifaddrlistx_free(ifaddrs);
   2091 
   2092 	/*
   2093 	 * We'd return -1, but foreachinterface() doesn't propagate the error
   2094 	 * into the exit status, so we're forced to explicitly exit().
   2095 	 */
   2096 	exit(1);
   2097 	/* NOTREACHED */
   2098 }
   2099 
   2100 static boolean_t
   2101 modcheck(const char *ifname)
   2102 {
   2103 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
   2104 
   2105 	if (ioctl(s, SIOCGLIFFLAGS, &lifr) < 0) {
   2106 		Perror0("SIOCGLIFFLAGS");
   2107 		return (_B_FALSE);
   2108 	}
   2109 
   2110 	if (lifr.lifr_flags & IFF_IPMP) {
   2111 		(void) fprintf(stderr, "ifconfig: %s: module operations not"
   2112 		    " supported on IPMP interfaces\n", ifname);
   2113 		return (_B_FALSE);
   2114 	}
   2115 	if (lifr.lifr_flags & IFF_VIRTUAL) {
   2116 		(void) fprintf(stderr, "ifconfig: %s: module operations not"
   2117 		    " supported on virtual IP interfaces\n", ifname);
   2118 		return (_B_FALSE);
   2119 	}
   2120 	return (_B_TRUE);
   2121 }
   2122 
   2123 /*
   2124  * To list all the modules above a given network interface.
   2125  */
   2126 /* ARGSUSED */
   2127 static int
   2128 modlist(char *null, int64_t param)
   2129 {
   2130 	int muxid_fd;
   2131 	int muxfd;
   2132 	int ipfd_lowstr;
   2133 	int arpfd_lowstr;
   2134 	int num_mods;
   2135 	int i;
   2136 	struct str_list strlist;
   2137 	int orig_arpid;
   2138 
   2139 	/*
   2140 	 * We'd return -1, but foreachinterface() doesn't propagate the error
   2141 	 * into the exit status, so we're forced to explicitly exit().
   2142 	 */
   2143 	if (!modcheck(name))
   2144 		exit(1);
   2145 
   2146 	if (ip_domux2fd(&muxfd, &muxid_fd, &ipfd_lowstr, &arpfd_lowstr,
   2147 	    &orig_arpid) < 0) {
   2148 		return (-1);
   2149 	}
   2150 	if ((num_mods = ioctl(ipfd_lowstr, I_LIST, NULL)) < 0) {
   2151 		Perror0("cannot I_LIST to get the number of modules");
   2152 	} else {
   2153 		if (debug > 0) {
   2154 			(void) printf("Listing (%d) modules above %s\n",
   2155 			    num_mods, name);
   2156 		}
   2157 
   2158 		strlist.sl_nmods = num_mods;
   2159 		strlist.sl_modlist = malloc(sizeof (struct str_mlist) *
   2160 		    num_mods);
   2161 		if (strlist.sl_modlist == NULL) {
   2162 			Perror0("cannot malloc");
   2163 		} else {
   2164 			if (ioctl(ipfd_lowstr, I_LIST, (caddr_t)&strlist) < 0) {
   2165 				Perror0("cannot I_LIST for module names");
   2166 			} else {
   2167 				for (i = 0; i < strlist.sl_nmods; i++) {
   2168 					(void) printf("%d %s\n", i,
   2169 					    strlist.sl_modlist[i].l_name);
   2170 				}
   2171 			}
   2172 			free(strlist.sl_modlist);
   2173 		}
   2174 	}
   2175 	return (ip_plink(muxfd, muxid_fd, ipfd_lowstr, arpfd_lowstr,
   2176 	    orig_arpid));
   2177 }
   2178 
   2179 #define	MODINSERT_OP	'i'
   2180 #define	MODREMOVE_OP	'r'
   2181 
   2182 /*
   2183  * To insert a module to the stream of the interface.  It is just a
   2184  * wrapper.  The real function is modop().
   2185  */
   2186 /* ARGSUSED */
   2187 static int
   2188 modinsert(char *arg, int64_t param)
   2189 {
   2190 	return (modop(arg, MODINSERT_OP));
   2191 }
   2192 
   2193 /*
   2194  * To remove a module from the stream of the interface.  It is just a
   2195  * wrapper.  The real function is modop().
   2196  */
   2197 /* ARGSUSED */
   2198 static int
   2199 modremove(char *arg, int64_t param)
   2200 {
   2201 	return (modop(arg, MODREMOVE_OP));
   2202 }
   2203 
   2204 /*
   2205  * Open a stream on /dev/udp{,6}, pop off all undesired modules (note that
   2206  * the user may have configured autopush to add modules above
   2207  * udp), and push the arp module onto the resulting stream.
   2208  * This is used to make IP+ARP be able to atomically track the muxid
   2209  * for the I_PLINKed STREAMS, thus it isn't related to ARP running the ARP
   2210  * protocol.
   2211  */
   2212 static int
   2213 open_arp_on_udp(char *udp_dev_name)
   2214 {
   2215 	int fd;
   2216 
   2217 	if ((fd = open(udp_dev_name, O_RDWR)) == -1) {
   2218 		Perror2("open", udp_dev_name);
   2219 		return (-1);
   2220 	}
   2221 	errno = 0;
   2222 	while (ioctl(fd, I_POP, 0) != -1)
   2223 		;
   2224 	if (errno != EINVAL) {
   2225 		Perror2("pop", udp_dev_name);
   2226 	} else if (ioctl(fd, I_PUSH, ARP_MOD_NAME) == -1) {
   2227 		Perror2("arp PUSH", udp_dev_name);
   2228 	} else {
   2229 		return (fd);
   2230 	}
   2231 	(void) close(fd);
   2232 	return (-1);
   2233 }
   2234 
   2235 /*
   2236  * Helper function for mod*() functions.  It gets a fd to the lower IP
   2237  * stream and I_PUNLINK's the lower stream.  It also initializes the
   2238  * global variable lifr.
   2239  *
   2240  * Param:
   2241  *	int *muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK
   2242  *	int *muxid_fd: fd to /dev/udp{,6} for LIFMUXID
   2243  *	int *ipfd_lowstr: fd to the lower IP stream.
   2244  *	int *arpfd_lowstr: fd to the lower ARP stream.
   2245  *
   2246  * Return:
   2247  *	-1 if operation fails, 0 otherwise.
   2248  *
   2249  * Please see the big block comment above ifplumb() for the logic of the
   2250  * PLINK/PUNLINK
   2251  */
   2252 static int
   2253 ip_domux2fd(int *muxfd, int *muxid_fd, int *ipfd_lowstr, int *arpfd_lowstr,
   2254     int *orig_arpid)
   2255 {
   2256 	uint64_t	flags;
   2257 	char		*udp_dev_name;
   2258 
   2259 	*orig_arpid = 0;
   2260 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2261 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
   2262 		Perror0_exit("status: SIOCGLIFFLAGS");
   2263 	}
   2264 	flags = lifr.lifr_flags;
   2265 	if (flags & IFF_IPV4) {
   2266 		udp_dev_name = UDP_DEV_NAME;
   2267 	} else if (flags & IFF_IPV6) {
   2268 		udp_dev_name = UDP6_DEV_NAME;
   2269 	} else {
   2270 		return (-1);
   2271 	}
   2272 
   2273 	if ((*muxid_fd = open(udp_dev_name, O_RDWR)) < 0) {
   2274 		Perror2("open", udp_dev_name);
   2275 		return (-1);
   2276 	}
   2277 	if (ioctl(*muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
   2278 		Perror2("SIOCGLIFMUXID", udp_dev_name);
   2279 		return (-1);
   2280 	}
   2281 	if (debug > 0) {
   2282 		(void) printf("ARP_muxid %d IP_muxid %d\n",
   2283 		    lifr.lifr_arp_muxid, lifr.lifr_ip_muxid);
   2284 	}
   2285 
   2286 	/*
   2287 	 * Use /dev/udp{,6} as the mux to avoid linkcycles.
   2288 	 */
   2289 	if ((*muxfd = open_arp_on_udp(udp_dev_name)) == -1)
   2290 		return (-1);
   2291 
   2292 	if (lifr.lifr_arp_muxid != 0) {
   2293 		if ((*arpfd_lowstr = ioctl(*muxfd, _I_MUXID2FD,
   2294 		    lifr.lifr_arp_muxid)) < 0) {
   2295 			if ((errno == EINVAL) &&
   2296 			    (flags & (IFF_NOARP | IFF_IPV6))) {
   2297 				/*
   2298 				 * Some plumbing utilities set the muxid to
   2299 				 * -1 or some invalid value to signify that
   2300 				 * there is no arp stream. Set the muxid to 0
   2301 				 * before trying to unplumb the IP stream.
   2302 				 * IP does not allow the IP stream to be
   2303 				 * unplumbed if it sees a non-null arp muxid,
   2304 				 * for consistency of IP-ARP streams.
   2305 				 */
   2306 				*orig_arpid = lifr.lifr_arp_muxid;
   2307 				lifr.lifr_arp_muxid = 0;
   2308 				(void) ioctl(*muxid_fd, SIOCSLIFMUXID,
   2309 				    (caddr_t)&lifr);
   2310 				*arpfd_lowstr = -1;
   2311 			} else {
   2312 				Perror0("_I_MUXID2FD");
   2313 				return (-1);
   2314 			}
   2315 		} else if (ioctl(*muxfd, I_PUNLINK,
   2316 		    lifr.lifr_arp_muxid) < 0) {
   2317 			Perror2("I_PUNLINK", udp_dev_name);
   2318 			return (-1);
   2319 		}
   2320 	} else {
   2321 		*arpfd_lowstr = -1;
   2322 	}
   2323 
   2324 	if ((*ipfd_lowstr = ioctl(*muxfd, _I_MUXID2FD,
   2325 	    lifr.lifr_ip_muxid)) < 0) {
   2326 		Perror0("_I_MUXID2FD");
   2327 		/* Undo any changes we made */
   2328 		if (*orig_arpid != 0) {
   2329 			lifr.lifr_arp_muxid = *orig_arpid;
   2330 			(void) ioctl(*muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
   2331 		}
   2332 		return (-1);
   2333 	}
   2334 	if (ioctl(*muxfd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) {
   2335 		Perror2("I_PUNLINK", udp_dev_name);
   2336 		/* Undo any changes we made */
   2337 		if (*orig_arpid != 0) {
   2338 			lifr.lifr_arp_muxid = *orig_arpid;
   2339 			(void) ioctl(*muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
   2340 		}
   2341 		return (-1);
   2342 	}
   2343 	return (0);
   2344 }
   2345 
   2346 /*
   2347  * Helper function for mod*() functions.  It I_PLINK's back the upper and
   2348  * lower IP streams.  Note that this function must be called after
   2349  * ip_domux2fd().  In ip_domux2fd(), the global variable lifr is initialized
   2350  * and ip_plink() needs information in lifr.  So ip_domux2fd() and ip_plink()
   2351  * must be called in pairs.
   2352  *
   2353  * Param:
   2354  *	int muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK
   2355  *	int muxid_fd: fd to /dev/udp{,6} for LIFMUXID
   2356  *	int ipfd_lowstr: fd to the lower IP stream.
   2357  *	int arpfd_lowstr: fd to the lower ARP stream.
   2358  *
   2359  * Return:
   2360  *	-1 if operation fails, 0 otherwise.
   2361  *
   2362  * Please see the big block comment above ifplumb() for the logic of the
   2363  * PLINK/PUNLINK
   2364  */
   2365 static int
   2366 ip_plink(int muxfd, int muxid_fd, int ipfd_lowstr, int arpfd_lowstr,
   2367     int orig_arpid)
   2368 {
   2369 	int ip_muxid;
   2370 
   2371 	ip_muxid = ioctl(muxfd, I_PLINK, ipfd_lowstr);
   2372 	if (ip_muxid < 0) {
   2373 		Perror2("I_PLINK", UDP_DEV_NAME);
   2374 		return (-1);
   2375 	}
   2376 
   2377 	/*
   2378 	 * If there is an arp stream, plink it. If there is no
   2379 	 * arp stream, then it is possible that the plumbing
   2380 	 * utility could have stored any value in the arp_muxid.
   2381 	 * If so, restore it from orig_arpid.
   2382 	 */
   2383 	if (arpfd_lowstr != -1) {
   2384 		if (ioctl(muxfd, I_PLINK, arpfd_lowstr) < 0) {
   2385 			Perror2("I_PLINK", UDP_DEV_NAME);
   2386 			return (-1);
   2387 		}
   2388 	} else if (orig_arpid != 0) {
   2389 		/* Undo the changes we did in ip_domux2fd */
   2390 		lifr.lifr_arp_muxid = orig_arpid;
   2391 		lifr.lifr_ip_muxid = ip_muxid;
   2392 		(void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
   2393 	}
   2394 
   2395 	(void) close(muxfd);
   2396 	(void) close(muxid_fd);
   2397 	return (0);
   2398 }
   2399 
   2400 /*
   2401  * The real function to perform module insertion/removal.
   2402  *
   2403  * Param:
   2404  *	char *arg: the argument string module_name@position
   2405  *	char op: operation, either MODINSERT_OP or MODREMOVE_OP.
   2406  *
   2407  * Return:
   2408  *	Before doing ip_domux2fd(), this function calls exit(1) in case of
   2409  *	error.  After ip_domux2fd() is done, it returns -1 for error, 0
   2410  *	otherwise.
   2411  */
   2412 static int
   2413 modop(char *arg, char op)
   2414 {
   2415 	char *pos_p;
   2416 	int muxfd;
   2417 	int muxid_fd;
   2418 	int ipfd_lowstr;  /* IP stream (lower stream of mux) to be plinked */
   2419 	int arpfd_lowstr; /* ARP stream (lower stream of mux) to be plinked */
   2420 	struct strmodconf mod;
   2421 	char *at_char = "@";
   2422 	char *arg_str;
   2423 	int orig_arpid;
   2424 
   2425 	/*
   2426 	 * We'd return -1, but foreachinterface() doesn't propagate the error
   2427 	 * into the exit status, so we're forced to explicitly exit().
   2428 	 */
   2429 	if (!modcheck(name))
   2430 		exit(1);
   2431 
   2432 	/* Need to save the original string for -a option. */
   2433 	if ((arg_str = malloc(strlen(arg) + 1)) == NULL) {
   2434 		Perror0("cannot malloc");
   2435 		return (-1);
   2436 	}
   2437 	(void) strcpy(arg_str, arg);
   2438 
   2439 	if (*arg_str == *at_char) {
   2440 		(void) fprintf(stderr,
   2441 		    "ifconfig: must supply a module name\n");
   2442 		exit(1);
   2443 	}
   2444 	mod.mod_name = strtok(arg_str, at_char);
   2445 	if (strlen(mod.mod_name) > FMNAMESZ) {
   2446 		(void) fprintf(stderr, "ifconfig: module name too long: %s\n",
   2447 		    mod.mod_name);
   2448 		exit(1);
   2449 	}
   2450 
   2451 	/*
   2452 	 * Need to make sure that the core TCP/IP stack modules are not
   2453 	 * removed.  Otherwise, "bad" things can happen.  If a module
   2454 	 * is removed and inserted back, it loses its old state.  But
   2455 	 * the modules above it still have the old state.  E.g. IP assumes
   2456 	 * fast data path while tunnel after re-inserted assumes that it can
   2457 	 * receive M_DATA only in fast data path for which it does not have
   2458 	 * any state.  This is a general caveat of _I_REMOVE/_I_INSERT.
   2459 	 */
   2460 	if (op == MODREMOVE_OP &&
   2461 	    (strcmp(mod.mod_name, ARP_MOD_NAME) == 0 ||
   2462 	    strcmp(mod.mod_name, IP_MOD_NAME) == 0)) {
   2463 		(void) fprintf(stderr, "ifconfig: cannot remove %s\n",
   2464 		    mod.mod_name);
   2465 		exit(1);
   2466 	}
   2467 
   2468 	if ((pos_p = strtok(NULL, at_char)) == NULL) {
   2469 		(void) fprintf(stderr, "ifconfig: must supply a position\n");
   2470 		exit(1);
   2471 	}
   2472 	mod.pos = atoi(pos_p);
   2473 
   2474 	if (ip_domux2fd(&muxfd, &muxid_fd, &ipfd_lowstr, &arpfd_lowstr,
   2475 	    &orig_arpid) < 0) {
   2476 		free(arg_str);
   2477 		return (-1);
   2478 	}
   2479 	switch (op) {
   2480 	case MODINSERT_OP:
   2481 		if (debug > 0) {
   2482 			(void) printf("Inserting module %s at %d\n",
   2483 			    mod.mod_name, mod.pos);
   2484 		}
   2485 		if (ioctl(ipfd_lowstr, _I_INSERT, (caddr_t)&mod) < 0) {
   2486 			Perror2("fail to insert module", mod.mod_name);
   2487 		}
   2488 		break;
   2489 	case MODREMOVE_OP:
   2490 		if (debug > 0) {
   2491 			(void) printf("Removing module %s at %d\n",
   2492 			    mod.mod_name, mod.pos);
   2493 		}
   2494 		if (ioctl(ipfd_lowstr, _I_REMOVE, (caddr_t)&mod) < 0) {
   2495 			Perror2("fail to remove module", mod.mod_name);
   2496 		}
   2497 		break;
   2498 	default:
   2499 		/* Should never get to here. */
   2500 		(void) fprintf(stderr, "Unknown operation\n");
   2501 		break;
   2502 	}
   2503 	free(arg_str);
   2504 	return (ip_plink(muxfd, muxid_fd, ipfd_lowstr, arpfd_lowstr,
   2505 	    orig_arpid));
   2506 }
   2507 
   2508 static int
   2509 modify_tun(iptun_params_t *params)
   2510 {
   2511 	dladm_status_t status;
   2512 
   2513 	if ((status = ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN,
   2514 	    &params->iptun_param_linkid)) == DLADM_STATUS_OK)
   2515 		status = dladm_iptun_modify(dlh, params, DLADM_OPT_ACTIVE);
   2516 	if (status != DLADM_STATUS_OK)
   2517 		dladmerr_exit(status, name);
   2518 	return (0);
   2519 }
   2520 
   2521 /*
   2522  * Set tunnel source address
   2523  */
   2524 /* ARGSUSED */
   2525 static int
   2526 setiftsrc(char *addr, int64_t param)
   2527 {
   2528 	iptun_params_t params;
   2529 
   2530 	params.iptun_param_flags = IPTUN_PARAM_LADDR;
   2531 	(void) strlcpy(params.iptun_param_laddr, addr,
   2532 	    sizeof (params.iptun_param_laddr));
   2533 	return (modify_tun(&params));
   2534 }
   2535 
   2536 /*
   2537  * Set tunnel destination address
   2538  */
   2539 /* ARGSUSED */
   2540 static int
   2541 setiftdst(char *addr, int64_t param)
   2542 {
   2543 	iptun_params_t params;
   2544 
   2545 	params.iptun_param_flags = IPTUN_PARAM_RADDR;
   2546 	(void) strlcpy(params.iptun_param_raddr, addr,
   2547 	    sizeof (params.iptun_param_raddr));
   2548 	return (modify_tun(&params));
   2549 }
   2550 
   2551 static int
   2552 set_tun_prop(const char *propname, char *value)
   2553 {
   2554 	dladm_status_t	status;
   2555 	datalink_id_t	linkid;
   2556 
   2557 	status = ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN, &linkid);
   2558 	if (status == DLADM_STATUS_OK) {
   2559 		status = dladm_set_linkprop(dlh, linkid, propname, &value, 1,
   2560 		    DLADM_OPT_ACTIVE);
   2561 	}
   2562 	if (status != DLADM_STATUS_OK)
   2563 		dladmerr_exit(status, name);
   2564 	return (0);
   2565 }
   2566 
   2567 /* Set tunnel encapsulation limit. */
   2568 /* ARGSUSED */
   2569 static int
   2570 set_tun_encap_limit(char *arg, int64_t param)
   2571 {
   2572 	return (set_tun_prop("encaplimit", arg));
   2573 }
   2574 
   2575 /* Disable encapsulation limit. */
   2576 /* ARGSUSED */
   2577 static int
   2578 clr_tun_encap_limit(char *arg, int64_t param)
   2579 {
   2580 	return (set_tun_encap_limit("-1", 0));
   2581 }
   2582 
   2583 /* Set tunnel hop limit. */
   2584 /* ARGSUSED */
   2585 static int
   2586 set_tun_hop_limit(char *arg, int64_t param)
   2587 {
   2588 	return (set_tun_prop("hoplimit", arg));
   2589 }
   2590 
   2591 /* Set zone ID */
   2592 static int
   2593 setzone(char *arg, int64_t param)
   2594 {
   2595 	zoneid_t zoneid = GLOBAL_ZONEID;
   2596 
   2597 	if (param == NEXTARG) {
   2598 		/* zone must be active */
   2599 		if ((zoneid = getzoneidbyname(arg)) == -1) {
   2600 			(void) fprintf(stderr,
   2601 			    "ifconfig: unknown zone '%s'\n", arg);
   2602 			exit(1);
   2603 		}
   2604 	}
   2605 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2606 	lifr.lifr_zoneid = zoneid;
   2607 	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1)
   2608 		Perror0_exit("SIOCSLIFZONE");
   2609 	return (0);
   2610 }
   2611 
   2612 /* Put interface into all zones */
   2613 /* ARGSUSED */
   2614 static int
   2615 setallzones(char *arg, int64_t param)
   2616 {
   2617 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2618 	lifr.lifr_zoneid = ALL_ZONES;
   2619 	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1)
   2620 		Perror0_exit("SIOCSLIFZONE");
   2621 	return (0);
   2622 }
   2623 
   2624 /* Set source address to use */
   2625 /* ARGSUSED */
   2626 static int
   2627 setifsrc(char *arg, int64_t param)
   2628 {
   2629 	uint_t ifindex = 0;
   2630 	int rval;
   2631 
   2632 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2633 
   2634 	/*
   2635 	 * Argument can be either an interface name or "none". The latter means
   2636 	 * that any previous selection is cleared.
   2637 	 */
   2638 
   2639 	rval = strcmp(arg, name);
   2640 	if (rval == 0) {
   2641 		(void) fprintf(stderr,
   2642 		    "ifconfig: Cannot specify same interface for usesrc"
   2643 		    " group\n");
   2644 		exit(1);
   2645 	}
   2646 
   2647 	rval = strcmp(arg, NONE_STR);
   2648 	if (rval != 0) {
   2649 		if ((ifindex = if_nametoindex(arg)) == 0) {
   2650 			(void) strncpy(lifr.lifr_name, arg, LIFNAMSIZ);
   2651 			Perror0_exit("Could not get interface index");
   2652 		}
   2653 		lifr.lifr_index = ifindex;
   2654 	} else {
   2655 		if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) != 0)
   2656 			Perror0_exit("Not a valid usesrc consumer");
   2657 		lifr.lifr_index = 0;
   2658 	}
   2659 
   2660 	if (debug)
   2661 		(void) printf("setifsrc: lifr_name %s, lifr_index %d\n",
   2662 		    lifr.lifr_name, lifr.lifr_index);
   2663 
   2664 	if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) == -1) {
   2665 		if (rval == 0)
   2666 			Perror0_exit("Cannot reset usesrc group");
   2667 		else
   2668 			Perror0_exit("Could not set source interface");
   2669 	}
   2670 
   2671 	return (0);
   2672 }
   2673 
   2674 /*
   2675  * Print the interface status line associated with `ifname'
   2676  */
   2677 static void
   2678 ifstatus(const char *ifname)
   2679 {
   2680 	uint64_t flags;
   2681 	char if_usesrc_name[LIFNAMSIZ];
   2682 	char *newbuf;
   2683 	int n, numifs, rval = 0;
   2684 	struct lifreq *lifrp;
   2685 	struct lifsrcof lifs;
   2686 
   2687 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
   2688 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
   2689 		Perror0_exit("status: SIOCGLIFFLAGS");
   2690 	}
   2691 	flags = lifr.lifr_flags;
   2692 
   2693 	/*
   2694 	 * In V4 compatibility mode, we don't print the IFF_IPV4 flag or
   2695 	 * interfaces with IFF_IPV6 set.
   2696 	 */
   2697 	if (v4compat) {
   2698 		flags &= ~IFF_IPV4;
   2699 		if (flags & IFF_IPV6)
   2700 			return;
   2701 	}
   2702 
   2703 	(void) printf("%s: ", ifname);
   2704 	print_flags(flags);
   2705 
   2706 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
   2707 	if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) {
   2708 		Perror0_exit("status: SIOCGLIFMETRIC");
   2709 	} else {
   2710 		if (lifr.lifr_metric)
   2711 			(void) printf(" metric %d", lifr.lifr_metric);
   2712 	}
   2713 	if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0)
   2714 		(void) printf(" mtu %u", lifr.lifr_mtu);
   2715 
   2716 	/* don't print index or zone when in compatibility mode */
   2717 	if (!v4compat) {
   2718 		if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0)
   2719 			(void) printf(" index %d", lifr.lifr_index);
   2720 		/*
   2721 		 * Stack instances use GLOBAL_ZONEID for IP data structures
   2722 		 * even in the non-global zone.
   2723 		 */
   2724 		if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) >= 0 &&
   2725 		    lifr.lifr_zoneid != getzoneid() &&
   2726 		    lifr.lifr_zoneid != GLOBAL_ZONEID) {
   2727 			char zone_name[ZONENAME_MAX];
   2728 
   2729 			if (lifr.lifr_zoneid == ALL_ZONES) {
   2730 				(void) printf("\n\tall-zones");
   2731 			} else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
   2732 			    sizeof (zone_name)) < 0) {
   2733 				(void) printf("\n\tzone %d", lifr.lifr_zoneid);
   2734 			} else {
   2735 				(void) printf("\n\tzone %s", zone_name);
   2736 			}
   2737 		}
   2738 	}
   2739 
   2740 	if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) {
   2741 		lifs.lifs_ifindex = lifr.lifr_index;
   2742 
   2743 		/*
   2744 		 * Find the number of interfaces that use this interfaces'
   2745 		 * address as a source address
   2746 		 */
   2747 		lifs.lifs_buf = NULL;
   2748 		lifs.lifs_maxlen = 0;
   2749 		for (;;) {
   2750 			/* The first pass will give the bufsize we need */
   2751 			rval = ioctl(s, SIOCGLIFSRCOF, (char *)&lifs);
   2752 			if (rval < 0) {
   2753 				if (lifs.lifs_buf != NULL) {
   2754 					free(lifs.lifs_buf);
   2755 					lifs.lifs_buf = NULL;
   2756 				}
   2757 				lifs.lifs_len = 0;
   2758 				break;
   2759 			}
   2760 			if (lifs.lifs_len <= lifs.lifs_maxlen)
   2761 				break;
   2762 			/* Use kernel's size + a small margin to avoid loops */
   2763 			lifs.lifs_maxlen = lifs.lifs_len +
   2764 			    5 * sizeof (struct lifreq);
   2765 			/* For the first pass, realloc acts like malloc */
   2766 			newbuf = realloc(lifs.lifs_buf, lifs.lifs_maxlen);
   2767 			if (newbuf == NULL) {
   2768 				if (lifs.lifs_buf != NULL) {
   2769 					free(lifs.lifs_buf);
   2770 					lifs.lifs_buf = NULL;
   2771 				}
   2772 				lifs.lifs_len = 0;
   2773 				break;
   2774 			}
   2775 			lifs.lifs_buf = newbuf;
   2776 		}
   2777 
   2778 
   2779 		numifs = lifs.lifs_len / sizeof (struct lifreq);
   2780 		if (numifs > 0) {
   2781 			lifrp = lifs.lifs_req;
   2782 			(void) printf("\n\tsrcof");
   2783 			for (n = numifs; n > 0; n--, lifrp++) {
   2784 				(void) printf(" %s", lifrp->lifr_name);
   2785 			}
   2786 		}
   2787 
   2788 		if (lifs.lifs_buf != NULL)
   2789 			free(lifs.lifs_buf);
   2790 	}
   2791 
   2792 	/* Find the interface whose source address this interface uses */
   2793 	if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) {
   2794 		if (lifr.lifr_index != 0) {
   2795 			if (if_indextoname(lifr.lifr_index,
   2796 			    if_usesrc_name) == NULL) {
   2797 				(void) printf("\n\tusesrc ifIndex %d",
   2798 				    lifr.lifr_index);
   2799 			} else {
   2800 				(void) printf("\n\tusesrc %s", if_usesrc_name);
   2801 			}
   2802 		}
   2803 	}
   2804 
   2805 	(void) putchar('\n');
   2806 }
   2807 
   2808 
   2809 /*
   2810  * Print the status of the interface.  If an address family was
   2811  * specified, show it and it only; otherwise, show them all.
   2812  */
   2813 static void
   2814 status(void)
   2815 {
   2816 	struct afswtch	*p = afp;
   2817 	uint64_t	flags;
   2818 	datalink_id_t	linkid;
   2819 
   2820 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2821 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
   2822 		Perror0_exit("status: SIOCGLIFFLAGS");
   2823 	}
   2824 
   2825 	flags = lifr.lifr_flags;
   2826 
   2827 	/*
   2828 	 * Only print the interface status if the address family matches
   2829 	 * the interface family flag.
   2830 	 */
   2831 	if (p != NULL) {
   2832 		if (((p->af_af == AF_INET6) && (flags & IFF_IPV4)) ||
   2833 		    ((p->af_af == AF_INET) && (flags & IFF_IPV6)))
   2834 			return;
   2835 	}
   2836 
   2837 	/*
   2838 	 * In V4 compatibility mode, don't print IFF_IPV6 interfaces.
   2839 	 */
   2840 	if (v4compat && (flags & IFF_IPV6))
   2841 		return;
   2842 
   2843 	ifstatus(name);
   2844 
   2845 	if (ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN, &linkid) ==
   2846 	    DLADM_STATUS_OK)
   2847 		tun_status(linkid);
   2848 
   2849 	if (p != NULL) {
   2850 		(*p->af_status)(1, flags);
   2851 	} else {
   2852 		for (p = afs; p->af_name; p++) {
   2853 			(void) close(s);
   2854 			s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0);
   2855 			/* set global af for use in p->af_status */
   2856 			af = p->af_af;
   2857 			if (s == -1) {
   2858 				Perror0_exit("socket");
   2859 			}
   2860 			(*p->af_status)(0, flags);
   2861 		}
   2862 
   2863 		/*
   2864 		 * Historically, 'ether' has been an address family,
   2865 		 * so print it here.
   2866 		 */
   2867 		print_ifether(name);
   2868 	}
   2869 }
   2870 
   2871 /*
   2872  * Print the status of the interface in a format that can be used to
   2873  * reconfigure the interface later. Code stolen from status() above.
   2874  */
   2875 /* ARGSUSED */
   2876 static int
   2877 configinfo(char *null, int64_t param)
   2878 {
   2879 	char *cp;
   2880 	struct afswtch *p = afp;
   2881 	uint64_t flags;
   2882 	char lifname[LIFNAMSIZ];
   2883 	char if_usesrc_name[LIFNAMSIZ];
   2884 
   2885 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2886 
   2887 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
   2888 		Perror0_exit("status: SIOCGLIFFLAGS");
   2889 	}
   2890 	flags = lifr.lifr_flags;
   2891 
   2892 	if (debug) {
   2893 		(void) printf("configinfo: name %s flags  0x%llx af_af %d\n",
   2894 		    name, flags, p != NULL ? p->af_af : -1);
   2895 	}
   2896 
   2897 	/*
   2898 	 * Build the interface name to print (we can't directly use `name'
   2899 	 * because one cannot "plumb" ":0" interfaces).
   2900 	 */
   2901 	(void) strlcpy(lifname, name, LIFNAMSIZ);
   2902 	if ((cp = strchr(lifname, ':')) != NULL && atoi(cp + 1) == 0)
   2903 		*cp = '\0';
   2904 
   2905 	/*
   2906 	 * if the interface is IPv4
   2907 	 *	if we have a IPv6 address family restriction return
   2908 	 *		so it won't print
   2909 	 *	if we are in IPv4 compatibility mode, clear out IFF_IPV4
   2910 	 *		so we don't print it.
   2911 	 */
   2912 	if (flags & IFF_IPV4) {
   2913 		if (p && p->af_af == AF_INET6)
   2914 			return (-1);
   2915 		if (v4compat)
   2916 			flags &= ~IFF_IPV4;
   2917 
   2918 		(void) printf("%s inet plumb", lifname);
   2919 	} else if (flags & IFF_IPV6) {
   2920 		/*
   2921 		 * else if the interface is IPv6
   2922 		 *	if we have a IPv4 address family restriction return
   2923 		 *	or we are in IPv4 compatibiltiy mode, return.
   2924 		 */
   2925 		if (p && p->af_af == AF_INET)
   2926 			return (-1);
   2927 		if (v4compat)
   2928 			return (-1);
   2929 
   2930 		(void) printf("%s inet6 plumb", lifname);
   2931 	}
   2932 
   2933 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2934 	if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) {
   2935 		Perror0_exit("configinfo: SIOCGLIFMETRIC");
   2936 	} else {
   2937 		if (lifr.lifr_metric)
   2938 			(void) printf(" metric %d ", lifr.lifr_metric);
   2939 	}
   2940 	if (((flags & (IFF_VIRTUAL|IFF_LOOPBACK)) != IFF_VIRTUAL) &&
   2941 	    ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0)
   2942 		(void) printf(" mtu %d", lifr.lifr_metric);
   2943 
   2944 	/* Index only applies to the zeroth interface */
   2945 	if (lifnum(name) == 0) {
   2946 		if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0)
   2947 			(void) printf(" index %d", lifr.lifr_index);
   2948 	}
   2949 
   2950 	if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) {
   2951 		if (lifr.lifr_index != 0) {
   2952 			if (if_indextoname(lifr.lifr_index,
   2953 			    if_usesrc_name) != NULL) {
   2954 				(void) printf(" usesrc %s", if_usesrc_name);
   2955 			}
   2956 		}
   2957 	}
   2958 
   2959 	if (p != NULL) {
   2960 		(*p->af_configinfo)(1, flags);
   2961 	} else {
   2962 		for (p = afs; p->af_name; p++) {
   2963 			(void) close(s);
   2964 			s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0);
   2965 			/* set global af for use in p->af_configinfo */
   2966 			af = p->af_af;
   2967 			if (s == -1) {
   2968 				Perror0_exit("socket");
   2969 			}
   2970 			(*p->af_configinfo)(0, flags);
   2971 		}
   2972 	}
   2973 
   2974 	(void) putchar('\n');
   2975 	return (0);
   2976 }
   2977 
   2978 static void
   2979 print_tsec(iptun_params_t *params)
   2980 {
   2981 	ipsec_req_t *ipsr;
   2982 
   2983 	(void) printf("\ttunnel security settings  ");
   2984 	if (!(params->iptun_param_flags & IPTUN_PARAM_SECINFO)) {
   2985 		(void) printf("-->  use 'ipsecconf -ln -i %s'", name);
   2986 	} else {
   2987 		ipsr = &params->iptun_param_secinfo;
   2988 		if (ipsr->ipsr_ah_req & IPSEC_PREF_REQUIRED) {
   2989 			(void) printf("ah (%s)  ",
   2990 			    rparsealg(ipsr->ipsr_auth_alg, IPSEC_PROTO_AH));
   2991 		}
   2992 		if (ipsr->ipsr_esp_req & IPSEC_PREF_REQUIRED) {
   2993 			(void) printf("esp (%s",
   2994 			    rparsealg(ipsr->ipsr_esp_alg, IPSEC_PROTO_ESP));
   2995 			(void) printf("/%s)",
   2996 			    rparsealg(ipsr->ipsr_esp_auth_alg, IPSEC_PROTO_AH));
   2997 		}
   2998 	}
   2999 	(void) printf("\n");
   3000 }
   3001 
   3002 static void
   3003 tun_status(datalink_id_t linkid)
   3004 {
   3005 	iptun_params_t	params;
   3006 	char		propval[DLADM_PROP_VAL_MAX];
   3007 	char		*valptr[1];
   3008 	uint_t		valcnt = 1;
   3009 	boolean_t	tabbed = _B_FALSE;
   3010 
   3011 	params.iptun_param_linkid = linkid;
   3012 
   3013 	/* If dladm_iptun_getparams() fails, assume we are not a tunnel. */
   3014 	assert(dlh_opened);
   3015 	if (dladm_iptun_getparams(dlh, &params, DLADM_OPT_ACTIVE) !=
   3016 	    DLADM_STATUS_OK)
   3017 		return;
   3018 
   3019 	switch (params.iptun_param_type) {
   3020 	case IPTUN_TYPE_IPV4:
   3021 	case IPTUN_TYPE_6TO4:
   3022 		(void) printf("\tinet");
   3023 		break;
   3024 	case IPTUN_TYPE_IPV6:
   3025 		(void) printf("\tinet6");
   3026 		break;
   3027 	default:
   3028 		dladmerr_exit(DLADM_STATUS_IPTUNTYPE, name);
   3029 		break;
   3030 	}
   3031 
   3032 	/*
   3033 	 * There is always a source address.  If it hasn't been explicitly
   3034 	 * set, the API will pass back a buffer containing the unspecified
   3035 	 * address.
   3036 	 */
   3037 	(void) printf(" tunnel src %s ", params.iptun_param_laddr);
   3038 
   3039 	if (params.iptun_param_flags & IPTUN_PARAM_RADDR)
   3040 		(void) printf("tunnel dst %s\n", params.iptun_param_raddr);
   3041 	else
   3042 		(void) putchar('\n');
   3043 
   3044 	if (params.iptun_param_flags & IPTUN_PARAM_IPSECPOL)
   3045 		print_tsec(&params);
   3046 
   3047 	valptr[0] = propval;
   3048 	if (dladm_get_linkprop(dlh, linkid, DLADM_PROP_VAL_CURRENT, "hoplimit",
   3049 	    (char **)valptr, &valcnt) == DLADM_STATUS_OK) {
   3050 		(void) printf("\ttunnel hop limit %s ", propval);
   3051 		tabbed = _B_TRUE;
   3052 	}
   3053 
   3054 	if (dladm_get_linkprop(dlh, linkid, DLADM_PROP_VAL_CURRENT,
   3055 	    "encaplimit", (char **)valptr, &valcnt) == DLADM_STATUS_OK) {
   3056 		uint32_t elim;
   3057 
   3058 		if (!tabbed) {
   3059 			(void) putchar('\t');
   3060 			tabbed = _B_TRUE;
   3061 		}
   3062 		elim = strtol(propval, NULL, 10);
   3063 		if (elim > 0)
   3064 			(void) printf("tunnel encapsulation limit %s", propval);
   3065 		else
   3066 			(void) printf("tunnel encapsulation limit disabled");
   3067 	}
   3068 
   3069 	if (tabbed)
   3070 		(void) putchar('\n');
   3071 }
   3072 
   3073 static void
   3074 in_status(int force, uint64_t flags)
   3075 {
   3076 	struct sockaddr_in	*sin, *laddr;
   3077 	struct sockaddr_in	netmask = { AF_INET };
   3078 
   3079 	if (debug)
   3080 		(void) printf("in_status(%s) flags 0x%llx\n", name, flags);
   3081 
   3082 	/* only print status for IPv4 interfaces */
   3083 	if (!(flags & IFF_IPV4))
   3084 		return;
   3085 
   3086 	if (!(flags & IFF_NOLOCAL)) {
   3087 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3088 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
   3089 			if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
   3090 			    errno == ENXIO) {
   3091 				if (!force)
   3092 					return;
   3093 				(void) memset(&lifr.lifr_addr, 0,
   3094 				    sizeof (lifr.lifr_addr));
   3095 			} else
   3096 				Perror0_exit("in_status: SIOCGLIFADDR");
   3097 		}
   3098 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
   3099 		(void) printf("\tinet %s ", inet_ntoa(sin->sin_addr));
   3100 		laddr = sin;
   3101 	} else {
   3102 		(void) printf("\tinet ");
   3103 	}
   3104 
   3105 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3106 	if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
   3107 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
   3108 		    errno == ENXIO) {
   3109 			if (!force)
   3110 				return;
   3111 			(void) memset(&lifr.lifr_addr, 0,
   3112 			    sizeof (lifr.lifr_addr));
   3113 		} else {
   3114 			Perror0_exit("in_status: SIOCGLIFSUBNET");
   3115 		}
   3116 	}
   3117 	sin = (struct sockaddr_in *)&lifr.lifr_addr;
   3118 	if ((flags & IFF_NOLOCAL) ||
   3119 	    sin->sin_addr.s_addr != laddr->sin_addr.s_addr) {
   3120 		(void) printf("subnet %s/%d ", inet_ntoa(sin->sin_addr),
   3121 		    lifr.lifr_addrlen);
   3122 	}
   3123 	if (sin->sin_family != AF_INET) {
   3124 		(void) printf("Wrong family: %d\n", sin->sin_family);
   3125 	}
   3126 
   3127 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3128 	if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) {
   3129 		if (errno != EADDRNOTAVAIL)
   3130 			Perror0_exit("in_status: SIOCGLIFNETMASK");
   3131 		(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
   3132 	} else
   3133 		netmask.sin_addr =
   3134 		    ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr;
   3135 	if (flags & IFF_POINTOPOINT) {
   3136 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3137 		if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
   3138 			if (errno == EADDRNOTAVAIL)
   3139 				(void) memset(&lifr.lifr_addr, 0,
   3140 				    sizeof (lifr.lifr_addr));
   3141 			else
   3142 				Perror0_exit("in_status: SIOCGLIFDSTADDR");
   3143 		}
   3144 		sin = (struct sockaddr_in *)&lifr.lifr_dstaddr;
   3145 		(void) printf("--> %s ", inet_ntoa(sin->sin_addr));
   3146 	}
   3147 	(void) printf("netmask %x ", ntohl(netmask.sin_addr.s_addr));
   3148 	if (flags & IFF_BROADCAST) {
   3149 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3150 		if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) {
   3151 			if (errno == EADDRNOTAVAIL)
   3152 				(void) memset(&lifr.lifr_addr, 0,
   3153 				    sizeof (lifr.lifr_addr));
   3154 			else
   3155 				Perror0_exit("in_status: SIOCGLIFBRDADDR");
   3156 		}
   3157 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
   3158 		if (sin->sin_addr.s_addr != 0) {
   3159 			(void) printf("broadcast %s",
   3160 			    inet_ntoa(sin->sin_addr));
   3161 		}
   3162 	}
   3163 	/* If there is a groupname, print it for only the physical interface */
   3164 	if (strchr(name, ':') == NULL) {
   3165 		if (ioctl(s, SIOCGLIFGROUPNAME, &lifr) >= 0 &&
   3166 		    lifr.lifr_groupname[0] != '\0') {
   3167 			(void) printf("\n\tgroupname %s", lifr.lifr_groupname);
   3168 		}
   3169 	}
   3170 	(void) putchar('\n');
   3171 }
   3172 
   3173 static void
   3174 in6_status(int force, uint64_t flags)
   3175 {
   3176 	char			abuf[INET6_ADDRSTRLEN];
   3177 	struct sockaddr_in6	*sin6, *laddr6;
   3178 
   3179 	if (debug)
   3180 		(void) printf("in6_status(%s) flags 0x%llx\n", name, flags);
   3181 
   3182 	if (!(flags & IFF_IPV6))
   3183 		return;
   3184 
   3185 	if (!(flags & IFF_NOLOCAL)) {
   3186 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3187 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
   3188 			if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
   3189 			    errno == ENXIO) {
   3190 				if (!force)
   3191 					return;
   3192 				(void) memset(&lifr.lifr_addr, 0,
   3193 				    sizeof (lifr.lifr_addr));
   3194 			} else
   3195 				Perror0_exit("in_status6: SIOCGLIFADDR");
   3196 		}
   3197 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
   3198 		(void) printf("\tinet6 %s/%d ",
   3199 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
   3200 		    abuf, sizeof (abuf)),
   3201 		    lifr.lifr_addrlen);
   3202 		laddr6 = sin6;
   3203 	} else {
   3204 		(void) printf("\tinet6 ");
   3205 	}
   3206 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3207 	if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
   3208 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
   3209 		    errno == ENXIO) {
   3210 			if (!force)
   3211 				return;
   3212 			(void) memset(&lifr.lifr_addr, 0,
   3213 			    sizeof (lifr.lifr_addr));
   3214 		} else
   3215 			Perror0_exit("in_status6: SIOCGLIFSUBNET");
   3216 	}
   3217 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
   3218 	if ((flags & IFF_NOLOCAL) ||
   3219 	    !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) {
   3220 		(void) printf("subnet %s/%d ",
   3221 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
   3222 		    abuf, sizeof (abuf)),
   3223 		    lifr.lifr_addrlen);
   3224 	}
   3225 	if (sin6->sin6_family != AF_INET6) {
   3226 		(void) printf("Wrong family: %d\n", sin6->sin6_family);
   3227 	}
   3228 	if (flags & IFF_POINTOPOINT) {
   3229 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3230 		if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
   3231 			if (errno == EADDRNOTAVAIL)
   3232 				(void) memset(&lifr.lifr_addr, 0,
   3233 				    sizeof (lifr.lifr_addr));
   3234 			else
   3235 				Perror0_exit("in_status6: SIOCGLIFDSTADDR");
   3236 		}
   3237 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr;
   3238 		(void) printf("--> %s ",
   3239 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
   3240 		    abuf, sizeof (abuf)));
   3241 	}
   3242 	if (verbose) {
   3243 		(void) putchar('\n');
   3244 		(void) putchar('\t');
   3245 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3246 		if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) {
   3247 			if (errno == EADDRNOTAVAIL || errno == EINVAL)
   3248 				(void) memset(&lifr.lifr_addr, 0,
   3249 				    sizeof (lifr.lifr_addr));
   3250 			else
   3251 				Perror0_exit("in_status6: SIOCGLIFTOKEN");
   3252 		} else {
   3253 			sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
   3254 			(void) printf("token %s/%d ",
   3255 			    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
   3256 			    abuf, sizeof (abuf)),
   3257 			    lifr.lifr_addrlen);
   3258 		}
   3259 		if (ioctl(s, SIOCGLIFLNKINFO, (caddr_t)&lifr) < 0) {
   3260 			if (errno != EINVAL) {
   3261 				Perror0_exit("in_status6: SIOCGLIFLNKINFO");
   3262 			}
   3263 		} else {
   3264 			(void) printf("maxhops %u, reachtime %u ms, "
   3265 			    "reachretrans %u ms, maxmtu %u ",
   3266 			    lifr.lifr_ifinfo.lir_maxhops,
   3267 			    lifr.lifr_ifinfo.lir_reachtime,
   3268 			    lifr.lifr_ifinfo.lir_reachretrans,
   3269 			    lifr.lifr_ifinfo.lir_maxmtu);
   3270 		}
   3271 	}
   3272 	/* If there is a groupname, print it for only the physical interface */
   3273 	if (strchr(name, ':') == NULL) {
   3274 		if (ioctl(s, SIOCGLIFGROUPNAME, &lifr) >= 0 &&
   3275 		    lifr.lifr_groupname[0] != '\0') {
   3276 			(void) printf("\n\tgroupname %s", lifr.lifr_groupname);
   3277 		}
   3278 	}
   3279 	(void) putchar('\n');
   3280 }
   3281 
   3282 static void
   3283 in_configinfo(int force, uint64_t flags)
   3284 {
   3285 	struct sockaddr_in *sin, *laddr;
   3286 	struct	sockaddr_in netmask = { AF_INET };
   3287 
   3288 	if (debug)
   3289 		(void) printf("in_configinfo(%s) flags 0x%llx\n", name, flags);
   3290 
   3291 	/* only configinfo info for IPv4 interfaces */
   3292 	if (!(flags & IFF_IPV4))
   3293 		return;
   3294 
   3295 	if (!(flags & IFF_NOLOCAL)) {
   3296 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3297 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
   3298 			if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
   3299 			    errno == ENXIO) {
   3300 				if (!force)
   3301 					return;
   3302 				(void) memset(&lifr.lifr_addr, 0,
   3303 				    sizeof (lifr.lifr_addr));
   3304 			} else
   3305 				Perror0_exit("in_configinfo: SIOCGLIFADDR");
   3306 		}
   3307 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
   3308 		(void) printf(" set %s ", inet_ntoa(sin->sin_addr));
   3309 		laddr = sin;
   3310 	}
   3311 
   3312 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3313 	if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
   3314 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
   3315 		    errno == ENXIO) {
   3316 			if (!force)
   3317 				return;
   3318 			(void) memset(&lifr.lifr_addr, 0,
   3319 			    sizeof (lifr.lifr_addr));
   3320 		} else {
   3321 			Perror0_exit("in_configinfo: SIOCGLIFSUBNET");
   3322 		}
   3323 	}
   3324 	sin = (struct sockaddr_in *)&lifr.lifr_addr;
   3325 
   3326 	if ((flags & IFF_NOLOCAL) ||
   3327 	    sin->sin_addr.s_addr != laddr->sin_addr.s_addr) {
   3328 		(void) printf(" subnet %s/%d ", inet_ntoa(sin->sin_addr),
   3329 		    lifr.lifr_addrlen);
   3330 	}
   3331 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3332 	if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) {
   3333 		if (errno != EADDRNOTAVAIL)
   3334 			Perror0_exit("in_configinfo: SIOCGLIFNETMASK");
   3335 		(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
   3336 	} else
   3337 		netmask.sin_addr =
   3338 		    ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr;
   3339 	if (flags & IFF_POINTOPOINT) {
   3340 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3341 		if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
   3342 			if (errno == EADDRNOTAVAIL)
   3343 				(void) memset(&lifr.lifr_addr, 0,
   3344 				    sizeof (lifr.lifr_addr));
   3345 			else
   3346 				Perror0_exit("in_configinfo: SIOCGLIFDSTADDR");
   3347 		}
   3348 		sin = (struct sockaddr_in *)&lifr.lifr_dstaddr;
   3349 		(void) printf(" destination %s ", inet_ntoa(sin->sin_addr));
   3350 	}
   3351 	(void) printf(" netmask 0x%x ", ntohl(netmask.sin_addr.s_addr));
   3352 	if (flags & IFF_BROADCAST) {
   3353 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3354 		if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) {
   3355 			if (errno == EADDRNOTAVAIL)
   3356 				(void) memset(&lifr.lifr_addr, 0,
   3357 				    sizeof (lifr.lifr_addr));
   3358 			else
   3359 				Perror0_exit("in_configinfo: SIOCGLIFBRDADDR");
   3360 		}
   3361 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
   3362 		if (sin->sin_addr.s_addr != 0) {
   3363 			(void) printf(" broadcast %s ",
   3364 			    inet_ntoa(sin->sin_addr));
   3365 		}
   3366 	}
   3367 
   3368 	/* If there is a groupname, print it for only the zeroth interface */
   3369 	if (lifnum(name) == 0) {
   3370 		if (ioctl(s, SIOCGLIFGROUPNAME, &lifr) >= 0 &&
   3371 		    lifr.lifr_groupname[0] != '\0') {
   3372 			(void) printf(" group %s ", lifr.lifr_groupname);
   3373 		}
   3374 	}
   3375 
   3376 	/* Print flags to configure */
   3377 	print_config_flags(AF_INET, flags);
   3378 }
   3379 
   3380 static void
   3381 in6_configinfo(int force, uint64_t flags)
   3382 {
   3383 	char abuf[INET6_ADDRSTRLEN];
   3384 	struct sockaddr_in6 *sin6, *laddr6;
   3385 
   3386 	if (debug)
   3387 		(void) printf("in6_configinfo(%s) flags 0x%llx\n", name,
   3388 		    flags);
   3389 
   3390 	if (!(flags & IFF_IPV6))
   3391 		return;
   3392 
   3393 	if (!(flags & IFF_NOLOCAL)) {
   3394 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3395 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
   3396 			if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
   3397 			    errno == ENXIO) {
   3398 				if (!force)
   3399 					return;
   3400 				(void) memset(&lifr.lifr_addr, 0,
   3401 				    sizeof (lifr.lifr_addr));
   3402 			} else
   3403 				Perror0_exit("in6_configinfo: SIOCGLIFADDR");
   3404 		}
   3405 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
   3406 		(void) printf(" set %s/%d ",
   3407 		    inet_ntop(AF_INET6, &sin6->sin6_addr, abuf, sizeof (abuf)),
   3408 		    lifr.lifr_addrlen);
   3409 		laddr6 = sin6;
   3410 	}
   3411 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3412 	if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
   3413 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
   3414 		    errno == ENXIO) {
   3415 			if (!force)
   3416 				return;
   3417 			(void) memset(&lifr.lifr_addr, 0,
   3418 			    sizeof (lifr.lifr_addr));
   3419 		} else
   3420 			Perror0_exit("in6_configinfo: SIOCGLIFSUBNET");
   3421 	}
   3422 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
   3423 	if ((flags & IFF_NOLOCAL) ||
   3424 	    !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) {
   3425 		(void) printf(" subnet %s/%d ",
   3426 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
   3427 		    abuf, sizeof (abuf)),
   3428 		    lifr.lifr_addrlen);
   3429 	}
   3430 
   3431 	if (flags & IFF_POINTOPOINT) {
   3432 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3433 		if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
   3434 			if (errno == EADDRNOTAVAIL)
   3435 				(void) memset(&lifr.lifr_addr, 0,
   3436 				    sizeof (lifr.lifr_addr));
   3437 			else
   3438 				Perror0_exit("in6_configinfo: SIOCGLIFDSTADDR");
   3439 		}
   3440 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr;
   3441 		(void) printf(" destination %s ",
   3442 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
   3443 		    abuf, sizeof (abuf)));
   3444 	}
   3445 
   3446 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3447 	if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) {
   3448 		if (errno == EADDRNOTAVAIL || errno == EINVAL)
   3449 			(void) memset(&lifr.lifr_addr, 0,
   3450 			    sizeof (lifr.lifr_addr));
   3451 		else
   3452 			Perror0_exit("in6_configinfo: SIOCGLIFTOKEN");
   3453 	} else {
   3454 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
   3455 		(void) printf(" token %s/%d ",
   3456 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
   3457 		    abuf, sizeof (abuf)),
   3458 		    lifr.lifr_addrlen);
   3459 	}
   3460 
   3461 	/* If there is a groupname, print it for only the zeroth interface */
   3462 	if (lifnum(name) == 0) {
   3463 		if (ioctl(s, SIOCGLIFGROUPNAME, &lifr) >= 0 &&
   3464 		    lifr.lifr_groupname[0] != '\0') {
   3465 			(void) printf(" group %s ", lifr.lifr_groupname);
   3466 		}
   3467 	}
   3468 
   3469 	/* Print flags to configure */
   3470 	print_config_flags(AF_INET6, flags);
   3471 }
   3472 
   3473 /*
   3474  * We need to plink both the arp-device stream and the arp-ip-device stream.
   3475  * However the muxid is stored only in IP. Plumbing 2 streams individually
   3476  * is not atomic, and if ifconfig is killed, the resulting plumbing can
   3477  * be inconsistent. For eg. if only the arp stream is plumbed, we have lost
   3478  * the muxid, and the half-baked plumbing can neither be unplumbed nor
   3479  * replumbed, thus requiring a reboot. To avoid the above the following
   3480  * scheme is used.
   3481  *
   3482  * Ifconfig asks IP to enforce atomicity of plumbing the arp and IP streams.
   3483  * This is done by pushing arp on to the mux (/dev/udp). ARP adds some
   3484  * extra information in the I_PLINK and I_PUNLINK ioctls to let IP know
   3485  * that the plumbing/unplumbing has to be done atomically. Ifconfig plumbs
   3486  * the IP stream first, and unplumbs it last. The kernel (IP) does not
   3487  * allow IP stream to be unplumbed without unplumbing arp stream. Similarly
   3488  * it does not allow arp stream to be plumbed before IP stream is plumbed.
   3489  * There is no need to use SIOCSLIFMUXID, since the whole operation is atomic,
   3490  * and IP uses the info in the I_PLINK message to get the muxid.
   3491  *
   3492  * a. STREAMS does not allow us to use /dev/ip itself as the mux. So we use
   3493  *    /dev/udp{,6}.
   3494  * b. SIOCGLIFMUXID returns the muxid corresponding to the V4 or V6 stream
   3495  *    depending on the open i.e. V4 vs V6 open. So we need to use /dev/udp
   3496  *    or /dev/udp6 for SIOCGLIFMUXID and SIOCSLIFMUXID.
   3497  * c. We need to push ARP in order to get the required kernel support for
   3498  *    atomic plumbings. The actual work done by ARP is explained in arp.c
   3499  *    Without pushing ARP, we will still be able to plumb/unplumb. But
   3500  *    it is not atomic, and is supported by the kernel for backward
   3501  *    compatibility for other utilities like atmifconfig etc. In this case
   3502  *    the utility must use SIOCSLIFMUXID.
   3503  */
   3504 static int
   3505 ifplumb(const char *linkname, const char *ifname, boolean_t genppa, int af)
   3506 {
   3507 	int	arp_muxid = -1, ip_muxid;
   3508 	int	mux_fd, ip_fd, arp_fd;
   3509 	int 	retval;
   3510 	char	*udp_dev_name;
   3511 	uint64_t flags;
   3512 	uint_t	dlpi_flags;
   3513 	dlpi_handle_t	dh_arp, dh_ip;
   3514 
   3515 	/*
   3516 	 * Always dlpi_open() with DLPI_NOATTACH because the IP and ARP module
   3517 	 * will do the attach themselves for DLPI style-2 links.
   3518 	 */
   3519 	dlpi_flags = DLPI_NOATTACH;
   3520 
   3521 	/*
   3522 	 * If `linkname' is the special token IPMPSTUB, then this is a request
   3523 	 * to create an IPMP interface atop /dev/ipmpstub0.  (We can't simply
   3524 	 * pass "ipmpstub0" as `linkname' since an admin *could* have a normal
   3525 	 * vanity-named link named "ipmpstub0" that they'd like to plumb.)
   3526 	 */
   3527 	if (linkname == IPMPSTUB) {
   3528 		linkname = "ipmpstub0";
   3529 		dlpi_flags |= DLPI_DEVONLY;
   3530 	}
   3531 
   3532 	retval = dlpi_open(linkname, &dh_ip, dlpi_flags);
   3533 	if (retval != DLPI_SUCCESS)
   3534 		Perrdlpi_exit("cannot open link", linkname, retval);
   3535 
   3536 	if (debug) {
   3537 		(void) printf("ifconfig: ifplumb: link %s, ifname %s, "
   3538 		    "genppa %u\n", linkname, ifname, genppa);
   3539 	}
   3540 
   3541 	ip_fd = dlpi_fd(dh_ip);
   3542 	if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1)
   3543 		Perror2_exit("I_PUSH", IP_MOD_NAME);
   3544 
   3545 	/*
   3546 	 * Prepare to set IFF_IPV4/IFF_IPV6 flags as part of SIOCSLIFNAME.
   3547 	 * (At this point in time the kernel also allows an override of the
   3548 	 * IFF_CANTCHANGE flags.)
   3549 	 */
   3550 	lifr.lifr_name[0] = '\0';
   3551 	if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1)
   3552 		Perror0_exit("ifplumb: SIOCGLIFFLAGS");
   3553 
   3554 	if (af == AF_INET6) {
   3555 		flags = lifr.lifr_flags | IFF_IPV6;
   3556 		flags &= ~(IFF_BROADCAST | IFF_IPV4);
   3557 	} else {
   3558 		flags = lifr.lifr_flags | IFF_IPV4;
   3559 		flags &= ~IFF_IPV6;
   3560 	}
   3561 
   3562 	/*
   3563 	 * Set the interface name.  If we've been asked to generate the PPA,
   3564 	 * then find the lowest available PPA (only currently used for IPMP
   3565 	 * interfaces).  Otherwise, use the interface name as-is.
   3566 	 */
   3567 	if (genppa) {
   3568 		int ppa;
   3569 
   3570 		/*
   3571 		 * We'd like to just set lifr_ppa to UINT_MAX and have the
   3572 		 * kernel pick a PPA.  Unfortunately, that would mishandle
   3573 		 * two cases:
   3574 		 *
   3575 		 *	1. If the PPA is available but the groupname is taken
   3576 		 *	   (e.g., the "ipmp2" IP interface name is available
   3577 		 *	   but the "ipmp2" groupname is taken) then the
   3578 		 *	   auto-assignment by the kernel will fail.
   3579 		 *
   3580 		 *	2. If we're creating (e.g.) an IPv6-only IPMP
   3581 		 *	   interface, and there's already an IPv4-only IPMP
   3582 		 *	   interface, the kernel will allow us to accidentally
   3583 		 *	   reuse the IPv6 IPMP interface name (since
   3584 		 *	   SIOCSLIFNAME uniqueness is per-interface-type).
   3585 		 *	   This will cause administrative confusion.
   3586 		 *
   3587 		 * Thus, we instead take a brute-force approach of checking
   3588 		 * whether the IPv4 or IPv6 name is already in-use before
   3589 		 * attempting the SIOCSLIFNAME.  As per (1) above, the
   3590 		 * SIOCSLIFNAME may still fail, in which case we just proceed
   3591 		 * to the next one.  If this approach becomes too slow, we
   3592 		 * can add a new SIOC* to handle this case in the kernel.
   3593 		 */
   3594 		for (ppa = 0; ppa < UINT_MAX; ppa++) {
   3595 			(void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d",
   3596 			    ifname, ppa);
   3597 
   3598 			if (ioctl(s4, SIOCGLIFFLAGS, &lifr) != -1 ||
   3599 			    errno != ENXIO)
   3600 				continue;
   3601 
   3602 			if (ioctl(s6, SIOCGLIFFLAGS, &lifr) != -1 ||
   3603 			    errno != ENXIO)
   3604 				continue;
   3605 
   3606 			lifr.lifr_ppa = ppa;
   3607 			lifr.lifr_flags = flags;
   3608 			retval = ioctl(ip_fd, SIOCSLIFNAME, &lifr);
   3609 			if (retval != -1 || errno != EEXIST)
   3610 				break;
   3611 		}
   3612 	} else {
   3613 		ifspec_t ifsp;
   3614 
   3615 		/*
   3616 		 * The interface name could have come from the command-line;
   3617 		 * check it.
   3618 		 */
   3619 		if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
   3620 			Perror2_exit("invalid IP interface name", ifname);
   3621 
   3622 		/*
   3623 		 * Before we call SIOCSLIFNAME, ensure that the IPMP group
   3624 		 * interface for this address family exists.  Otherwise, the
   3625 		 * kernel will kick the interface out of the group when we do
   3626 		 * the SIOCSLIFNAME.
   3627 		 *
   3628 		 * Example: suppose bge0 is plumbed for IPv4 and in group "a".
   3629 		 * If we're now plumbing bge0 for IPv6, but the IPMP group
   3630 		 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME
   3631 		 * will kick bge0 out of group "a", which is undesired.
   3632 		 */
   3633 		if (create_ipmp_peer(af, ifname) == -1) {
   3634 			(void) fprintf(stderr, "ifconfig: warning: cannot "
   3635 			    "create %s IPMP group; %s will be removed from "
   3636 			    "group\n", af == AF_INET ? "IPv4" : "IPv6", ifname);
   3637 		}
   3638 
   3639 		lifr.lifr_ppa = ifsp.ifsp_ppa;
   3640 		lifr.lifr_flags = flags;
   3641 		(void) strlcpy(lifr.lifr_name, ifname, LIFNAMSIZ);
   3642 		retval = ioctl(ip_fd, SIOCSLIFNAME, &lifr);
   3643 	}
   3644 
   3645 	if (retval == -1) {
   3646 		if (errno != EEXIST)
   3647 			Perror0_exit("SIOCSLIFNAME for ip");
   3648 		/*
   3649 		 * This difference between the way we behave for EEXIST
   3650 		 * and that with other errors exists to preserve legacy
   3651 		 * behaviour. Earlier when foreachinterface() and matchif()
   3652 		 * were doing the duplicate interface name checks, for
   3653 		 * already existing interfaces, inetplumb() returned "0".
   3654 		 * To preserve this behaviour, Perror0() and return are
   3655 		 * called for EEXIST.
   3656 		 */
   3657 		Perror0("SIOCSLIFNAME for ip");
   3658 		return (-1);
   3659 	}
   3660 
   3661 	/* Get the full set of existing flags for this stream */
   3662 	if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1)
   3663 		Perror0_exit("ifplumb: SIOCGLIFFLAGS");
   3664 
   3665 	if (debug) {
   3666 		(void) printf("ifconfig: ifplumb: %s got flags:\n",
   3667 		    lifr.lifr_name);
   3668 		print_flags(lifr.lifr_flags);
   3669 		(void) putchar('\n');
   3670 	}
   3671 
   3672 	/*
   3673 	 * Open "/dev/udp" for use as a multiplexor to PLINK the
   3674 	 * interface stream under. We use "/dev/udp" instead of "/dev/ip"
   3675 	 * since STREAMS will not let you PLINK a driver under itself,
   3676 	 * and "/dev/ip" is typically the driver at the bottom of
   3677 	 * the stream for tunneling interfaces.
   3678 	 */
   3679 	if (af == AF_INET6)
   3680 		udp_dev_name = UDP6_DEV_NAME;
   3681 	else
   3682 		udp_dev_name = UDP_DEV_NAME;
   3683 	if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1)
   3684 		exit(EXIT_FAILURE);
   3685 
   3686 	/* Check if arp is not needed */
   3687 	if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) {
   3688 		/*
   3689 		 * PLINK the interface stream so that ifconfig can exit
   3690 		 * without tearing down the stream.
   3691 		 */
   3692 		if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1)
   3693 			Perror0_exit("I_PLINK for ip");
   3694 		(void) close(mux_fd);
   3695 		return (lifr.lifr_ppa);
   3696 	}
   3697 
   3698 	/*
   3699 	 * This interface does use ARP, so set up a separate stream
   3700 	 * from the interface to ARP.
   3701 	 */
   3702 	if (debug)
   3703 		(void) printf("ifconfig: ifplumb: interface %s", ifname);
   3704 
   3705 	retval = dlpi_open(linkname, &dh_arp, dlpi_flags);
   3706 	if (retval != DLPI_SUCCESS)
   3707 		Perrdlpi_exit("cannot open link", linkname, retval);
   3708 
   3709 	arp_fd = dlpi_fd(dh_arp);
   3710 	if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1)
   3711 		Perror2_exit("I_PUSH", ARP_MOD_NAME);
   3712 
   3713 	/*
   3714 	 * Tell ARP the name and unit number for this interface.
   3715 	 * Note that arp has no support for transparent ioctls.
   3716 	 */
   3717 	if (strioctl(arp_fd, SIOCSLIFNAME, &lifr, sizeof (lifr)) == -1) {
   3718 		if (errno != EEXIST)
   3719 			Perror0_exit("SIOCSLIFNAME for arp");
   3720 		Perror0("SIOCSLIFNAME for arp");
   3721 		goto out;
   3722 	}
   3723 
   3724 	/*
   3725 	 * PLINK the IP and ARP streams so that ifconfig can exit
   3726 	 * without tearing down the stream.
   3727 	 */
   3728 	if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1)
   3729 		Perror0_exit("I_PLINK for ip");
   3730 	if ((arp_muxid = ioctl(mux_fd, I_PLINK, arp_fd)) == -1) {
   3731 		(void) ioctl(mux_fd, I_PUNLINK, ip_muxid);
   3732 		Perror0_exit("I_PLINK for arp");
   3733 	}
   3734 
   3735 	if (debug)
   3736 		(void) printf("arp muxid = %d\n", arp_muxid);
   3737 out:
   3738 	dlpi_close(dh_ip);
   3739 	dlpi_close(dh_arp);
   3740 	(void) close(mux_fd);
   3741 	return (lifr.lifr_ppa);
   3742 }
   3743 
   3744 /*
   3745  * If this is a physical interface then remove it.
   3746  * If it is a logical interface name use SIOCLIFREMOVEIF to
   3747  * remove it. In both cases fail if it doesn't exist.
   3748  */
   3749 /* ARGSUSED */
   3750 static int
   3751 inetunplumb(char *arg, int64_t param)
   3752 {
   3753 	int ip_muxid, arp_muxid;
   3754 	int mux_fd;
   3755 	int muxid_fd;
   3756 	char *udp_dev_name;
   3757 	char *strptr;
   3758 	uint64_t flags;
   3759 	boolean_t changed_arp_muxid = _B_FALSE;
   3760 	int save_errno;
   3761 	boolean_t v6 = (afp->af_af == AF_INET6);
   3762 
   3763 	strptr = strchr(name, ':');
   3764 	if (strptr != NULL || strcmp(name, LOOPBACK_IF) == 0) {
   3765 		/* Can't unplumb logical interface zero */
   3766 		if (strptr != NULL && strcmp(strptr, ":0") == 0) {
   3767 			(void) fprintf(stderr, "ifconfig: unplumb:"
   3768 			    " Cannot unplumb %s: Invalid interface\n", name);
   3769 			exit(1);
   3770 		}
   3771 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3772 		(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
   3773 
   3774 		if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0)
   3775 			Perror0_exit("unplumb: SIOCLIFREMOVEIF");
   3776 		return (0);
   3777 	}
   3778 
   3779 	/*
   3780 	 * We used /dev/udp or udp6 to set up the mux. So we have to use
   3781 	 * the same now for PUNLINK also.
   3782 	 */
   3783 	if (v6)
   3784 		udp_dev_name = UDP6_DEV_NAME;
   3785 	else
   3786 		udp_dev_name = UDP_DEV_NAME;
   3787 
   3788 	if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1)
   3789 		exit(EXIT_FAILURE);
   3790 
   3791 	if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1)
   3792 		exit(EXIT_FAILURE);
   3793 
   3794 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3795 	if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
   3796 		Perror0_exit("unplumb: SIOCGLIFFLAGS");
   3797 	}
   3798 	flags = lifr.lifr_flags;
   3799 again:
   3800 	if (flags & IFF_IPMP) {
   3801 		lifgroupinfo_t lifgr;
   3802 		ifaddrlistx_t *ifaddrs, *ifaddrp;
   3803 
   3804 		/*
   3805 		 * There are two reasons the I_PUNLINK can fail with EBUSY:
   3806 		 * (1) if IP interfaces are in the group, or (2) if IPMP data
   3807 		 * addresses are administratively up.  For case (1), we fail
   3808 		 * here with a specific error message.  For case (2), we bring
   3809 		 * down the addresses prior to doing the I_PUNLINK.  If the
   3810 		 * I_PUNLINK still fails with EBUSY then the configuration
   3811 		 * must have changed after our checks, in which case we branch
   3812 		 * back up to `again' and rerun this logic.  The net effect is
   3813 		 * that unplumbing an IPMP interface will only fail with EBUSY
   3814 		 * if IP interfaces are in the group.
   3815 		 */
   3816 		if (ioctl(s, SIOCGLIFGROUPNAME, &lifr) == -1)
   3817 			Perror0_exit("unplumb: SIOCGLIFGROUPNAME");
   3818 
   3819 		(void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname,
   3820 		    LIFGRNAMSIZ);
   3821 		if (ioctl(s, SIOCGLIFGROUPINFO, &lifgr) == -1)
   3822 			Perror0_exit("unplumb: SIOCGLIFGROUPINFO");
   3823 
   3824 		if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) {
   3825 			(void) fprintf(stderr, "ifconfig: %s: cannot unplumb:"
   3826 			    " IPMP group is not empty\n", name);
   3827 			exit(1);
   3828 		}
   3829 
   3830 		/*
   3831 		 * The kernel will fail the I_PUNLINK if the IPMP interface
   3832 		 * has administratively up addresses; bring 'em down.
   3833 		 */
   3834 		if (ifaddrlistx(name, IFF_UP|IFF_DUPLICATE, 0, &ifaddrs) == -1)
   3835 			Perror2_exit(name, "cannot get address list");
   3836 
   3837 		ifaddrp = ifaddrs;
   3838 		for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
   3839 			if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) ||
   3840 			    (!(ifaddrp->ia_flags & IFF_IPV6) && v6))
   3841 				continue;
   3842 
   3843 			if (!ifaddr_down(ifaddrp)) {
   3844 				Perror2_exit(ifaddrp->ia_name,
   3845 				    "cannot bring down");
   3846 			}
   3847 		}
   3848 		ifaddrlistx_free(ifaddrs);
   3849 	}
   3850 
   3851 	if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
   3852 		Perror0_exit("unplumb: SIOCGLIFMUXID");
   3853 	}
   3854 	arp_muxid = lifr.lifr_arp_muxid;
   3855 	ip_muxid = lifr.lifr_ip_muxid;
   3856 	/*
   3857 	 * We don't have a good way of knowing whether the arp stream is
   3858 	 * plumbed. We can't rely on IFF_NOARP because someone could
   3859 	 * have turned it off later using "ifconfig xxx -arp".
   3860 	 */
   3861 	if (arp_muxid != 0) {
   3862 		if (debug)
   3863 			(void) printf("arp_muxid %d\n", arp_muxid);
   3864 		if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) {
   3865 			/*
   3866 			 * See the comment before the SIOCGLIFGROUPNAME call.
   3867 			 */
   3868 			if (errno == EBUSY && (flags & IFF_IPMP))
   3869 				goto again;
   3870 
   3871 			if ((errno == EINVAL) &&
   3872 			    (flags & (IFF_NOARP | IFF_IPV6))) {
   3873 				/*
   3874 				 * Some plumbing utilities set the muxid to
   3875 				 * -1 or some invalid value to signify that
   3876 				 * there is no arp stream. Set the muxid to 0
   3877 				 * before trying to unplumb the IP stream.
   3878 				 * IP does not allow the IP stream to be
   3879 				 * unplumbed if it sees a non-null arp muxid,
   3880 				 * for consistency of IP-ARP streams.
   3881 				 */
   3882 				lifr.lifr_arp_muxid = 0;
   3883 				(void) ioctl(muxid_fd, SIOCSLIFMUXID,
   3884 				    (caddr_t)&lifr);
   3885 				changed_arp_muxid = _B_TRUE;
   3886 			} else {
   3887 				Perror0("I_PUNLINK for arp");
   3888 			}
   3889 		}
   3890 	}
   3891 	if (debug)
   3892 		(void) printf("ip_muxid %d\n", ip_muxid);
   3893 
   3894 	if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) {
   3895 		if (changed_arp_muxid) {
   3896 			/*
   3897 			 * Some error occurred, and we need to restore
   3898 			 * everything back to what it was.
   3899 			 */
   3900 			save_errno = errno;
   3901 			lifr.lifr_arp_muxid = arp_muxid;
   3902 			lifr.lifr_ip_muxid = ip_muxid;
   3903 			(void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
   3904 			errno = save_errno;
   3905 		}
   3906 
   3907 		/*
   3908 		 * See the comment before the SIOCGLIFGROUPNAME call.
   3909 		 */
   3910 		if (errno == EBUSY && (flags & IFF_IPMP))
   3911 			goto again;
   3912 
   3913 		Perror0_exit("I_PUNLINK for ip");
   3914 	}
   3915 	(void) close(mux_fd);
   3916 	(void) close(muxid_fd);
   3917 	return (0);
   3918 }
   3919 
   3920 /*
   3921  * If this is a physical interface then create it unless it is already
   3922  * present. If it is a logical interface name use SIOCLIFADDIF to
   3923  * create and (and fail it if already exists.)
   3924  * As a special case send SIOCLIFADDIF for the loopback interface. This
   3925  * is needed since there is no other notion of plumbing the loopback
   3926  * interface.
   3927  */
   3928 /* ARGSUSED */
   3929 static int
   3930 inetplumb(char *arg, int64_t param)
   3931 {
   3932 	char		*strptr;
   3933 	boolean_t	islo;
   3934 	zoneid_t	zoneid;
   3935 	datalink_id_t	linkid;
   3936 
   3937 	strptr = strchr(name, ':');
   3938 	islo = (strcmp(name, LOOPBACK_IF) == 0);
   3939 
   3940 	if (strptr != NULL || islo) {
   3941 		(void) memset(&lifr, 0, sizeof (lifr));
   3942 		(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   3943 		if (islo && ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0) {
   3944 			if (debug) {
   3945 				(void) fprintf(stderr,
   3946 				    "ifconfig: %s already exists\n", name);
   3947 			}
   3948 			return (0);
   3949 		}
   3950 		if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) {
   3951 			if (errno == EEXIST) {
   3952 				if (debug) {
   3953 					(void) fprintf(stderr,
   3954 					    "ifconfig: %s already exists\n",
   3955 					    name);
   3956 				}
   3957 			} else {
   3958 				Perror2_exit("plumb: SIOCLIFADDIF", name);
   3959 			}
   3960 		}
   3961 		return (0);
   3962 	}
   3963 
   3964 	/*
   3965 	 * If we're in the global zone and we're plumbing a datalink, make
   3966 	 * sure that the datalink is not assigned to a non-global zone.  Note
   3967 	 * that the non-global zones don't need this check, because zoneadm
   3968 	 * has taken care of this when the zones boot.
   3969 	 */
   3970 	zoneid = getzoneid();
   3971 	if (zoneid == GLOBAL_ZONEID &&
   3972 	    ifconfig_dladm_open(name, DATALINK_CLASS_ALL, &linkid) ==
   3973 	    DLADM_STATUS_OK) {
   3974 		int ret;
   3975 
   3976 		zoneid = ALL_ZONES;
   3977 		ret = zone_check_datalink(&zoneid, linkid);
   3978 		if (ret == 0) {
   3979 			char zonename[ZONENAME_MAX];
   3980 
   3981 			(void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX);
   3982 			(void) fprintf(stderr, "%s is used by non-global"
   3983 			    "zone: %s\n", name, zonename);
   3984 			return (1);
   3985 		}
   3986 	}
   3987 
   3988 	if (debug)
   3989 		(void) printf("inetplumb: %s af %d\n", name, afp->af_af);
   3990 
   3991 	(void) ifplumb(name, name, _B_FALSE, afp->af_af);
   3992 	return (0);
   3993 }
   3994 
   3995 /* ARGSUSED */
   3996 static int
   3997 inetipmp(char *arg, int64_t param)
   3998 {
   3999 	int retval;
   4000 
   4001 	/*
   4002 	 * Treat e.g. "ifconfig ipmp0:2 ipmp" as "ifconfig ipmp0:2 plumb".
   4003 	 * Otherwise, try to create the requested IPMP interface.
   4004 	 */
   4005 	if (strchr(name, ':') != NULL)
   4006 		retval = inetplumb(arg, param);
   4007 	else
   4008 		retval = create_ipmp(name, afp->af_af, name, _B_FALSE);
   4009 
   4010 	/*
   4011 	 * We'd return -1, but foreachinterface() doesn't propagate the error
   4012 	 * into the exit status, so we're forced to explicitly exit().
   4013 	 */
   4014 	if (retval == -1)
   4015 		exit(1);
   4016 	return (0);
   4017 }
   4018 
   4019 /*
   4020  * Create an IPMP group `grname' with address family `af'.  If `ifname' is
   4021  * non-NULL, it specifies the interface name to use.  Otherwise, use the name
   4022  * ipmpN, where N corresponds to the lowest available integer.  If `implicit'
   4023  * is set, then the group is being created as a side-effect of placing an
   4024  * underlying interface in a group.  Also start in.mpathd if necessary.
   4025  */
   4026 static int
   4027 create_ipmp(const char *grname, int af, const char *ifname, boolean_t implicit)
   4028 {
   4029 	int ppa;
   4030 	static int ipmp_daemon_started;
   4031 
   4032 	if (debug) {
   4033 		(void) printf("create_ipmp: ifname %s grname %s af %d\n",
   4034 		    ifname != NULL ? ifname : "NULL", grname, af);
   4035 	}
   4036 
   4037 	if (ifname != NULL)
   4038 		ppa = ifplumb(IPMPSTUB, ifname, _B_FALSE, af);
   4039 	else
   4040 		ppa = ifplumb(IPMPSTUB, "ipmp", _B_TRUE, af);
   4041 
   4042 	if (ppa == -1) {
   4043 		Perror2(grname, "cannot create IPMP interface");
   4044 		return (-1);
   4045 	}
   4046 
   4047 	if (ifname != NULL)
   4048 		(void) strlcpy(lifr.lifr_name, ifname, LIFNAMSIZ);
   4049 	else
   4050 		(void) snprintf(lifr.lifr_name, LIFNAMSIZ, "ipmp%d", ppa);
   4051 
   4052 	/*
   4053 	 * To preserve backward-compatibility, always bring up the link-local
   4054 	 * address for implicitly-created IPv6 IPMP interfaces.
   4055 	 */
   4056 	if (implicit && af == AF_INET6) {
   4057 		if (ioctl(s6, SIOCGLIFFLAGS, &lifr) == 0) {
   4058 			lifr.lifr_flags |= IFF_UP;
   4059 			(void) ioctl(s6, SIOCSLIFFLAGS, &lifr);
   4060 		}
   4061 	}
   4062 
   4063 	/*
   4064 	 * If the caller requested a different group name, issue a
   4065 	 * SIOCSLIFGROUPNAME on the new IPMP interface.
   4066 	 */
   4067 	if (strcmp(lifr.lifr_name, grname) != 0) {
   4068 		(void) strlcpy(lifr.lifr_groupname, grname, LIFGRNAMSIZ);
   4069 		if (ioctl(s, SIOCSLIFGROUPNAME, &lifr) == -1) {
   4070 			Perror0("SIOCSLIFGROUPNAME");
   4071 			return (-1);
   4072 		}
   4073 	}
   4074 
   4075 	/*
   4076 	 * If we haven't done so yet, ensure in.mpathd is started.
   4077 	 */
   4078 	if (ipmp_daemon_started++ == 0)
   4079 		start_ipmp_daemon();
   4080 
   4081 	return (0);
   4082 }
   4083 
   4084 /*
   4085  * Check if `ifname' is plumbed and in an IPMP group on its "other" address
   4086  * family.  If so, create a matching IPMP group for address family `af'.
   4087  */
   4088 static int
   4089 create_ipmp_peer(int af, const char *ifname)
   4090 {
   4091 	int		fd;
   4092 	lifgroupinfo_t	lifgr;
   4093 
   4094 	assert(af == AF_INET || af == AF_INET6);
   4095 
   4096 	/*
   4097 	 * Get the socket for the "other" address family.
   4098 	 */
   4099 	fd = (af == AF_INET) ? s6 : s4;
   4100 
   4101 	(void) strlcpy(lifr.lifr_name, ifname, LIFNAMSIZ);
   4102 	if (ioctl(fd, SIOCGLIFGROUPNAME, &lifr) != 0)
   4103 		return (0);
   4104 
   4105 	(void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ);
   4106 	if (ioctl(fd, SIOCGLIFGROUPINFO, &lifgr) != 0)
   4107 		return (0);
   4108 
   4109 	/*
   4110 	 * If `ifname' *is* the IPMP group interface, or if the relevant
   4111 	 * address family is already configured, then there's nothing to do.
   4112 	 */
   4113 	if (strcmp(lifgr.gi_grifname, ifname) == 0 ||
   4114 	    (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6))
   4115 		return (0);
   4116 
   4117 	return (create_ipmp(lifgr.gi_grname, af, lifgr.gi_grifname, _B_TRUE));
   4118 }
   4119 
   4120 /*
   4121  * Start in.mpathd if it's not already running.
   4122  */
   4123 static void
   4124 start_ipmp_daemon(void)
   4125 {
   4126 	int retval;
   4127 	ipmp_handle_t ipmp_handle;
   4128 
   4129 	/*
   4130 	 * Ping in.mpathd to see if it's running already.
   4131 	 */
   4132 	if ((retval = ipmp_open(&ipmp_handle)) != IPMP_SUCCESS) {
   4133 		(void) fprintf(stderr, "ifconfig: cannot create IPMP handle: "
   4134 		    "%s\n", ipmp_errmsg(retval));
   4135 		return;
   4136 	}
   4137 
   4138 	retval = ipmp_ping_daemon(ipmp_handle);
   4139 	ipmp_close(ipmp_handle);
   4140 
   4141 	switch (retval) {
   4142 	case IPMP_ENOMPATHD:
   4143 		break;
   4144 	case IPMP_SUCCESS:
   4145 		return;
   4146 	default:
   4147 		(void) fprintf(stderr, "ifconfig: cannot ping in.mpathd: %s\n",
   4148 		    ipmp_errmsg(retval));
   4149 		break;
   4150 	}
   4151 
   4152 	/*
   4153 	 * Start in.mpathd.  Note that in.mpathd will handle multiple
   4154 	 * incarnations (ipmp_ping_daemon() is just an optimization) so we
   4155 	 * don't need to worry about racing with another ifconfig process.
   4156 	 */
   4157 	switch (fork()) {
   4158 	case -1:
   4159 		Perror0_exit("start_ipmp_daemon: fork");
   4160 		/* NOTREACHED */
   4161 	case 0:
   4162 		(void) execl(MPATHD_PATH, MPATHD_PATH, NULL);
   4163 		_exit(1);
   4164 		/* NOTREACHED */
   4165 	default:
   4166 		break;
   4167 	}
   4168 }
   4169 
   4170 /*
   4171  * Bring the address named by `ifaddrp' up or down.  Doesn't trust any mutable
   4172  * values in ia_flags since they may be stale.
   4173  */
   4174 static boolean_t
   4175 ifaddr_op(ifaddrlistx_t *ifaddrp, boolean_t up)
   4176 {
   4177 	struct lifreq	lifrl;	/* Local lifreq struct */
   4178 	int		fd = (ifaddrp->ia_flags & IFF_IPV4) ? s4 : s6;
   4179 
   4180 	(void) memset(&lifrl, 0, sizeof (lifrl));
   4181 	(void) strlcpy(lifrl.lifr_name, ifaddrp->ia_name, LIFNAMSIZ);
   4182 	if (ioctl(fd, SIOCGLIFFLAGS, &lifrl) == -1)
   4183 		return (_B_FALSE);
   4184 
   4185 	if (up)
   4186 		lifrl.lifr_flags |= IFF_UP;
   4187 	else
   4188 		lifrl.lifr_flags &= ~IFF_UP;
   4189 
   4190 	if (ioctl(fd, SIOCSLIFFLAGS, &lifrl) == -1)
   4191 		return (_B_FALSE);
   4192 
   4193 	/*
   4194 	 * If we're trying to bring the address down, ensure that DAD activity
   4195 	 * (observable by IFF_DUPLICATE) has also been stopped.
   4196 	 */
   4197 	if (!up && ioctl(fd, SIOCGLIFFLAGS, &lifrl) != -1 &&
   4198 	    lifrl.lifr_flags & IFF_DUPLICATE) {
   4199 		if (ioctl(fd, SIOCGLIFADDR, &lifrl) == -1 ||
   4200 		    ioctl(fd, SIOCSLIFADDR, &lifrl) == -1) {
   4201 			return (_B_FALSE);
   4202 		}
   4203 	}
   4204 	return (_B_TRUE);
   4205 }
   4206 
   4207 static boolean_t
   4208 ifaddr_up(ifaddrlistx_t *ifaddrp)
   4209 {
   4210 	return (ifaddr_op(ifaddrp, _B_TRUE));
   4211 }
   4212 
   4213 static boolean_t
   4214 ifaddr_down(ifaddrlistx_t *ifaddrp)
   4215 {
   4216 	return (ifaddr_op(ifaddrp, _B_FALSE));
   4217 }
   4218 
   4219 /*
   4220  * Open the global libdladm handle "dlh" if it isn't already opened.  The
   4221  * caller may optionally supply a link name to obtain its linkid.  If a link
   4222  * of a specific class or classes is required, reqclass specifies the class
   4223  * mask.
   4224  */
   4225 static dladm_status_t
   4226 ifconfig_dladm_open(const char *name, datalink_class_t reqclass,
   4227     datalink_id_t *linkid)
   4228 {
   4229 	dladm_status_t status = DLADM_STATUS_OK;
   4230 	datalink_class_t class;
   4231 
   4232 	if (!dlh_opened) {
   4233 		if ((status = dladm_open(&dlh)) != DLADM_STATUS_OK)
   4234 			return (status);
   4235 		dlh_opened = _B_TRUE;
   4236 	}
   4237 	if (name != NULL) {
   4238 		status = dladm_name2info(dlh, name, linkid, NULL, &class, NULL);
   4239 		if (status == DLADM_STATUS_OK) {
   4240 			if (!(class & reqclass))
   4241 				status = DLADM_STATUS_LINKINVAL;
   4242 		}
   4243 	}
   4244 	return (status);
   4245 }
   4246 
   4247 void
   4248 dladmerr_exit(dladm_status_t status, const char *str)
   4249 {
   4250 	char errstr[DLADM_STRSIZE];
   4251 
   4252 	(void) fprintf(stderr, "%s: %s\n", str,
   4253 	    dladm_status2str(status, errstr));
   4254 	exit(1);
   4255 }
   4256 
   4257 void
   4258 Perror0(const char *cmd)
   4259 {
   4260 	Perror2(cmd, lifr.lifr_name);
   4261 }
   4262 
   4263 void
   4264 Perror0_exit(const char *cmd)
   4265 {
   4266 	Perror0(cmd);
   4267 	exit(1);
   4268 }
   4269 
   4270 void
   4271 Perror2(const char *cmd, const char *str)
   4272 {
   4273 	int error = errno;
   4274 
   4275 	(void) fprintf(stderr, "ifconfig: %s: ", cmd);
   4276 
   4277 	switch (error) {
   4278 	case ENXIO:
   4279 		(void) fprintf(stderr, "%s: no such interface\n", str);
   4280 		break;
   4281 	case EPERM:
   4282 		(void) fprintf(stderr, "%s: permission denied\n", str);
   4283 		break;
   4284 	case EEXIST:
   4285 		(void) fprintf(stderr, "%s: already exists\n", str);
   4286 		break;
   4287 	default:
   4288 		errno = error;
   4289 		perror(str);
   4290 	}
   4291 }
   4292 
   4293 /*
   4294  * Print out error message (Perror2()) and exit
   4295  */
   4296 void
   4297 Perror2_exit(const char *cmd, const char *str)
   4298 {
   4299 	Perror2(cmd, str);
   4300 	exit(1);
   4301 	/* NOTREACHED */
   4302 }
   4303 
   4304 void
   4305 Perrdlpi(const char *cmd, const char *linkname, int err)
   4306 {
   4307 	(void) fprintf(stderr, "ifconfig: %s \"%s\": %s\n", cmd,
   4308 	    linkname, dlpi_strerror(err));
   4309 }
   4310 
   4311 /*
   4312  * Print out error message (Perrdlpi()) and exit
   4313  */
   4314 void
   4315 Perrdlpi_exit(const char *cmd, const char *linkname, int err)
   4316 {
   4317 	Perrdlpi(cmd, linkname, err);
   4318 	exit(1);
   4319 }
   4320 
   4321 /*
   4322  * If the last argument is non-NULL allow a <addr>/<n> syntax and
   4323  * pass out <n> in *plenp.
   4324  * If <n> doesn't parse return BAD_ADDR as *plenp.
   4325  * If no /<n> is present return NO_PREFIX as *plenp.
   4326  */
   4327 static void
   4328 in_getaddr(char *s, struct sockaddr *saddr, int *plenp)
   4329 {
   4330 	/* LINTED: alignment */
   4331 	struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
   4332 	struct hostent *hp;
   4333 	struct netent *np;
   4334 	char str[BUFSIZ];
   4335 	int error_num;
   4336 
   4337 	(void) strncpy(str, s, sizeof (str));
   4338 
   4339 	/*
   4340 	 * Look for '/'<n> is plenp
   4341 	 */
   4342 	if (plenp != NULL) {
   4343 		char *cp;
   4344 
   4345 		*plenp = in_getprefixlen(str, _B_TRUE, IP_ABITS);
   4346 		if (*plenp == BAD_ADDR)
   4347 			return;
   4348 		cp = strchr(str, '/');
   4349 		if (cp != NULL)
   4350 			*cp = '\0';
   4351 	} else if (strchr(str, '/') != NULL) {
   4352 		(void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str);
   4353 		exit(1);
   4354 	}
   4355 
   4356 	(void) memset(sin, 0, sizeof (*sin));
   4357 
   4358 	/*
   4359 	 *	Try to catch attempts to set the broadcast address to all 1's.
   4360 	 */
   4361 	if (strcmp(str, "255.255.255.255") == 0 ||
   4362 	    (strtoul(str, (char **)NULL, 0) == 0xffffffffUL)) {
   4363 		sin->sin_family = AF_INET;
   4364 		sin->sin_addr.s_addr = 0xffffffff;
   4365 		return;
   4366 	}
   4367 
   4368 	hp = getipnodebyname(str, AF_INET, 0, &error_num);
   4369 	if (hp) {
   4370 		sin->sin_family = hp->h_addrtype;
   4371 		(void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
   4372 		freehostent(hp);
   4373 		return;
   4374 	}
   4375 	np = getnetbyname(str);
   4376 	if (np) {
   4377 		sin->sin_family = np->n_addrtype;
   4378 		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
   4379 		return;
   4380 	}
   4381 	if (error_num == TRY_AGAIN) {
   4382 		(void) fprintf(stderr, "ifconfig: %s: bad address "
   4383 		    "(try again later)\n", s);
   4384 	} else {
   4385 		(void) fprintf(stderr, "ifconfig: %s: bad address\n", s);
   4386 	}
   4387 	exit(1);
   4388 }
   4389 
   4390 /*
   4391  * If the last argument is non-NULL allow a <addr>/<n> syntax and
   4392  * pass out <n> in *plenp.
   4393  * If <n> doesn't parse return BAD_ADDR as *plenp.
   4394  * If no /<n> is present return NO_PREFIX as *plenp.
   4395  */
   4396 static void
   4397 in6_getaddr(char *s, struct sockaddr *saddr, int *plenp)
   4398 {
   4399 	/* LINTED: alignment */
   4400 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr;
   4401 	struct hostent *hp;
   4402 	char str[BUFSIZ];
   4403 	int error_num;
   4404 
   4405 	(void) strncpy(str, s, sizeof (str));
   4406 
   4407 	/*
   4408 	 * Look for '/'<n> is plenp
   4409 	 */
   4410 	if (plenp != NULL) {
   4411 		char *cp;
   4412 
   4413 		*plenp = in_getprefixlen(str, _B_TRUE, IPV6_ABITS);
   4414 		if (*plenp == BAD_ADDR)
   4415 			return;
   4416 		cp = strchr(str, '/');
   4417 		if (cp != NULL)
   4418 			*cp = '\0';
   4419 	} else if (strchr(str, '/') != NULL) {
   4420 		(void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str);
   4421 		exit(1);
   4422 	}
   4423 
   4424 	(void) memset(sin6, 0, sizeof (*sin6));
   4425 
   4426 	hp = getipnodebyname(str, AF_INET6, 0, &error_num);
   4427 	if (hp) {
   4428 		sin6->sin6_family = hp->h_addrtype;
   4429 		(void) memcpy(&sin6->sin6_addr, hp->h_addr, hp->h_length);
   4430 		freehostent(hp);
   4431 		return;
   4432 	}
   4433 	if (error_num == TRY_AGAIN) {
   4434 		(void) fprintf(stderr, "ifconfig: %s: bad address "
   4435 		    "(try again later)\n", s);
   4436 	} else {
   4437 		(void) fprintf(stderr, "ifconfig: %s: bad address\n", s);
   4438 	}
   4439 	exit(1);
   4440 }
   4441 
   4442 /*
   4443  * If "slash" is zero this parses the whole string as
   4444  * an integer. With "slash" non zero it parses the tail part as an integer.
   4445  *
   4446  * If it is not a valid integer this returns BAD_ADDR.
   4447  * If there is /<n> present this returns NO_PREFIX.
   4448  */
   4449 static int
   4450 in_getprefixlen(char *addr, boolean_t slash, int max_plen)
   4451 {
   4452 	int prefixlen;
   4453 	char *str, *end;
   4454 
   4455 	if (slash) {
   4456 		str = strchr(addr, '/');
   4457 		if (str == NULL)
   4458 			return (NO_PREFIX);
   4459 		str++;
   4460 	} else
   4461 		str = addr;
   4462 
   4463 	prefixlen = strtol(str, &end, 10);
   4464 	if (prefixlen < 0)
   4465 		return (BAD_ADDR);
   4466 	if (str == end)
   4467 		return (BAD_ADDR);
   4468 	if (max_plen != 0 && max_plen < prefixlen)
   4469 		return (BAD_ADDR);
   4470 	return (prefixlen);
   4471 }
   4472 
   4473 /*
   4474  * Convert a prefix length to a mask.
   4475  * Returns 1 if ok. 0 otherwise.
   4476  * Assumes the mask array is zero'ed by the caller.
   4477  */
   4478 static boolean_t
   4479 in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask)
   4480 {
   4481 	if (prefixlen < 0 || prefixlen > maxlen)
   4482 		return (0);
   4483 
   4484 	while (prefixlen > 0) {
   4485 		if (prefixlen >= 8) {
   4486 			*mask++ = 0xFF;
   4487 			prefixlen -= 8;
   4488 			continue;
   4489 		}
   4490 		*mask |= 1 << (8 - prefixlen);
   4491 		prefixlen--;
   4492 	}
   4493 	return (1);
   4494 }
   4495 
   4496 static void
   4497 print_flags(uint64_t flags)
   4498 {
   4499 	boolean_t first = _B_TRUE;
   4500 	int cnt, i;
   4501 
   4502 	(void) printf("flags=%llx", flags);
   4503 	cnt = sizeof (if_flags_tbl) / sizeof (if_flags_t);
   4504 	for (i = 0; i < cnt; i++) {
   4505 		if (flags & if_flags_tbl[i].iff_value) {
   4506 			if (first) {
   4507 				(void) printf("<");
   4508 				first = _B_FALSE;
   4509 			} else {
   4510 				/*
   4511 				 * It has to be here and not with the
   4512 				 * printf below because for the last one,
   4513 				 * we don't want a comma before the ">".
   4514 				 */
   4515 				(void) printf(",");
   4516 			}
   4517 			(void) printf("%s", if_flags_tbl[i].iff_name);
   4518 		}
   4519 	}
   4520 	if (!first)
   4521 		(void) printf(">");
   4522 }
   4523 
   4524 static void
   4525 print_config_flags(int af, uint64_t flags)
   4526 {
   4527 	if_config_cmd_t *cmdp;
   4528 
   4529 	for (cmdp = if_config_cmd_tbl; cmdp->iff_flag != 0; cmdp++) {
   4530 		if ((flags & cmdp->iff_flag) &&
   4531 		    (cmdp->iff_af == AF_UNSPEC || cmdp->iff_af == af)) {
   4532 			(void) printf("%s ", cmdp->iff_name);
   4533 		}
   4534 	}
   4535 }
   4536 
   4537 /*
   4538  * Use the configured directory lookup mechanism (e.g. files/NIS/NIS+/...)
   4539  * to find the network mask.  Returns true if we found one to set.
   4540  *
   4541  * The parameter addr_set controls whether we should get the address of
   4542  * the working interface for the netmask query.  If addr_set is true,
   4543  * we will use the address provided.  Otherwise, we will find the working
   4544  * interface's address and use it instead.
   4545  */
   4546 static boolean_t
   4547 in_getmask(struct sockaddr_in *saddr, boolean_t addr_set)
   4548 {
   4549 	struct sockaddr_in ifaddr;
   4550 
   4551 	/*
   4552 	 * Read the address from the interface if it is not passed in.
   4553 	 */
   4554 	if (!addr_set) {
   4555 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   4556 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
   4557 			if (errno != EADDRNOTAVAIL) {
   4558 				(void) fprintf(stderr, "Need net number for "
   4559 				    "mask\n");
   4560 			}
   4561 			return (_B_FALSE);
   4562 		}
   4563 		ifaddr = *((struct sockaddr_in *)&lifr.lifr_addr);
   4564 	} else {
   4565 		ifaddr.sin_addr = saddr->sin_addr;
   4566 	}
   4567 	if (getnetmaskbyaddr(ifaddr.sin_addr, &saddr->sin_addr) == 0) {
   4568 		saddr->sin_family = AF_INET;
   4569 		return (_B_TRUE);
   4570 	}
   4571 	return (_B_FALSE);
   4572 }
   4573 
   4574 static int
   4575 lifnum(const char *ifname)
   4576 {
   4577 	const char *cp;
   4578 
   4579 	if ((cp = strchr(ifname, ':')) == NULL)
   4580 		return (0);
   4581 	else
   4582 		return (atoi(cp + 1));
   4583 }
   4584 
   4585 static int
   4586 strioctl(int s, int cmd, void *buf, int buflen)
   4587 {
   4588 	struct strioctl ioc;
   4589 
   4590 	(void) memset(&ioc, 0, sizeof (ioc));
   4591 	ioc.ic_cmd = cmd;
   4592 	ioc.ic_timout = 0;
   4593 	ioc.ic_len = buflen;
   4594 	ioc.ic_dp = buf;
   4595 	return (ioctl(s, I_STR, (char *)&ioc));
   4596 }
   4597 
   4598 static void
   4599 add_ni(const char *name)
   4600 {
   4601 	ni_t **pp;
   4602 	ni_t *p;
   4603 
   4604 	for (pp = &ni_list; (p = *pp) != NULL; pp = &(p->ni_next)) {
   4605 		if (strcmp(p->ni_name, name) == 0) {
   4606 			if (debug > 2)
   4607 				(void) fprintf(stderr, "'%s' is a duplicate\n",
   4608 				    name);
   4609 			return;
   4610 		}
   4611 	}
   4612 
   4613 	if (debug > 2)
   4614 		(void) fprintf(stderr, "adding '%s'\n",
   4615 		    name);
   4616 
   4617 	if ((p = malloc(sizeof (ni_t))) == NULL)
   4618 		return;
   4619 
   4620 	(void) strlcpy(p->ni_name, name, sizeof (p->ni_name));
   4621 	p->ni_next = NULL;
   4622 
   4623 	*pp = p;
   4624 	num_ni++;
   4625 }
   4626 
   4627 static boolean_t
   4628 ni_entry(const char *linkname, void *arg)
   4629 {
   4630 	dlpi_handle_t	dh;
   4631 	datalink_class_t class;
   4632 
   4633 	(void) dladm_name2info(arg, linkname, NULL, NULL, &class, NULL);
   4634 
   4635 	if (class == DATALINK_CLASS_ETHERSTUB)
   4636 		return (_B_FALSE);
   4637 	if (dlpi_open(linkname, &dh, 0) != DLPI_SUCCESS)
   4638 		return (_B_FALSE);
   4639 
   4640 	add_ni(linkname);
   4641 
   4642 	dlpi_close(dh);
   4643 	return (_B_FALSE);
   4644 }
   4645 
   4646 /*
   4647  * dhcp-related routines
   4648  */
   4649 
   4650 static int
   4651 setifdhcp(const char *caller, const char *ifname, int argc, char *argv[])
   4652 {
   4653 	dhcp_ipc_request_t	*request;
   4654 	dhcp_ipc_reply_t	*reply	= NULL;
   4655 	int			timeout = DHCP_IPC_WAIT_DEFAULT;
   4656 	dhcp_ipc_type_t		type	= DHCP_START;
   4657 	int			error;
   4658 	boolean_t		is_primary = _B_FALSE;
   4659 	boolean_t		started = _B_FALSE;
   4660 
   4661 	for (argv++; --argc > 0; argv++) {
   4662 
   4663 		if (strcmp(*argv, "primary") == 0) {
   4664 			is_primary = _B_TRUE;
   4665 			continue;
   4666 		}
   4667 
   4668 		if (strcmp(*argv, "wait") == 0) {
   4669 			if (--argc <= 0) {
   4670 				usage();
   4671 				return (DHCP_EXIT_BADARGS);
   4672 			}
   4673 			argv++;
   4674 
   4675 			if (strcmp(*argv, "forever") == 0) {
   4676 				timeout = DHCP_IPC_WAIT_FOREVER;
   4677 				continue;
   4678 			}
   4679 
   4680 			if (sscanf(*argv, "%d", &timeout) != 1) {
   4681 				usage();
   4682 				return (DHCP_EXIT_BADARGS);
   4683 			}
   4684 
   4685 			if (timeout < 0) {
   4686 				usage();
   4687 				return (DHCP_EXIT_BADARGS);
   4688 			}
   4689 			continue;
   4690 		}
   4691 
   4692 		type = dhcp_string_to_request(*argv);
   4693 		if (type == -1) {
   4694 			usage();
   4695 			return (DHCP_EXIT_BADARGS);
   4696 		}
   4697 	}
   4698 
   4699 	/*
   4700 	 * Only try to start agent on start or inform; in all other cases it
   4701 	 * has to already be running for anything to make sense.
   4702 	 */
   4703 	if (type == DHCP_START || type == DHCP_INFORM) {
   4704 		if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) {
   4705 			(void) fprintf(stderr, "%s: unable to start %s\n",
   4706 			    caller, DHCP_AGENT_PATH);
   4707 			return (DHCP_EXIT_FAILURE);
   4708 		}
   4709 		started = _B_TRUE;
   4710 	}
   4711 
   4712 	if (is_primary)
   4713 		type |= DHCP_PRIMARY;
   4714 
   4715 	if (af != AF_INET)
   4716 		type |= DHCP_V6;
   4717 
   4718 	request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE);
   4719 	if (request == NULL) {
   4720 		(void) fprintf(stderr, "%s: out of memory\n", caller);
   4721 		return (DHCP_EXIT_SYSTEM);
   4722 	}
   4723 
   4724 	error = dhcp_ipc_make_request(request, &reply, timeout);
   4725 	if (error != 0) {
   4726 		free(request);
   4727 		/*
   4728 		 * Re-map connect error to not under control if we didn't try a
   4729 		 * start operation, as this has to be true and results in a
   4730 		 * clearer message, not to mention preserving compatibility
   4731 		 * with the days when we always started dhcpagent for every
   4732 		 * request.
   4733 		 */
   4734 		if (error == DHCP_IPC_E_CONNECT && !started)
   4735 			error = DHCP_IPC_E_UNKIF;
   4736 		(void) fprintf(stderr, "%s: %s: %s\n", caller, ifname,
   4737 		    dhcp_ipc_strerror(error));
   4738 		return (DHCP_EXIT_FAILURE);
   4739 	}
   4740 
   4741 	error = reply->return_code;
   4742 	if (error != 0) {
   4743 		free(request);
   4744 		free(reply);
   4745 
   4746 		if (error == DHCP_IPC_E_TIMEOUT && timeout == 0)
   4747 			return (DHCP_EXIT_SUCCESS);
   4748 
   4749 		(void) fprintf(stderr, "%s: %s: %s\n", caller, ifname,
   4750 		    dhcp_ipc_strerror(error));
   4751 
   4752 		if (error == DHCP_IPC_E_TIMEOUT)
   4753 			return (DHCP_EXIT_TIMEOUT);
   4754 		else
   4755 			return (DHCP_EXIT_IF_FAILURE);
   4756 	}
   4757 
   4758 	if (DHCP_IPC_CMD(type) == DHCP_STATUS) {
   4759 		(void) printf("%s", dhcp_status_hdr_string());
   4760 		(void) printf("%s", dhcp_status_reply_to_string(reply));
   4761 	}
   4762 
   4763 	free(request);
   4764 	free(reply);
   4765 	return (DHCP_EXIT_SUCCESS);
   4766 }
   4767 
   4768 static void
   4769 usage(void)
   4770 {
   4771 	(void) fprintf(stderr,
   4772 	    "usage: ifconfig <interface> | -a[ 4 | 6 | D ][ u | d ][ Z ]\n");
   4773 
   4774 	(void) fprintf(stderr, "%s",
   4775 	    "\t[ <addr_family> ]\n"
   4776 	    "\t[ <address>[/<prefix_length>] [ <dest_address> ] ]\n"
   4777 	    "\t[ set [ <address>][/<prefix_length>] ]"
   4778 	    " [ <address>/<prefix_length>] ]\n"
   4779 	    "\t[ destination <dest_address> ]\n"
   4780 	    "\t[ addif <address>[/<prefix_length>]"
   4781 	    "  [ <dest_address> ] ]\n"
   4782 	    "\t[ removeif <address>[/<prefix_length>] ]\n"
   4783 	    "\t[ arp | -arp ]\n"
   4784 	    "\t[ auto-revarp ]\n"
   4785 	    "\t[ broadcast <broad_addr> ]\n"
   4786 	    "\t[ index <if_index> ]\n"
   4787 	    "\t[ metric <n> ] [ mtu <n> ]\n"
   4788 	    "\t[ netmask <mask> ]\n"
   4789 	    "\t[ plumb ] [ unplumb ]\n"
   4790 	    "\t[ preferred | -preferred ]\n"
   4791 	    "\t[ private | -private ]\n"
   4792 	    "\t[ local | -local ]\n"
   4793 	    "\t[ router | -router ]\n"
   4794 	    "\t[ subnet <subnet_address>]\n"
   4795 	    "\t[ trailers | -trailers ]\n"
   4796 	    "\t[ token <address>/<prefix_length> ]\n"
   4797 	    "\t[ tsrc <tunnel_src_address> ]\n"
   4798 	    "\t[ tdst <tunnel_dest_address> ]\n"
   4799 	    "\t[ auth_algs <tunnel_AH_authentication_algorithm> ]\n"
   4800 	    "\t[ encr_algs <tunnel_ESP_encryption_algorithm> ]\n"
   4801 	    "\t[ encr_auth_algs <tunnel_ESP_authentication_algorithm> ]\n"
   4802 	    "\t[ up ] [ down ]\n"
   4803 	    "\t[ xmit | -xmit ]\n"
   4804 	    "\t[ modlist ]\n"
   4805 	    "\t[ modinsert <module_name@position> ]\n"
   4806 	    "\t[ modremove <module_name@position> ]\n"
   4807 	    "\t[ ipmp ]\n"
   4808 	    "\t[ group <groupname>] | [ group \"\"]\n"
   4809 	    "\t[ deprecated | -deprecated ]\n"
   4810 	    "\t[ standby | -standby ]\n"
   4811 	    "\t[ failover | -failover ]\n"
   4812 	    "\t[ zone <zonename> | -zone ]\n"
   4813 	    "\t[ usesrc <interface> ]\n"
   4814 	    "\t[ all-zones ]\n");
   4815 
   4816 	(void) fprintf(stderr, "or\n");
   4817 	(void) fprintf(stderr,
   4818 	    "\tifconfig <interface> |  -a[ 4 | 6 | D ] [ u | d ]\n");
   4819 
   4820 	(void) fprintf(stderr, "%s", "\tauto-dhcp | dhcp\n"
   4821 	    "\t[ wait <time> | forever ]\n\t[ primary ]\n"
   4822 	    "\tstart | drop | ping | release | status | inform\n");
   4823 }
   4824