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