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