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