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