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