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