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