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