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