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