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