xref: /titanic_52/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c (revision d04ccbb3f3163ae5962a8b7465d9796bff6ca434)
1 /*
2  * Copyright 2007 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 
207 #define	NEXTARG		0xffffff	/* command takes an argument */
208 #define	OPTARG		0xfffffe 	/* command takes an optional argument */
209 #define	AF_ANY		(-1)
210 
211 /* Refer to the comments in ifconfig() on the netmask "hack" */
212 #define	NETMASK_CMD	"netmask"
213 struct sockaddr_storage	g_netmask;
214 enum { G_NETMASK_NIL, G_NETMASK_PENDING, G_NETMASK_SET }
215     g_netmask_set = G_NETMASK_NIL;
216 
217 struct	cmd {
218 	char		*c_name;
219 	int64_t		c_parameter;	/* NEXTARG means next argv */
220 	int		(*c_func)(char *, int64_t);
221 	int		c_abortonfail;	/* don't continue parsing args */
222 					/* for the current interface */
223 	int	c_af;			/* address family restrictions */
224 } cmds[] = {
225 	{ "up",		IFF_UP,		setifflags,	0,	AF_ANY },
226 	{ "down",	-IFF_UP,	setifflags,	0,	AF_ANY },
227 	{ "trailers",	-IFF_NOTRAILERS, setifflags,	0,	AF_ANY },
228 	{ "-trailers",	IFF_NOTRAILERS,	setifflags,	0,	AF_ANY },
229 	{ "arp",	-IFF_NOARP,	setifflags,	0,	AF_INET },
230 	{ "-arp",	IFF_NOARP,	setifflags,	0,	AF_INET },
231 	{ "router",	IFF_ROUTER,	setifflags,	0,	AF_ANY },
232 	{ "-router",	-IFF_ROUTER,	setifflags,	0,	AF_ANY },
233 	{ "private",	IFF_PRIVATE,	setifflags,	0,	AF_ANY },
234 	{ "-private",	-IFF_PRIVATE,	setifflags,	0,	AF_ANY },
235 	{ "xmit",	-IFF_NOXMIT,	setifflags,	0,	AF_ANY },
236 	{ "-xmit",	IFF_NOXMIT,	setifflags,	0,	AF_ANY },
237 	{ "-nud",	IFF_NONUD,	setifflags,	0,	AF_INET6 },
238 	{ "nud",	-IFF_NONUD,	setifflags,	0,	AF_INET6 },
239 	{ "anycast",	IFF_ANYCAST,	setifflags,	0,	AF_ANY },
240 	{ "-anycast",	-IFF_ANYCAST,	setifflags,	0,	AF_ANY },
241 	{ "local",	-IFF_NOLOCAL,	setifflags,	0,	AF_ANY },
242 	{ "-local",	IFF_NOLOCAL,	setifflags,	0,	AF_ANY },
243 	{ "deprecated",	IFF_DEPRECATED,	setifflags,	0,	AF_ANY },
244 	{ "-deprecated", -IFF_DEPRECATED, setifflags,	0,	AF_ANY },
245 	{ "preferred",	IFF_PREFERRED,	setifflags,	0,	AF_INET6 },
246 	{ "-preferred",	-IFF_PREFERRED,	setifflags,	0,	AF_INET6 },
247 	{ "debug",	0,		setdebugflag,	0,	AF_ANY },
248 	{ "verbose",	0,		setverboseflag,	0,	AF_ANY },
249 	{ NETMASK_CMD,	NEXTARG,	setifnetmask,	0,	AF_INET },
250 	{ "metric",	NEXTARG,	setifmetric,	0,	AF_ANY },
251 	{ "mtu",	NEXTARG,	setifmtu,	0,	AF_ANY },
252 	{ "index",	NEXTARG,	setifindex,	0,	AF_ANY },
253 	{ "broadcast",	NEXTARG,	setifbroadaddr,	0,	AF_INET },
254 	{ "auto-revarp", 0,		setifrevarp,	1,	AF_INET },
255 	{ "plumb",	0,		inetplumb,	1,	AF_ANY },
256 	{ "unplumb",	0,		inetunplumb,	0,	AF_ANY },
257 	{ "subnet",	NEXTARG,	setifsubnet,	0,	AF_ANY },
258 	{ "token",	NEXTARG,	setiftoken,	0,	AF_INET6 },
259 	{ "tsrc",	NEXTARG,	setiftsrc,	0,	AF_ANY },
260 	{ "tdst",	NEXTARG,	setiftdst,	0,	AF_ANY },
261 	{ "encr_auth_algs", NEXTARG,	set_tun_esp_auth_alg, 0, AF_ANY },
262 	{ "encr_algs",	NEXTARG,	set_tun_esp_encr_alg, 0, AF_ANY },
263 	{ "auth_algs",	NEXTARG,	set_tun_ah_alg,	0,	AF_ANY },
264 	{ "addif",	NEXTARG,	addif,		1,	AF_ANY },
265 	{ "removeif",	NEXTARG,	removeif,	1,	AF_ANY },
266 	{ "modlist",	0,		modlist,	1,	AF_ANY },
267 	{ "modinsert",	NEXTARG,	modinsert,	1,	AF_ANY },
268 	{ "modremove",	NEXTARG,	modremove,	1,	AF_ANY },
269 	{ "failover",	-IFF_NOFAILOVER, setifflags,	1,	AF_ANY },
270 	{ "-failover",	IFF_NOFAILOVER, setifflags,	1,	AF_ANY },
271 	{ "standby",	IFF_STANDBY,	setifflags,	1,	AF_ANY },
272 	{ "-standby",	-IFF_STANDBY,	setifflags,	1,	AF_ANY },
273 	{ "failed",	IFF_FAILED,	setifflags,	1,	AF_ANY },
274 	{ "-failed",	-IFF_FAILED,	setifflags,	1,	AF_ANY },
275 	{ "group",	NEXTARG,	setifgroupname,	1,	AF_ANY },
276 	{ "configinfo",	0,		configinfo,	1,	AF_ANY },
277 	{ "encaplimit",	NEXTARG,	set_tun_encap_limit,	0, AF_ANY },
278 	{ "-encaplimit", 0,		clr_tun_encap_limit,	0, AF_ANY },
279 	{ "thoplimit",	NEXTARG,	set_tun_hop_limit,	0, AF_ANY },
280 	{ "set",	NEXTARG,	setifaddr,	0,	AF_ANY },
281 	{ "destination", NEXTARG,	setifdstaddr,	0,	AF_ANY },
282 	{ "zone",	NEXTARG,	setzone,	0,	AF_ANY },
283 	{ "-zone",	0,		setzone,	0,	AF_ANY },
284 	{ "all-zones",	0,		setallzones,	0,	AF_ANY },
285 	{ "ether",	OPTARG,		setifether,	0,	AF_ANY },
286 	{ "usesrc",	NEXTARG,	setifsrc,	0,	AF_ANY },
287 	{ 0,		0,		setifaddr,	0,	AF_ANY },
288 	{ 0,		0,		setifdstaddr,	0,	AF_ANY },
289 	{ 0,		0,		0,		0,	0 },
290 };
291 
292 
293 typedef struct if_config_cmd {
294 	uint64_t	iff_flag;
295 	char		*iff_name;
296 } if_config_cmd_t;
297 
298 static if_config_cmd_t	if_config_cmd_tbl[] = {
299 	{ IFF_UP,		"up" },
300 	{ IFF_NOTRAILERS,	"-trailers" },
301 	{ IFF_PRIVATE,		"private" },
302 	{ IFF_NOXMIT,		"-xmit" },
303 	{ IFF_ANYCAST,		"anycast" },
304 	{ IFF_NOLOCAL,		"-local" },
305 	{ IFF_DEPRECATED,	"deprecated" },
306 	{ IFF_NOFAILOVER,	"-failover" },
307 	{ IFF_STANDBY,		"standby" },
308 	{ IFF_FAILED,		"failed" },
309 	{ IFF_PREFERRED,	"preferred" },
310 	{ 0,			0 },
311 };
312 
313 typedef struct ni {
314 	char		ni_name[LIFNAMSIZ];
315 	struct ni	*ni_next;
316 } ni_t;
317 
318 static ni_t	*ni_list = NULL;
319 static int	num_ni = 0;
320 
321 /* End defines and structure definitions for ifconfig -a plumb */
322 
323 /* Known address families */
324 struct afswtch {
325 	char *af_name;
326 	short af_af;
327 	void (*af_status)();
328 	void (*af_getaddr)();
329 	void (*af_configinfo)();
330 } afs[] = {
331 	{ "inet", AF_INET, in_status, in_getaddr, in_configinfo },
332 	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_configinfo },
333 	{ 0, 0,	0, 0, 0 }
334 };
335 
336 #define	SOCKET_AF(af)	(((af) == AF_UNSPEC) ? AF_INET : (af))
337 
338 struct afswtch *afp;	/* the address family being set or asked about */
339 
340 int
341 main(int argc, char *argv[])
342 {
343 	/* Include IFF_NOXMIT, IFF_TEMPORARY and all zone interfaces */
344 	int64_t lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
345 	char *default_ip_str;
346 
347 	if (argc < 2) {
348 		usage();
349 		exit(1);
350 	}
351 	argc--, argv++;
352 	if (strlen(*argv) > sizeof (name) - 1) {
353 		(void) fprintf(stderr, "%s: interface name too long\n", *argv);
354 		exit(1);
355 	}
356 	(void) strncpy(name, *argv, sizeof (name));
357 	name[sizeof (name) - 1] = '\0';
358 	(void) strncpy(origname, name, sizeof (origname));	/* For addif */
359 	default_ip_str = NULL;
360 	v4compat = get_compat_flag(&default_ip_str);
361 	if (v4compat == DEFAULT_PROT_BAD_VALUE) {
362 		(void) fprintf(stderr,
363 		    "ifconfig: %s: Bad value for %s in %s\n", default_ip_str,
364 		    DEFAULT_IP, INET_DEFAULT_FILE);
365 		free(default_ip_str);
366 		exit(2);
367 	}
368 	free(default_ip_str);
369 	argc--, argv++;
370 	if (argc > 0) {
371 		struct afswtch *myafp;
372 
373 		for (myafp = afp = afs; myafp->af_name; myafp++) {
374 			if (strcmp(myafp->af_name, *argv) == 0) {
375 				afp = myafp; argc--; argv++;
376 				break;
377 			}
378 		}
379 		af = lifr.lifr_addr.ss_family = afp->af_af;
380 		if (af == AF_INET6) {
381 			v4compat = 0;
382 		}
383 	}
384 
385 	s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
386 	if (s < 0) {
387 		Perror0_exit("socket");
388 	}
389 
390 	/*
391 	 * Special interface names is any combination of these flags.
392 	 * Note that due to the ifconfig syntax they have to be combined
393 	 * as a single '-' option.
394 	 *	-a	All interfaces
395 	 *	-u	"up" interfaces
396 	 *	-d	"down" interfaces
397 	 *	-D	Interfaces not controlled by DHCP
398 	 *	-4	IPv4 interfaces
399 	 *	-6	IPv6 interfaces
400 	 *	-X	Turn on debug (not documented)
401 	 *	-v	Turn on verbose
402 	 *	-Z	Only interfaces in caller's zone
403 	 */
404 
405 	if (name[0] == '-') {
406 		/* One or more options */
407 		int64_t onflags = 0;
408 		int64_t offflags = 0;
409 		int c;
410 		char *av[2] = { "ifconfig", name };
411 
412 		while ((c = getopt(2, av, "audDXZ46v")) != -1) {
413 			switch ((char)c) {
414 			case 'a':
415 				all = 1;
416 				break;
417 			case 'u':
418 				onflags |= IFF_UP;
419 				break;
420 			case 'd':
421 				offflags |= IFF_UP;
422 				break;
423 			case 'D':
424 				offflags |= IFF_DHCPRUNNING;
425 				break;
426 			case 'X':
427 				debug += 3;
428 				break;
429 			case 'Z':
430 				lifc_flags &= ~LIFC_ALLZONES;
431 				break;
432 			case '4':
433 				/*
434 				 * -4 is not a compatable flag, therefore
435 				 * we assume they want v4compat turned off
436 				 */
437 				v4compat = 0;
438 				onflags |= IFF_IPV4;
439 				break;
440 			case '6':
441 				/*
442 				 * If they want IPv6, well then we'll assume
443 				 * they don't want IPv4 compat
444 				 */
445 				v4compat = 0;
446 				onflags |= IFF_IPV6;
447 				break;
448 			case 'v':
449 				verbose = 1;
450 				break;
451 			case '?':
452 				usage();
453 				exit(1);
454 			}
455 		}
456 		if (!all) {
457 			(void) fprintf(stderr,
458 			    "ifconfig: %s: no such interface\n",
459 			    name);
460 			exit(1);
461 		}
462 		foreachinterface(ifconfig, argc, argv, af, onflags, offflags,
463 		    lifc_flags);
464 	} else {
465 		ifconfig(argc, argv, af, (struct lifreq *)NULL);
466 	}
467 	return (0);
468 }
469 
470 /*
471  * For each interface, call (*func)(argc, argv, af, lifrp).
472  * Only call function if onflags and offflags are set or clear, respectively,
473  * in the interfaces flags field.
474  */
475 static void
476 foreachinterface(void (*func)(), int argc, char *argv[], int af,
477     int64_t onflags, int64_t offflags, int64_t lifc_flags)
478 {
479 	int n;
480 	char *buf;
481 	struct lifnum lifn;
482 	struct lifconf lifc;
483 	struct lifreq *lifrp;
484 	struct lifreq lifrl;	/* Local lifreq struct */
485 	int numifs;
486 	unsigned bufsize;
487 	ni_t *nip;
488 	int plumball = 0;
489 	int save_af = af;
490 
491 	/*
492 	 * Special case:
493 	 * ifconfig -a plumb should find all network interfaces
494 	 * in the machine by traversing the devinfo tree.
495 	 * Also, there is no need to  SIOCGLIF* ioctls, since
496 	 * those interfaces have already been plumbed
497 	 */
498 	if (argc > 0 && (strcmp(*argv, "plumb") == 0)) {
499 		/*
500 		 * Look through the kernel's devinfo tree for
501 		 * network devices
502 		 */
503 		di_node_t root;
504 
505 		/*
506 		 * DINFOCACHE is equivalent to DINFOSUBTREE | DINFOMINOR |
507 		 * DINFOPROP | DINFOFORCE.
508 		 */
509 		if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
510 			(void) fprintf(stderr, "ifconfig: di_init failed;"
511 			    " check the devinfo driver.\n");
512 			exit(1);
513 		}
514 
515 		(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, NULL,
516 		    devfs_entry);
517 		di_fini(root);
518 
519 		/*
520 		 * Now, translate the linked list into
521 		 * a struct lifreq buffer
522 		 */
523 		bufsize = num_ni * sizeof (struct lifreq);
524 		if ((buf = malloc(bufsize)) == NULL)
525 			Perror0_exit("foreachinterface: malloc failed");
526 
527 		lifc.lifc_family = AF_UNSPEC;
528 		lifc.lifc_flags = lifc_flags;
529 		lifc.lifc_len = bufsize;
530 		lifc.lifc_buf = buf;
531 
532 		for (n = 0, lifrp = lifc.lifc_req; n < num_ni; n++, lifrp++) {
533 			nip = ni_list;
534 			(void) strncpy(lifrp->lifr_name, nip->ni_name,
535 			    sizeof (lifr.lifr_name));
536 			ni_list = nip->ni_next;
537 			free(nip);
538 		}
539 
540 		plumball = 1;
541 	} else {
542 		lifn.lifn_family = AF_UNSPEC;
543 		lifn.lifn_flags = lifc_flags;
544 		if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
545 			Perror0_exit("Could not determine number"
546 			    " of interfaces");
547 		}
548 		numifs = lifn.lifn_count;
549 		if (debug)
550 			(void) printf("ifconfig: %d interfaces\n",  numifs);
551 
552 		bufsize = numifs * sizeof (struct lifreq);
553 		if ((buf = malloc(bufsize)) == NULL) {
554 			Perror0("out of memory\n");
555 			(void) close(s);
556 			return;
557 		}
558 
559 		lifc.lifc_family = AF_UNSPEC;
560 		lifc.lifc_flags = lifc_flags;
561 		lifc.lifc_len = bufsize;
562 		lifc.lifc_buf = buf;
563 
564 		if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
565 			Perror0("SIOCGLIFCONF");
566 			(void) close(s);
567 			free(buf);
568 			return;
569 		}
570 	}
571 
572 	lifrp = lifc.lifc_req;
573 	for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
574 
575 		if (!plumball) {
576 			/*
577 			 * We must close and recreate the socket each time
578 			 * since we don't know what type of socket it is now
579 			 * (each status function may change it).
580 			 */
581 
582 			(void) close(s);
583 
584 			af = lifrp->lifr_addr.ss_family;
585 			s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
586 			if (s == -1) {
587 				/*
588 				 * Perror0() assumes the name to be in the
589 				 * globally defined lifreq structure.
590 				 */
591 				(void) strncpy(lifr.lifr_name,
592 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
593 				Perror0_exit("socket");
594 			}
595 		}
596 
597 		/*
598 		 * Only service interfaces that match the on and off
599 		 * flags masks.
600 		 */
601 		if (onflags || offflags) {
602 			(void) memset(&lifrl, 0, sizeof (lifrl));
603 			(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
604 				sizeof (lifrl.lifr_name));
605 			if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) {
606 				/*
607 				 * Perror0() assumes the name to be in the
608 				 * globally defined lifreq structure.
609 				 */
610 				(void) strncpy(lifr.lifr_name,
611 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
612 				Perror0_exit("foreachinterface: SIOCGLIFFLAGS");
613 			}
614 			if ((lifrl.lifr_flags & onflags) != onflags)
615 				continue;
616 			if ((~lifrl.lifr_flags & offflags) != offflags)
617 				continue;
618 		}
619 
620 		if (!plumball) {
621 			(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
622 			    sizeof (lifrl.lifr_name));
623 			if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifrl) < 0) {
624 				/*
625 				 * Perror0() assumes the name to be in the
626 				 * globally defined lifreq structure.
627 				 */
628 				(void) strncpy(lifr.lifr_name,
629 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
630 				Perror0("foreachinterface: SIOCGLIFADDR");
631 				continue;
632 			}
633 			if (lifrl.lifr_addr.ss_family != af) {
634 				/* Switch address family */
635 				af = lifrl.lifr_addr.ss_family;
636 				(void) close(s);
637 
638 				s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
639 				if (s == -1) {
640 					/*
641 					 * Perror0() assumes the name to be in
642 					 * the globally defined lifreq
643 					 * structure.
644 					 */
645 					(void) strncpy(lifr.lifr_name,
646 					    lifrp->lifr_name,
647 					    sizeof (lifr.lifr_name));
648 					Perror0_exit("socket");
649 				}
650 			}
651 		}
652 
653 		/*
654 		 * Reset global state
655 		 * setaddr: Used by parser to tear apart source and dest
656 		 * name and origname contain the name of the 'current'
657 		 * interface.
658 		 */
659 		setaddr = 0;
660 		(void) strncpy(name, lifrp->lifr_name, sizeof (name));
661 		(void) strncpy(origname, name, sizeof (origname));
662 
663 		(*func)(argc, argv, save_af, lifrp);
664 		/* the func could have overwritten origname, so restore */
665 		(void) strncpy(name, origname, sizeof (name));
666 	}
667 	free(buf);
668 }
669 
670 static void
671 tun_reality_check(void)
672 {
673 	struct iftun_req treq;
674 	ipsec_req_t *ipsr;
675 
676 	(void) strncpy(treq.ifta_lifr_name, name, sizeof (treq.ifta_lifr_name));
677 	if (strchr(name, ':') != NULL) {
678 		/* Return, we don't need to check. */
679 		return;
680 	}
681 	if (ioctl(s, SIOCGTUNPARAM, (caddr_t)&treq) < 0 ||
682 	    (treq.ifta_flags & IFTUN_SECURITY) == 0) {
683 		/*
684 		 * Either not a tunnel (the SIOCGTUNPARAM fails on
685 		 * non-tunnels), or the security flag is not set.  Either
686 		 * way, return.
687 		 */
688 		return;
689 	}
690 
691 	ipsr = (ipsec_req_t *)&treq.ifta_secinfo;
692 
693 	if (ipsr->ipsr_esp_req != 0 &&
694 	    ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE &&
695 	    ipsr->ipsr_ah_req == 0)
696 		(void) fprintf(stderr, "ifconfig: WARNING - tunnel with "
697 		    "only ESP and potentially no authentication.\n");
698 }
699 
700 /*
701  * for the specified interface call (*func)(argc, argv, af, lifrp).
702  */
703 
704 static void
705 ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp)
706 {
707 	static boolean_t scan_netmask = _B_FALSE;
708 	int ret;
709 
710 	if (argc == 0) {
711 		status();
712 		return;
713 	}
714 
715 	if (strcmp(*argv, "auto-dhcp") == 0 || strcmp(*argv, "dhcp") == 0) {
716 		/*
717 		 * Some errors are ignored in the case where more than one
718 		 * interface is being operated on.
719 		 */
720 		ret = setifdhcp("ifconfig", name, argc, argv);
721 		if (ret == DHCP_EXIT_IF_FAILURE) {
722 			if (!all)
723 				exit(DHCP_EXIT_FAILURE);
724 		} else if (ret != DHCP_EXIT_SUCCESS) {
725 			exit(ret);
726 		}
727 		return;
728 	}
729 
730 	/*
731 	 * The following is a "hack" to get around the existing interface
732 	 * setting mechanism.  Currently, each interface attribute,
733 	 * such as address, netmask, broadcast, ... is set separately.  But
734 	 * sometimes two or more attributes must be set together.  For
735 	 * example, setting an address without a netmask does not make sense.
736 	 * Yet they can be set separately for IPv4 address using the current
737 	 * ifconfig(1M) syntax.  The kernel then "infers" the correct netmask
738 	 * using the deprecated "IP address classes."  This is simply not
739 	 * correct.
740 	 *
741 	 * The "hack" below is to go thru the whole command list looking for
742 	 * the netmask command first.  Then use this netmask to set the
743 	 * address.  This does not provide an extensible way to accommodate
744 	 * future need for setting more than one attributes together.
745 	 *
746 	 * Note that if the "netmask" command argument is a "+", we need
747 	 * to save this info and do the query after we know the address to
748 	 * be set.  The reason is that if "addif" is used, the working
749 	 * interface name will be changed later when the logical interface
750 	 * is created.  In in_getmask(), if an address is not provided,
751 	 * it will use the working interface's address to do the query.
752 	 * It will be wrong now as we don't know the logical interface's name.
753 	 *
754 	 * ifconfig(1M) is too overloaded and the code is so convoluted
755 	 * that it is "safer" not to re-architect the code to fix the above
756 	 * issue, hence this "hack."  We may be better off to have a new
757 	 * command with better syntax for configuring network interface
758 	 * parameters...
759 	 */
760 	if (!scan_netmask && afp->af_af == AF_INET) {
761 		int	largc;
762 		char	**largv;
763 
764 		/* Only go thru the command list once to find the netmask. */
765 		scan_netmask = _B_TRUE;
766 
767 		/*
768 		 * Currently, if multiple netmask commands are specified, the
769 		 * last one will be used as the final netmask.  So we need
770 		 * to scan the whole list to preserve this behavior.
771 		 */
772 		for (largc = argc, largv = argv; largc > 0; largc--, largv++) {
773 			if (strcmp(*largv, NETMASK_CMD) == 0) {
774 				if (--largc == 0)
775 					break;
776 				largv++;
777 				if (strcmp(*largv, "+") == 0) {
778 					g_netmask_set = G_NETMASK_PENDING;
779 				} else {
780 					in_getaddr(*largv, (struct sockaddr *)
781 					    &g_netmask, NULL);
782 					g_netmask_set = G_NETMASK_SET;
783 				}
784 				/* Continue the scan. */
785 			}
786 		}
787 	}
788 
789 	while (argc > 0) {
790 		struct cmd *p;
791 		boolean_t found_cmd;
792 
793 		if (debug)
794 			(void) printf("ifconfig: argv %s\n", *argv);
795 
796 		found_cmd = _B_FALSE;
797 		for (p = cmds; p->c_func; p++) {
798 			if (p->c_name) {
799 				if (strcmp(*argv, p->c_name) == 0) {
800 					/*
801 					 * indicate that the command was
802 					 * found and check to see if
803 					 * the address family is valid
804 					 */
805 					found_cmd = _B_TRUE;
806 					if (p->c_af == AF_ANY ||
807 					    af == p->c_af)
808 						break;
809 				}
810 			} else {
811 				if (p->c_af == AF_ANY ||
812 				    af == p->c_af)
813 					break;
814 			}
815 		}
816 		/*
817 		 * If we found the keyword, but the address family
818 		 * did not match spit out an error
819 		 */
820 		if (found_cmd && p->c_name == 0) {
821 			(void) fprintf(stderr, "ifconfig: Operation %s not"
822 			    " supported for %s\n", *argv, afp->af_name);
823 			exit(1);
824 		}
825 		/*
826 		 * else (no keyword found), we assume it's an address
827 		 * of some sort
828 		 */
829 		if (p->c_name == 0 && setaddr)
830 			p++;	/* got src, do dst */
831 		if (p->c_func) {
832 			if (p->c_af == AF_INET6) {
833 				v4compat = 0;
834 			}
835 			if (p->c_parameter == NEXTARG ||
836 			    p->c_parameter == OPTARG) {
837 				argc--, argv++;
838 				if (argc == 0 && p->c_parameter == NEXTARG) {
839 					(void) fprintf(stderr,
840 					    "ifconfig: no argument for %s\n",
841 					    p->c_name);
842 					exit(1);
843 				}
844 			}
845 			/*
846 			 *	Call the function if:
847 			 *
848 			 *		there's no address family
849 			 *		restriction
850 			 *	OR
851 			 *		we don't know the address yet
852 			 *		(because we were called from
853 			 *		main)
854 			 *	OR
855 			 *		there is a restriction AND
856 			 *		the address families match
857 			 */
858 			if ((p->c_af == AF_ANY)	||
859 			    (lifrp == (struct lifreq *)NULL) ||
860 			    (lifrp->lifr_addr.ss_family == p->c_af)) {
861 				ret = (*p->c_func)(*argv, p->c_parameter);
862 				/*
863 				 *	If c_func failed and we should
864 				 *	abort processing for this
865 				 *	interface on failure, return
866 				 *	now rather than going on to
867 				 *	process other commands for
868 				 *	the same interface.
869 				 */
870 				if (ret != 0 && p->c_abortonfail)
871 					return;
872 			}
873 		}
874 		argc--, argv++;
875 	}
876 
877 	/* Check to see if there's a security hole in the tunnel setup. */
878 	tun_reality_check();
879 }
880 
881 /* ARGSUSED */
882 static int
883 setdebugflag(char *val, int64_t arg)
884 {
885 	debug++;
886 	return (0);
887 }
888 
889 /* ARGSUSED */
890 static int
891 setverboseflag(char *val, int64_t arg)
892 {
893 	verbose++;
894 	return (0);
895 }
896 
897 /*
898  * This function fills in the given lifreq's lifr_addr field based on
899  * g_netmask_set.
900  */
901 static void
902 set_mask_lifreq(struct lifreq *lifr, struct sockaddr_storage *addr,
903     struct sockaddr_storage *mask)
904 {
905 	assert(addr != NULL);
906 	assert(mask != NULL);
907 
908 	switch (g_netmask_set) {
909 	case G_NETMASK_SET:
910 		lifr->lifr_addr = g_netmask;
911 		break;
912 
913 	case G_NETMASK_PENDING:
914 		/*
915 		 * "+" is used as the argument to "netmask" command.  Query
916 		 * the database on the correct netmask based on the address to
917 		 * be set.
918 		 */
919 		assert(afp->af_af == AF_INET);
920 		g_netmask = *addr;
921 		if (!in_getmask((struct sockaddr_in *)&g_netmask, _B_TRUE)) {
922 			lifr->lifr_addr = *mask;
923 			g_netmask_set = G_NETMASK_NIL;
924 		} else {
925 			lifr->lifr_addr = g_netmask;
926 			g_netmask_set = G_NETMASK_SET;
927 		}
928 		break;
929 
930 	case G_NETMASK_NIL:
931 	default:
932 		lifr->lifr_addr = *mask;
933 		break;
934 	}
935 }
936 
937 /*
938  * Set the interface address. Handles <addr>, <addr>/<n> as well as /<n>
939  * syntax for setting the address, the address plus netmask, and just
940  * the netmask respectively.
941  */
942 /* ARGSUSED */
943 static int
944 setifaddr(char *addr, int64_t param)
945 {
946 	int prefixlen = 0;
947 	struct	sockaddr_storage laddr;
948 	struct	sockaddr_storage netmask;
949 	struct	sockaddr_in6 *sin6;
950 	struct	sockaddr_in *sin;
951 	struct	sockaddr_storage sav_netmask;
952 
953 	if (addr[0] == '/')
954 		return (setifprefixlen(addr, 0));
955 
956 	(*afp->af_getaddr)(addr, (struct sockaddr *)&laddr, &prefixlen);
957 
958 	(void) memset(&netmask, 0, sizeof (netmask));
959 	netmask.ss_family = afp->af_af;
960 	switch (prefixlen) {
961 	case NO_PREFIX:
962 		/* Nothing there - ok */
963 		break;
964 	case BAD_ADDR:
965 		(void) fprintf(stderr, "ifconfig: Bad prefix length in %s\n",
966 		    addr);
967 		exit(1);
968 	default:
969 		if (afp->af_af == AF_INET6) {
970 			sin6 = (struct sockaddr_in6 *)&netmask;
971 			if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
972 			    (uchar_t *)&sin6->sin6_addr)) {
973 				(void) fprintf(stderr, "ifconfig: "
974 				    "Bad prefix length: %d\n",
975 				    prefixlen);
976 				exit(1);
977 			}
978 		} else {
979 			sin = (struct sockaddr_in *)&netmask;
980 			if (!in_prefixlentomask(prefixlen, IP_ABITS,
981 			    (uchar_t *)&sin->sin_addr)) {
982 				(void) fprintf(stderr, "ifconfig: "
983 				    "Bad prefix length: %d\n",
984 				    prefixlen);
985 				exit(1);
986 			}
987 		}
988 		/*
989 		 * Just in case of funny setting of both prefix and netmask,
990 		 * prefix should override the netmask command.
991 		 */
992 		g_netmask_set = G_NETMASK_NIL;
993 		break;
994 	}
995 	/* Tell parser that an address was set */
996 	setaddr++;
997 	/* save copy of netmask to restore in case of error */
998 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
999 	if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0)
1000 		Perror0_exit("SIOCGLIFNETMASK");
1001 	sav_netmask = lifr.lifr_addr;
1002 
1003 	/*
1004 	 * If setting the address and not the mask, clear any existing mask
1005 	 * and the kernel will then assign the default (netmask has been set
1006 	 * to 0 in this case).  If setting both (either by using a prefix or
1007 	 * using the netmask command), set the mask first, so the address will
1008 	 * be interpreted correctly.
1009 	 */
1010 	set_mask_lifreq(&lifr, &laddr, &netmask);
1011 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1012 		Perror0_exit("SIOCSLIFNETMASK");
1013 
1014 	if (debug) {
1015 		char abuf[INET6_ADDRSTRLEN];
1016 		void *addr = (afp->af_af == AF_INET) ?
1017 		    (void *)&((struct sockaddr_in *)&laddr)->sin_addr :
1018 		    (void *)&((struct sockaddr_in6 *)&laddr)->sin6_addr;
1019 
1020 		(void) printf("Setting %s af %d addr %s\n",
1021 		    lifr.lifr_name, afp->af_af,
1022 		    inet_ntop(afp->af_af, addr, abuf, sizeof (abuf)));
1023 	}
1024 	lifr.lifr_addr = laddr;
1025 	lifr.lifr_addr.ss_family = afp->af_af;
1026 	if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
1027 		/*
1028 		 * Restore the netmask
1029 		 */
1030 		int saverr = errno;
1031 
1032 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1033 		lifr.lifr_addr = sav_netmask;
1034 		(void) ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr);
1035 		errno = saverr;
1036 		Perror0_exit("SIOCSLIFADDR");
1037 	}
1038 
1039 	return (0);
1040 }
1041 
1042 /*
1043  * The following functions are stolen from the ipseckey(1m) program.
1044  * Perhaps they should be somewhere common, but for now, we just maintain
1045  * two versions.  We do this because of the different semantics for which
1046  * algorithms we select ("requested" for ifconfig vs. "actual" for key).
1047  */
1048 
1049 static ulong_t
1050 parsenum(char *num)
1051 {
1052 	ulong_t rc;
1053 	char *end = NULL;
1054 
1055 	errno = 0;
1056 	rc = strtoul(num, &end, 0);
1057 	if (errno != 0 || end == num || *end != '\0') {
1058 		rc = (ulong_t)-1;
1059 	}
1060 
1061 	return (rc);
1062 }
1063 
1064 /*
1065  * Parse and reverse parse possible algorithm values, include numbers.
1066  * Mostly stolen from ipseckey.c. See the comments above parsenum() for why
1067  * this isn't common to ipseckey.c.
1068  *
1069  * NOTE: Static buffer in this function for the return value.  Since ifconfig
1070  *	 isn't multithreaded, this isn't a huge problem.
1071  */
1072 
1073 #define	NBUF_SIZE 20	/* Enough to print a large integer. */
1074 
1075 static char *
1076 rparsealg(uint8_t alg_value, int proto_num)
1077 {
1078 	struct ipsecalgent *alg;
1079 	static char numprint[128];	/* Enough to hold an algorithm name. */
1080 
1081 	/* Special-case 0 to return "<any-none>" */
1082 	if (alg_value == 0)
1083 		return ("<any-none>");
1084 
1085 	alg = getipsecalgbynum(alg_value, proto_num, NULL);
1086 	if (alg != NULL) {
1087 		(void) strlcpy(numprint, alg->a_names[0], sizeof (numprint));
1088 		freeipsecalgent(alg);
1089 	} else {
1090 		(void) snprintf(numprint, sizeof (numprint), "%d", alg_value);
1091 	}
1092 
1093 	return (numprint);
1094 }
1095 
1096 static uint_t
1097 parsealg(char *algname, int proto_num)
1098 {
1099 	struct ipsecalgent *alg;
1100 	ulong_t invalue;
1101 
1102 	if (algname == NULL) {
1103 		(void) fprintf(stderr, "ifconfig: Unexpected end of command "
1104 		    "line.\n");
1105 		exit(1);
1106 	}
1107 
1108 	/*
1109 	 * Special-case "none". Use strcasecmp because its length is
1110 	 * bound.
1111 	 */
1112 	if (strcasecmp("none", algname) == 0) {
1113 		return ((proto_num == IPSEC_PROTO_ESP) ?
1114 		    NO_ESP_EALG : NO_ESP_AALG);
1115 	}
1116 
1117 	alg = getipsecalgbyname(algname, proto_num, NULL);
1118 	if (alg != NULL) {
1119 		invalue = alg->a_alg_num;
1120 		freeipsecalgent(alg);
1121 		return ((uint_t)invalue);
1122 	}
1123 
1124 	/*
1125 	 * Since algorithms can be loaded during kernel run-time, check for
1126 	 * numeric algorithm values too.
1127 	 */
1128 	invalue = parsenum(algname);
1129 	if ((invalue & (ulong_t)0xff) == invalue)
1130 		return ((uint_t)invalue);
1131 
1132 	(void) fprintf(stderr, "ifconfig: %s algorithm type %s unknown.\n",
1133 	    (proto_num == IPSEC_PROTO_ESP) ?
1134 	    "Encryption" : "Authentication", algname);
1135 	exit(1);
1136 	/* NOTREACHED */
1137 }
1138 
1139 /*
1140  * Actual ifconfig functions to set tunnel security properties.
1141  */
1142 
1143 enum ipsec_alg_type { ESP_ENCR_ALG = 1, ESP_AUTH_ALG, AH_AUTH_ALG };
1144 
1145 boolean_t first_set_tun = _B_TRUE;
1146 boolean_t encr_alg_set = _B_FALSE;
1147 
1148 static int
1149 set_tun_algs(int which_alg, int alg)
1150 {
1151 	struct iftun_req treq;
1152 	ipsec_req_t *ipsr;
1153 
1154 	(void) strncpy(treq.ifta_lifr_name, name, sizeof (treq.ifta_lifr_name));
1155 	if (strchr(name, ':') != NULL) {
1156 		errno = EPERM;
1157 		Perror0_exit("Tunnel params on logical interfaces");
1158 	}
1159 	if (ioctl(s, SIOCGTUNPARAM, (caddr_t)&treq) < 0) {
1160 		if (errno == EOPNOTSUPP || errno == EINVAL)
1161 			Perror0_exit("Not a tunnel");
1162 		else Perror0_exit("SIOCGTUNPARAM");
1163 	}
1164 
1165 	ipsr = (ipsec_req_t *)&treq.ifta_secinfo;
1166 
1167 	if (treq.ifta_vers != IFTUN_VERSION) {
1168 		(void) fprintf(stderr,
1169 		    "Kernel tunnel secinfo version mismatch.\n");
1170 		exit(1);
1171 	}
1172 
1173 	/*
1174 	 * If I'm just starting off this ifconfig, I want a clean slate,
1175 	 * otherwise, I've captured the current tunnel security settings.
1176 	 * In the case of continuation, I merely add to the settings.
1177 	 */
1178 	if (first_set_tun) {
1179 		first_set_tun = _B_FALSE;
1180 		(void) memset(ipsr, 0, sizeof (*ipsr));
1181 	}
1182 
1183 	treq.ifta_flags = IFTUN_SECURITY;
1184 
1185 	switch (which_alg) {
1186 	case ESP_ENCR_ALG:
1187 		if (alg == NO_ESP_EALG) {
1188 			if (ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE)
1189 				ipsr->ipsr_esp_req = 0;
1190 			ipsr->ipsr_esp_alg = SADB_EALG_NONE;
1191 		} else {
1192 			encr_alg_set = _B_TRUE;
1193 			ipsr->ipsr_esp_req =
1194 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
1195 			ipsr->ipsr_esp_alg = alg;
1196 		}
1197 		break;
1198 	case ESP_AUTH_ALG:
1199 		if (alg == NO_ESP_AALG) {
1200 			if (ipsr->ipsr_esp_alg == SADB_EALG_NONE ||
1201 			    ipsr->ipsr_esp_alg == SADB_EALG_NULL)
1202 				ipsr->ipsr_esp_req = 0;
1203 			ipsr->ipsr_esp_auth_alg = SADB_AALG_NONE;
1204 		} else {
1205 			ipsr->ipsr_esp_req =
1206 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
1207 			ipsr->ipsr_esp_auth_alg = alg;
1208 
1209 			/* Let the user specify NULL encryption implicitly. */
1210 			if (ipsr->ipsr_esp_alg == SADB_EALG_NONE &&
1211 			    !encr_alg_set)
1212 				ipsr->ipsr_esp_alg = SADB_EALG_NULL;
1213 		}
1214 		break;
1215 	case AH_AUTH_ALG:
1216 		if (alg == NO_AH_AALG) {
1217 			ipsr->ipsr_ah_req = 0;
1218 			ipsr->ipsr_auth_alg = SADB_AALG_NONE;
1219 		} else {
1220 			ipsr->ipsr_ah_req =
1221 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
1222 			ipsr->ipsr_auth_alg = alg;
1223 		}
1224 		break;
1225 		/* Will never hit DEFAULT */
1226 	}
1227 
1228 	if (ioctl(s, SIOCSTUNPARAM, (caddr_t)&treq) < 0) {
1229 		Perror2_exit("set tunnel security properties",
1230 		    treq.ifta_lifr_name);
1231 	}
1232 
1233 	return (0);
1234 }
1235 
1236 /* ARGSUSED */
1237 static int
1238 set_tun_esp_encr_alg(char *addr, int64_t param)
1239 {
1240 	return (set_tun_algs(ESP_ENCR_ALG,
1241 		    parsealg(addr, IPSEC_PROTO_ESP)));
1242 }
1243 
1244 /* ARGSUSED */
1245 static int
1246 set_tun_esp_auth_alg(char *addr, int64_t param)
1247 {
1248 	return (set_tun_algs(ESP_AUTH_ALG,
1249 		    parsealg(addr, IPSEC_PROTO_AH)));
1250 }
1251 
1252 /* ARGSUSED */
1253 static int
1254 set_tun_ah_alg(char *addr, int64_t param)
1255 {
1256 	return (set_tun_algs(AH_AUTH_ALG,
1257 		    parsealg(addr, IPSEC_PROTO_AH)));
1258 }
1259 
1260 /* ARGSUSED */
1261 static int
1262 setifrevarp(char *arg, int64_t param)
1263 {
1264 	struct sockaddr_in	laddr;
1265 
1266 	if (afp->af_af == AF_INET6) {
1267 		(void) fprintf(stderr,
1268 		    "ifconfig: revarp not possible on IPv6 interface %s\n",
1269 		    name);
1270 		exit(1);
1271 	}
1272 	if (doifrevarp(name, &laddr)) {
1273 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1274 		laddr.sin_family = AF_INET;
1275 		(void) memcpy(&lifr.lifr_addr, &laddr, sizeof (laddr));
1276 		if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1277 			Perror0_exit("SIOCSLIFADDR");
1278 	}
1279 	return (0);
1280 }
1281 
1282 /* ARGSUSED */
1283 static int
1284 setifsubnet(char *addr, int64_t param)
1285 {
1286 	int prefixlen = 0;
1287 	struct	sockaddr_storage subnet;
1288 
1289 	(*afp->af_getaddr)(addr, &subnet, &prefixlen);
1290 
1291 	switch (prefixlen) {
1292 	case NO_PREFIX:
1293 		(void) fprintf(stderr,
1294 		    "ifconfig: Missing prefix length in subnet %s\n", addr);
1295 		exit(1);
1296 		/* NOTREACHED */
1297 	case BAD_ADDR:
1298 		(void) fprintf(stderr,
1299 		    "ifconfig: Bad prefix length in %s\n", addr);
1300 		exit(1);
1301 	default:
1302 		break;
1303 	}
1304 
1305 	lifr.lifr_addr = subnet;
1306 	lifr.lifr_addrlen = prefixlen;
1307 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1308 	if (ioctl(s, SIOCSLIFSUBNET, (caddr_t)&lifr) < 0)
1309 		Perror0_exit("SIOCSLIFSUBNET");
1310 
1311 	return (0);
1312 }
1313 
1314 /* ARGSUSED */
1315 static int
1316 setifnetmask(char *addr, int64_t param)
1317 {
1318 	struct sockaddr_in netmask;
1319 
1320 	assert(afp->af_af != AF_INET6);
1321 
1322 	if (strcmp(addr, "+") == 0) {
1323 		if (!in_getmask(&netmask, _B_FALSE))
1324 			return (0);
1325 		(void) printf("Setting netmask of %s to %s\n", name,
1326 		    inet_ntoa(netmask.sin_addr));
1327 	} else {
1328 		in_getaddr(addr, (struct sockaddr *)&netmask, NULL);
1329 	}
1330 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1331 	(void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask));
1332 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1333 		Perror0_exit("SIOCSLIFNETMASK");
1334 	return (0);
1335 }
1336 
1337 /*
1338  * Parse '/<n>' as a netmask.
1339  */
1340 /* ARGSUSED */
1341 static int
1342 setifprefixlen(char *addr, int64_t param)
1343 {
1344 	int prefixlen;
1345 	int af = afp->af_af;
1346 
1347 	prefixlen = in_getprefixlen(addr, _B_TRUE,
1348 	    (af == AF_INET) ? IP_ABITS : IPV6_ABITS);
1349 	if (prefixlen < 0) {
1350 		(void) fprintf(stderr,
1351 		    "ifconfig: Bad prefix length in %s\n", addr);
1352 		exit(1);
1353 	}
1354 	(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
1355 	lifr.lifr_addr.ss_family = af;
1356 	if (af == AF_INET6) {
1357 		struct sockaddr_in6 *sin6;
1358 
1359 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1360 		if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
1361 		    (uchar_t *)&sin6->sin6_addr)) {
1362 			(void) fprintf(stderr, "ifconfig: "
1363 			    "Bad prefix length: %d\n",
1364 			    prefixlen);
1365 			exit(1);
1366 		}
1367 	} else if (af == AF_INET) {
1368 		struct sockaddr_in *sin;
1369 
1370 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
1371 		if (!in_prefixlentomask(prefixlen, IP_ABITS,
1372 		    (uchar_t *)&sin->sin_addr)) {
1373 			(void) fprintf(stderr, "ifconfig: "
1374 			    "Bad prefix length: %d\n",
1375 			    prefixlen);
1376 			exit(1);
1377 		}
1378 	} else {
1379 		(void) fprintf(stderr, "ifconfig: setting prefix only supported"
1380 		    " for address family inet or inet6\n");
1381 		exit(1);
1382 	}
1383 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1384 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1385 		Perror0_exit("SIOCSLIFNETMASK");
1386 	return (0);
1387 }
1388 
1389 /* ARGSUSED */
1390 static int
1391 setifbroadaddr(char *addr, int64_t param)
1392 {
1393 	struct	sockaddr_in broadaddr;
1394 
1395 	assert(afp->af_af != AF_INET6);
1396 
1397 	if (strcmp(addr, "+") == 0) {
1398 		/*
1399 		 * This doesn't set the broadcast address at all. Rather, it
1400 		 * gets, then sets the interface's address, relying on the fact
1401 		 * that resetting the address will reset the broadcast address.
1402 		 */
1403 		(void) strncpy(lifr.lifr_name, name,
1404 		    sizeof (lifr.lifr_name));
1405 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
1406 			if (errno != EADDRNOTAVAIL)
1407 				Perror0_exit("SIOCGLIFADDR");
1408 			return (0);
1409 		}
1410 		if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1411 			Perror0_exit("SIOCGLIFADDR");
1412 
1413 		return (0);
1414 	}
1415 	in_getaddr(addr, (struct sockaddr *)&broadaddr, NULL);
1416 
1417 	(void) memcpy(&lifr.lifr_addr, &broadaddr, sizeof (broadaddr));
1418 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1419 	if (ioctl(s, SIOCSLIFBRDADDR, (caddr_t)&lifr) < 0)
1420 		Perror0_exit("SIOCSLIFBRDADDR");
1421 	return (0);
1422 }
1423 
1424 /*
1425  * set interface destination address
1426  */
1427 /* ARGSUSED */
1428 static int
1429 setifdstaddr(char *addr, int64_t param)
1430 {
1431 	(*afp->af_getaddr)(addr, (struct sockaddr *)&lifr.lifr_addr, NULL);
1432 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1433 	if (ioctl(s, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0)
1434 		Perror0_exit("setifdstaddr: SIOCSLIFDSTADDR");
1435 	return (0);
1436 }
1437 
1438 /* ARGSUSED */
1439 static int
1440 setifflags(char *val, int64_t value)
1441 {
1442 	int phyintlen, origphyintlen;
1443 
1444 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1445 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0)
1446 		Perror0_exit("setifflags: SIOCGLIFFLAGS");
1447 
1448 	if (value == IFF_NOFAILOVER) {
1449 		/*
1450 		 * Fail if '-failover' is set after a prior addif created the
1451 		 * alias on a different interface. This can happen when the
1452 		 * interface is part of an IPMP group.
1453 		 */
1454 		phyintlen = strcspn(name, ":");
1455 		origphyintlen = strcspn(origname, ":");
1456 		if (phyintlen != origphyintlen ||
1457 		    strncmp(name, origname, phyintlen) != 0) {
1458 			(void) fprintf(stderr, "ifconfig: can't set -failover "
1459 			    "on failed/standby/offlined interface %s\n",
1460 			    origname);
1461 			exit(1);
1462 		}
1463 	}
1464 
1465 	if (value < 0) {
1466 		value = -value;
1467 		lifr.lifr_flags &= ~value;
1468 		if ((value & IFF_UP) && (lifr.lifr_flags & IFF_DUPLICATE)) {
1469 			/*
1470 			 * If the user is trying to mark an interface with a
1471 			 * duplicate address as "down," then fetch the address
1472 			 * and set it.  This will cause IP to clear the
1473 			 * IFF_DUPLICATE flag and stop the automatic recovery
1474 			 * timer.
1475 			 */
1476 			value = lifr.lifr_flags;
1477 			if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
1478 				(void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr);
1479 			lifr.lifr_flags = value;
1480 		}
1481 	} else {
1482 		lifr.lifr_flags |= value;
1483 	}
1484 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1485 	if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
1486 		Perror0_exit("setifflags: SIOCSLIFFLAGS");
1487 	}
1488 	return (0);
1489 }
1490 
1491 /* ARGSUSED */
1492 static int
1493 setifmetric(char *val, int64_t param)
1494 {
1495 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1496 	lifr.lifr_metric = atoi(val);
1497 	if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0)
1498 		Perror0_exit("setifmetric: SIOCSLIFMETRIC");
1499 	return (0);
1500 }
1501 
1502 /* ARGSUSED */
1503 static int
1504 setifmtu(char *val, int64_t param)
1505 {
1506 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1507 	lifr.lifr_mtu = atoi(val);
1508 	if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0)
1509 		Perror0_exit("setifmtu: SIOCSLIFMTU");
1510 	return (0);
1511 }
1512 
1513 /* ARGSUSED */
1514 static int
1515 setifindex(char *val, int64_t param)
1516 {
1517 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1518 	lifr.lifr_index = atoi(val);
1519 	if (ioctl(s, SIOCSLIFINDEX, (caddr_t)&lifr) < 0)
1520 		Perror0_exit("setifindex: SIOCSLIFINDEX");
1521 	return (0);
1522 }
1523 
1524 /* ARGSUSED */
1525 static int
1526 setifether(char *addr, int64_t param)
1527 {
1528 	uchar_t	*ea;
1529 	iface_t	*current;
1530 	int	maclen;
1531 
1532 	if (addr == NULL) {
1533 		ifstatus(name);
1534 		print_ifether(name);
1535 		return (0);
1536 	}
1537 
1538 	phyif = NULL;
1539 	logifs = NULL;
1540 
1541 	/*
1542 	 * if the IP interface in the arguments is a logical
1543 	 * interface, exit with an error now.
1544 	 */
1545 	if (strchr(name, ':') != NULL) {
1546 		(void) fprintf(stderr, "ifconfig: cannot change"
1547 		    " ethernet address of a logical interface\n");
1548 		exit(1);
1549 	}
1550 
1551 	ea = _link_aton(addr, &maclen);
1552 	if (ea == NULL) {
1553 		if (maclen == -1)
1554 			(void) fprintf(stderr,
1555 			    "ifconfig: %s: bad address\n", addr);
1556 		else
1557 			(void) fprintf(stderr, "ifconfig: malloc() failed\n");
1558 		exit(1);
1559 	}
1560 
1561 	(void) strncpy(savedname, name, sizeof (savedname));
1562 
1563 	/*
1564 	 * Call selectifs only for the IP interfaces that are ipv4.
1565 	 * offflags == IFF_IPV6 because you should not change the
1566 	 *		Ethernet address of an ipv6 interface
1567 	 */
1568 	foreachinterface(selectifs, 0, (char **)NULL, 0, 0, IFF_IPV6, 0);
1569 
1570 	/* If physical interface not found, exit now */
1571 	if (phyif == NULL) {
1572 		(void) fprintf(stderr,
1573 		    "ifconfig: interface %s not found\n", savedname);
1574 		exit(1);
1575 	}
1576 
1577 	/* Restore */
1578 	(void) strncpy(name, savedname, sizeof (name));
1579 	(void) strncpy(origname, savedname, sizeof (origname));
1580 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1581 
1582 	/*
1583 	 * close and reopen the socket
1584 	 * we don't know which type of socket we have now
1585 	 */
1586 	(void) close(s);
1587 	s = socket(SOCKET_AF(AF_UNSPEC), SOCK_DGRAM, 0);
1588 	if (s < 0) {
1589 		Perror0_exit("socket");
1590 	}
1591 
1592 	/*
1593 	 * mark down the logical interfaces first,
1594 	 * and then the physical interface
1595 	 */
1596 	if (updownifs(logifs, 0) < 0 || updownifs(phyif, 0) < 0) {
1597 		Perror0_exit("mark down interface failed");
1598 	}
1599 
1600 	/*
1601 	 * Change the physical address
1602 	 */
1603 	if (dlpi_set_address(savedname, ea, maclen) == -1) {
1604 		(void) fprintf(stderr,
1605 		    "ifconfig: failed setting mac address on %s\n",
1606 		    savedname);
1607 	}
1608 
1609 	/*
1610 	 * if any interfaces were marked down before changing the
1611 	 * ethernet address, put them up again.
1612 	 * First the physical interface, then the logical ones.
1613 	 */
1614 	if (updownifs(phyif, 1) < 0 || updownifs(logifs, 1) < 0) {
1615 		Perror0_exit("mark down interface failed");
1616 	}
1617 
1618 	/* Free the memory allocated by selectifs */
1619 	free(phyif);
1620 	for (current = logifs; current != NULL; current = logifs) {
1621 		logifs = logifs->next;
1622 		free(current);
1623 	}
1624 
1625 	return (0);
1626 }
1627 
1628 /*
1629  * Print an interface's Ethernet address, if it has one.
1630  */
1631 static void
1632 print_ifether(char *ifname)
1633 {
1634 	int		protocol;
1635 	icfg_if_t	interface;
1636 	icfg_handle_t	handle;
1637 	int		fd;
1638 
1639 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1640 
1641 	fd = socket(AF_INET, SOCK_DGRAM, 0);
1642 	if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) {
1643 		/*
1644 		 * It's possible the interface is only configured for
1645 		 * IPv6; check again with AF_INET6.
1646 		 */
1647 		(void) close(fd);
1648 		fd = socket(AF_INET6, SOCK_DGRAM, 0);
1649 		if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) {
1650 			(void) close(fd);
1651 			return;
1652 		}
1653 	}
1654 	(void) close(fd);
1655 
1656 	/* Virtual interfaces don't have MAC addresses */
1657 	if (lifr.lifr_flags & IFF_VIRTUAL)
1658 		return;
1659 
1660 	/*
1661 	 * We must be careful to set if_protocol based on the current
1662 	 * properties of the interface.  For instance, if "ip.tun0" is
1663 	 * configured only as an IPv6 tunnel, then if_protocol must be
1664 	 * set to AF_INET6 or icfg_get_tunnel_lower() will fail and
1665 	 * we will falsely conclude that it's not a tunnel.
1666 	 */
1667 	interface.if_protocol = AF_INET;
1668 	if (lifr.lifr_flags & IFF_IPV6)
1669 		interface.if_protocol = AF_INET6;
1670 
1671 	(void) strncpy(interface.if_name, ifname, sizeof (interface.if_name));
1672 
1673 	if (icfg_open(&handle, &interface) == ICFG_SUCCESS) {
1674 		if (icfg_get_tunnel_lower(handle, &protocol) == ICFG_SUCCESS) {
1675 			/* Tunnel op succeeded -- it's a tunnel so skip */
1676 			icfg_close(handle);
1677 			return;
1678 		}
1679 		icfg_close(handle);
1680 	}
1681 
1682 	dlpi_print_address(ifname);
1683 }
1684 
1685 /*
1686  * static void selectifs(int argc, char *argv[], int af, struct lifreq *rp)
1687  *
1688  * Called inside setifether() to create a list of interfaces to
1689  * mark down/up when changing the Ethernet address.
1690  * If the current interface is the physical interface passed
1691  * as an argument to ifconfig, update phyif.
1692  * If the current interface is a logical interface associated
1693  * to the physical interface, add it to the logifs list.
1694  */
1695 /* ARGSUSED */
1696 static void
1697 selectifs(int argc, char *argv[], int af, struct lifreq *rp)
1698 {
1699 	char		*colonp;
1700 	int		length;
1701 	iface_t		*current;
1702 
1703 	/*
1704 	 *  savedname=	name of the IP interface to which you want to
1705 	 *		change ethernet address
1706 	 *  name=	name of the current IP interface
1707 	 */
1708 	colonp = strchr(name, ':');
1709 	if (colonp == NULL)
1710 		length = max(strlen(savedname), strlen(name));
1711 	else
1712 		length = max(strlen(savedname), colonp - name);
1713 	if (strncmp(savedname, name, length) == 0) {
1714 		(void) strcpy(lifr.lifr_name, name);
1715 		if (ioctl(s, SIOCGLIFFLAGS, &lifr) < 0) {
1716 			Perror0("selectifs: SIOCGLIFFLAGS");
1717 			return;
1718 		}
1719 
1720 		if ((current = malloc(sizeof (iface_t))) == NULL) {
1721 			Perror0_exit("selectifs: malloc failed\n");
1722 		}
1723 
1724 		if (colonp == NULL) {
1725 			/* this is the physical interface */
1726 			phyif = current;
1727 			bcopy(&lifr, &phyif->lifr, sizeof (struct lifreq));
1728 			phyif->next = NULL;
1729 		} else {
1730 			/* this is a logical interface */
1731 			bcopy(&lifr, &current->lifr, sizeof (struct lifreq));
1732 			current->next = logifs;
1733 			logifs = current;
1734 		}
1735 	}
1736 }
1737 
1738 /*
1739  * static int updownifs(iface_t *ifs, int up)
1740  *
1741  * It takes in input a list of IP interfaces (ifs)
1742  * and a flag (up).
1743  * It marks each interface in the list down (up = 0)
1744  * or up (up > 0). This is done ONLY if the IP
1745  * interface was originally up.
1746  *
1747  * Return values:
1748  *  0 = everything OK
1749  * -1 = problem
1750  */
1751 static int
1752 updownifs(iface_t *ifs, int up)
1753 {
1754 	iface_t *current;
1755 	int	ret = 0;
1756 	int 	save_errno;
1757 	char	savename[LIFNAMSIZ];
1758 	uint64_t orig_flags;
1759 
1760 	for (current = ifs; current != NULL; current = current->next) {
1761 		if (current->lifr.lifr_flags & IFF_UP) {
1762 			orig_flags = current->lifr.lifr_flags;
1763 			if (!up)
1764 				current->lifr.lifr_flags &= ~IFF_UP;
1765 			if (ioctl(s, SIOCSLIFFLAGS, &current->lifr) < 0) {
1766 				save_errno = errno;
1767 				(void) strcpy(savename,
1768 				    current->lifr.lifr_name);
1769 				ret = -1;
1770 			}
1771 			if (!up) /* restore the original flags */
1772 				current->lifr.lifr_flags = orig_flags;
1773 		}
1774 	}
1775 
1776 	if (ret == -1) {
1777 		(void) strcpy(lifr.lifr_name, savename);
1778 		errno = save_errno;
1779 	}
1780 	return (ret);
1781 }
1782 
1783 /*
1784  * Create the next unused logical interface using the original name
1785  * and assign the address (and mask if '/<n>' is part of the address).
1786  * Use the new logical interface for subsequent subcommands by updating
1787  * the name variable.
1788  *
1789  * This allows syntax like:
1790  *	ifconfig le0 addif 109.106.86.130 netmask + up \
1791  *	addif 109.106.86.131 netmask + up
1792  */
1793 /* ARGSUSED */
1794 static int
1795 addif(char *str, int64_t param)
1796 {
1797 	int prefixlen = 0;
1798 	struct sockaddr_storage laddr;
1799 	struct sockaddr_storage mask;
1800 
1801 	(void) strncpy(name, origname, sizeof (name));
1802 
1803 	if (strchr(name, ':') != NULL) {
1804 		(void) fprintf(stderr,
1805 		    "ifconfig: addif: bad physical interface name %s\n",
1806 		    name);
1807 		exit(1);
1808 	}
1809 
1810 	/*
1811 	 * clear so parser will interpret next address as source followed
1812 	 * by possible dest
1813 	 */
1814 	setaddr = 0;
1815 	(*afp->af_getaddr)(str, (struct sockaddr *)&laddr, &prefixlen);
1816 
1817 	switch (prefixlen) {
1818 	case NO_PREFIX:
1819 		/* Nothing there - ok */
1820 		break;
1821 	case BAD_ADDR:
1822 		(void) fprintf(stderr,
1823 		    "ifconfig: Bad prefix length in %s\n", str);
1824 		exit(1);
1825 	default:
1826 		(void) memset(&mask, 0, sizeof (mask));
1827 		mask.ss_family = afp->af_af;
1828 		if (afp->af_af == AF_INET6) {
1829 			struct sockaddr_in6 *sin6;
1830 			sin6 = (struct sockaddr_in6 *)&mask;
1831 			if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
1832 			    (uchar_t *)&sin6->sin6_addr)) {
1833 				(void) fprintf(stderr, "ifconfig: "
1834 				    "Bad prefix length: %d\n",
1835 				    prefixlen);
1836 				exit(1);
1837 			}
1838 		} else {
1839 			struct sockaddr_in *sin;
1840 
1841 			sin = (struct sockaddr_in *)&mask;
1842 			if (!in_prefixlentomask(prefixlen, IP_ABITS,
1843 			    (uchar_t *)&sin->sin_addr)) {
1844 				(void) fprintf(stderr, "ifconfig: "
1845 				    "Bad prefix length: %d\n",
1846 				    prefixlen);
1847 				exit(1);
1848 			}
1849 		}
1850 		g_netmask_set = G_NETMASK_NIL;
1851 		break;
1852 	}
1853 
1854 	/*
1855 	 * This is a "hack" to get around the problem of SIOCLIFADDIF.  The
1856 	 * problem is that this ioctl does not include the netmask when
1857 	 * adding a logical interface.  This is the same problem described
1858 	 * in the ifconfig() comments.  To get around this problem, we first
1859 	 * add the logical interface with a 0 address.  After that, we set
1860 	 * the netmask if provided.  Finally we set the interface address.
1861 	 */
1862 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1863 	(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
1864 
1865 	/* Note: no need to do DAD here since the interface isn't up yet. */
1866 
1867 	if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
1868 		Perror0_exit("addif: SIOCLIFADDIF");
1869 
1870 	(void) printf("Created new logical interface %s\n",
1871 	    lifr.lifr_name);
1872 	(void) strncpy(name, lifr.lifr_name, sizeof (name));
1873 
1874 	/*
1875 	 * Check and see if any "netmask" command is used and perform the
1876 	 * necessary operation.
1877 	 */
1878 	set_mask_lifreq(&lifr, &laddr, &mask);
1879 	/*
1880 	 * Only set the netmask if "netmask" command is used or a prefix is
1881 	 * provided.
1882 	 */
1883 	if (g_netmask_set == G_NETMASK_SET || prefixlen >= 0) {
1884 		if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1885 			Perror0_exit("addif: SIOCSLIFNETMASK");
1886 	}
1887 
1888 	/* Finally, we set the interface address. */
1889 	lifr.lifr_addr = laddr;
1890 	if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1891 		Perror0_exit("SIOCSLIFADDR");
1892 
1893 	/*
1894 	 * let parser know we got a source.
1895 	 * Next address, if given, should be dest
1896 	 */
1897 	setaddr++;
1898 	return (0);
1899 }
1900 
1901 /*
1902  * Remove a logical interface based on its IP address. Unlike addif
1903  * there is no '/<n>' here.
1904  * Verifies that the interface is down before it is removed.
1905  */
1906 /* ARGSUSED */
1907 static int
1908 removeif(char *str, int64_t param)
1909 {
1910 	struct sockaddr_storage laddr;
1911 
1912 	if (strchr(name, ':') != NULL) {
1913 		(void) fprintf(stderr,
1914 		    "ifconfig: removeif: bad physical interface name %s\n",
1915 		    name);
1916 		exit(1);
1917 	}
1918 
1919 	(*afp->af_getaddr)(str, &laddr, NULL);
1920 	lifr.lifr_addr = laddr;
1921 
1922 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1923 	if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
1924 		if (errno == EBUSY) {
1925 			/* This can only happen if ipif_id = 0 */
1926 			(void) fprintf(stderr,
1927 			    "ifconfig: removeif: can't remove interface: %s\n",
1928 			    name);
1929 			exit(1);
1930 		}
1931 		Perror0_exit("removeif: SIOCLIFREMOVEIF");
1932 	}
1933 	return (0);
1934 }
1935 
1936 /*
1937  * Set the address token for IPv6.
1938  */
1939 /* ARGSUSED */
1940 static int
1941 setiftoken(char *addr, int64_t param)
1942 {
1943 	int prefixlen = 0;
1944 	struct sockaddr_in6 token;
1945 
1946 	in6_getaddr(addr, (struct sockaddr *)&token, &prefixlen);
1947 	switch (prefixlen) {
1948 	case NO_PREFIX:
1949 		(void) fprintf(stderr,
1950 		    "ifconfig: Missing prefix length in subnet %s\n", addr);
1951 		exit(1);
1952 		/* NOTREACHED */
1953 	case BAD_ADDR:
1954 		(void) fprintf(stderr,
1955 		    "ifconfig: Bad prefix length in %s\n", addr);
1956 		exit(1);
1957 	default:
1958 		break;
1959 	}
1960 	(void) memcpy(&lifr.lifr_addr, &token, sizeof (token));
1961 	lifr.lifr_addrlen = prefixlen;
1962 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1963 	if (ioctl(s, SIOCSLIFTOKEN, (caddr_t)&lifr) < 0)  {
1964 		Perror0_exit("setiftoken: SIOCSLIFTOKEN");
1965 	}
1966 	return (0);
1967 }
1968 
1969 /*
1970  * Return value: 0 on success, -1 on failure.
1971  */
1972 static int
1973 connect_to_mpathd(int family)
1974 {
1975 	int s;
1976 	struct sockaddr_storage ss;
1977 	struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
1978 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
1979 	struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
1980 	int addrlen;
1981 	int ret;
1982 	int on;
1983 
1984 	s = socket(family, SOCK_STREAM, 0);
1985 	if (s < 0) {
1986 		Perror0_exit("connect_to_mpathd: socket");
1987 	}
1988 	(void) bzero((char *)&ss, sizeof (ss));
1989 	ss.ss_family = family;
1990 	/*
1991 	 * Need to bind to a privileged port. For non-root, this
1992 	 * will fail. in.mpathd verifies that only commands coming
1993 	 * from privileged ports succeed so that ordinary users
1994 	 * can't connect and start talking to in.mpathd
1995 	 */
1996 	on = 1;
1997 	if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on,
1998 	    sizeof (on)) < 0) {
1999 		Perror0_exit("connect_to_mpathd: setsockopt");
2000 	}
2001 	switch (family) {
2002 	case AF_INET:
2003 		sin->sin_port = 0;
2004 		sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2005 		addrlen = sizeof (struct sockaddr_in);
2006 		break;
2007 	case AF_INET6:
2008 		sin6->sin6_port = 0;
2009 		sin6->sin6_addr = loopback_addr;
2010 		addrlen = sizeof (struct sockaddr_in6);
2011 		break;
2012 	}
2013 	ret = bind(s, (struct sockaddr *)&ss, addrlen);
2014 	if (ret != 0) {
2015 		(void) close(s);
2016 		return (-1);
2017 	}
2018 
2019 	switch (family) {
2020 	case AF_INET:
2021 		sin->sin_port = htons(MPATHD_PORT);
2022 		break;
2023 	case AF_INET6:
2024 		sin6->sin6_port = htons(MPATHD_PORT);
2025 		break;
2026 	}
2027 	ret = connect(s, (struct sockaddr *)&ss, addrlen);
2028 	(void) close(s);
2029 	return (ret);
2030 }
2031 
2032 /* ARGSUSED */
2033 static int
2034 setifgroupname(char *grpname, int64_t param)
2035 {
2036 	if (debug) {
2037 		(void) printf("Setting groupname %s on interface %s\n",
2038 		    grpname, name);
2039 	}
2040 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2041 	(void) strncpy(lifr.lifr_groupname, grpname,
2042 	    sizeof (lifr.lifr_groupname));
2043 	if (ioctl(s, SIOCSLIFGROUPNAME, (caddr_t)&lifr) < 0) {
2044 		Perror0_exit("setifgroupname: SIOCSLIFGROUPNAME");
2045 	}
2046 
2047 	/*
2048 	 * If the SUNW_NO_MPATHD environment variable is set then don't
2049 	 * bother starting up in.mpathd.  See PSARC/2002/249 for the
2050 	 * depressing details on this bit of stupidity.
2051 	 */
2052 	if (getenv("SUNW_NO_MPATHD") != NULL) {
2053 		return (0);
2054 	}
2055 
2056 	/*
2057 	 * Try to connect to in.mpathd using IPv4. If we succeed,
2058 	 * we conclude that in.mpathd is running, and quit.
2059 	 */
2060 	if (connect_to_mpathd(AF_INET) == 0) {
2061 		/* connect succeeded, mpathd is already running */
2062 		return (0);
2063 	}
2064 	/*
2065 	 * Try to connect to in.mpathd using IPv6. If we succeed,
2066 	 * we conclude that in.mpathd is running, and quit.
2067 	 */
2068 	if (connect_to_mpathd(AF_INET6) == 0) {
2069 		/* connect succeeded, mpathd is already running */
2070 		return (0);
2071 	}
2072 
2073 	/*
2074 	 * in.mpathd may not be running. Start it now. If it is already
2075 	 * running, in.mpathd will take care of handling multiple incarnations
2076 	 * of itself. ifconfig only tries to optimize performance by not
2077 	 * starting another incarnation of in.mpathd.
2078 	 */
2079 	switch (fork()) {
2080 
2081 	case -1:
2082 		Perror0_exit("setifgroupname: fork");
2083 		/* NOTREACHED */
2084 	case 0:
2085 		(void) execl(MPATHD_PATH, MPATHD_PATH, NULL);
2086 		_exit(1);
2087 		/* NOTREACHED */
2088 	default:
2089 		return (0);
2090 	}
2091 }
2092 
2093 
2094 /*
2095  * To list all the modules above a given network interface.
2096  */
2097 /* ARGSUSED */
2098 static int
2099 modlist(char *null, int64_t param)
2100 {
2101 	int muxfd;
2102 	int ipfd_lowstr;
2103 	int arpfd_lowstr;
2104 	int num_mods;
2105 	int i;
2106 	struct str_list strlist;
2107 	int orig_arpid;
2108 
2109 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2110 	if (ip_domux2fd(&muxfd, &ipfd_lowstr, &arpfd_lowstr,
2111 	    &orig_arpid) < 0) {
2112 		return (-1);
2113 	}
2114 	if ((num_mods = ioctl(ipfd_lowstr, I_LIST, NULL)) < 0) {
2115 		Perror0("cannot I_LIST to get the number of modules");
2116 	} else {
2117 		if (debug > 0) {
2118 			(void) printf("Listing (%d) modules above %s\n",
2119 			    num_mods, name);
2120 		}
2121 
2122 		strlist.sl_nmods = num_mods;
2123 		strlist.sl_modlist = malloc(sizeof (struct str_mlist) *
2124 		    num_mods);
2125 		if (strlist.sl_modlist == NULL) {
2126 			Perror0("cannot malloc");
2127 		} else {
2128 			if (ioctl(ipfd_lowstr, I_LIST, (caddr_t)&strlist) < 0) {
2129 				Perror0("cannot I_LIST for module names");
2130 			} else {
2131 				for (i = 0; i < strlist.sl_nmods; i++) {
2132 				    (void) printf("%d %s\n", i,
2133 				    strlist.sl_modlist[i].l_name);
2134 				}
2135 			}
2136 			free(strlist.sl_modlist);
2137 		}
2138 	}
2139 	return (ip_plink(muxfd, ipfd_lowstr, arpfd_lowstr, orig_arpid));
2140 }
2141 
2142 #define	MODINSERT_OP	'i'
2143 #define	MODREMOVE_OP	'r'
2144 
2145 /*
2146  * To insert a module to the stream of the interface.  It is just a
2147  * wrapper.  The real function is modop().
2148  */
2149 /* ARGSUSED */
2150 static int
2151 modinsert(char *arg, int64_t param)
2152 {
2153 	return (modop(arg, MODINSERT_OP));
2154 }
2155 
2156 /*
2157  * To remove a module from the stream of the interface.  It is just a
2158  * wrapper.  The real function is modop().
2159  */
2160 /* ARGSUSED */
2161 static int
2162 modremove(char *arg, int64_t param)
2163 {
2164 	return (modop(arg, MODREMOVE_OP));
2165 }
2166 
2167 /*
2168  * Open a stream on /dev/udp, pop off all undesired modules (note that
2169  * the user may have configured autopush to add modules above or below
2170  * udp), and push the arp module onto raw IP.
2171  */
2172 static int
2173 open_arp_on_udp(char *udp_dev_name)
2174 {
2175 	int fd;
2176 	boolean_t popped;
2177 
2178 	if ((fd = open(udp_dev_name, O_RDWR)) == -1) {
2179 		Perror2("open", udp_dev_name);
2180 		return (-1);
2181 	}
2182 	errno = 0;
2183 	popped = _B_FALSE;
2184 	while (ioctl(fd, I_POP, 0) != -1)
2185 		popped = _B_TRUE;
2186 	if (!popped) {
2187 		Perror2("cannot pop", udp_dev_name);
2188 	} else if (errno != EINVAL) {
2189 		Perror2("pop", udp_dev_name);
2190 	} else if (ioctl(fd, I_PUSH, ARP_MOD_NAME) == -1) {
2191 		Perror2("arp PUSH", udp_dev_name);
2192 	} else {
2193 		return (fd);
2194 	}
2195 	(void) close(fd);
2196 	return (-1);
2197 }
2198 
2199 /*
2200  * Helper function for mod*() functions.  It gets a fd to the lower IP
2201  * stream and I_PUNLINK's the lower stream.  It also initializes the
2202  * global variable lifr.
2203  *
2204  * Param:
2205  *	int *udp_fd: (referenced) fd to /dev/udp (upper IP stream).
2206  *	int *fd: (referenced) fd to the lower IP stream.
2207  *
2208  * Return:
2209  *	-1 if operation fails, 0 otherwise.
2210  *
2211  * Please see the big block comment above plumb_one_device()
2212  * for the logic of the PLINK/PUNLINK
2213  */
2214 static int
2215 ip_domux2fd(int *muxfd, int *ipfd_lowstr, int *arpfd_lowstr, int *orig_arpid)
2216 {
2217 	int		ip_fd;
2218 	uint64_t	flags;
2219 	char		*udp_dev_name;
2220 	char		*ip_dev_name;
2221 
2222 	*orig_arpid = 0;
2223 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2224 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2225 		Perror0_exit("status: SIOCGLIFFLAGS");
2226 	}
2227 	flags = lifr.lifr_flags;
2228 	if (flags & IFF_IPV4) {
2229 		udp_dev_name = UDP_DEV_NAME;
2230 		ip_dev_name  = IP_DEV_NAME;
2231 	} else if (flags & IFF_IPV6) {
2232 		udp_dev_name = UDP6_DEV_NAME;
2233 		ip_dev_name  = IP6_DEV_NAME;
2234 	} else {
2235 		return (-1);
2236 	}
2237 
2238 	if ((ip_fd = open(ip_dev_name, O_RDWR)) < 0) {
2239 		Perror2("open", ip_dev_name);
2240 		return (-1);
2241 	}
2242 	if (ioctl(ip_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
2243 		Perror2("SIOCGLIFMUXID", ip_dev_name);
2244 		return (-1);
2245 	}
2246 	if (debug > 0) {
2247 		(void) printf("ARP_muxid %d IP_muxid %d\n",
2248 		    lifr.lifr_arp_muxid, lifr.lifr_ip_muxid);
2249 	}
2250 
2251 	if ((*muxfd = open_arp_on_udp(udp_dev_name)) == -1)
2252 		return (-1);
2253 
2254 	if (lifr.lifr_arp_muxid != 0) {
2255 		if ((*arpfd_lowstr = ioctl(*muxfd, _I_MUXID2FD,
2256 		    lifr.lifr_arp_muxid)) < 0) {
2257 			if ((errno == EINVAL) &&
2258 			    (flags & (IFF_NOARP | IFF_IPV6))) {
2259 				/*
2260 				 * Some plumbing utilities set the muxid to
2261 				 * -1 or some invalid value to signify that
2262 				 * there is no arp stream. Set the muxid to 0
2263 				 * before trying to unplumb the IP stream.
2264 				 * IP does not allow the IP stream to be
2265 				 * unplumbed if it sees a non-null arp muxid,
2266 				 * for consistency of IP-ARP streams.
2267 				 */
2268 				*orig_arpid = lifr.lifr_arp_muxid;
2269 				lifr.lifr_arp_muxid = 0;
2270 				(void) ioctl(*muxfd, SIOCSLIFMUXID,
2271 				    (caddr_t)&lifr);
2272 				*arpfd_lowstr = -1;
2273 			} else {
2274 				Perror0("_I_MUXID2FD");
2275 				return (-1);
2276 			}
2277 		} else if (ioctl(*muxfd, I_PUNLINK,
2278 		    lifr.lifr_arp_muxid) < 0) {
2279 			Perror2("I_PUNLINK", udp_dev_name);
2280 			return (-1);
2281 		}
2282 	} else {
2283 		*arpfd_lowstr = -1;
2284 	}
2285 
2286 	if ((*ipfd_lowstr = ioctl(*muxfd, _I_MUXID2FD,
2287 	    lifr.lifr_ip_muxid)) < 0) {
2288 		Perror0("_I_MUXID2FD");
2289 		/* Undo any changes we made */
2290 		if (*orig_arpid != 0) {
2291 			lifr.lifr_arp_muxid = *orig_arpid;
2292 			(void) ioctl(*muxfd, SIOCSLIFMUXID, (caddr_t)&lifr);
2293 		}
2294 		return (-1);
2295 	}
2296 	if (ioctl(*muxfd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) {
2297 		Perror2("I_PUNLINK", udp_dev_name);
2298 		/* Undo any changes we made */
2299 		if (*orig_arpid != 0) {
2300 			lifr.lifr_arp_muxid = *orig_arpid;
2301 			(void) ioctl(*muxfd, SIOCSLIFMUXID, (caddr_t)&lifr);
2302 		}
2303 		return (-1);
2304 	}
2305 	return (0);
2306 }
2307 
2308 /*
2309  * Helper function for mod*() functions.  It I_PLINK's back the upper and
2310  * lower IP streams.  Note that this function must be called after
2311  * ip_domux2fd().  In ip_domux2fd(), the global variable lifr is initialized
2312  * and ip_plink() needs information in lifr.  So ip_domux2fd() and ip_plink()
2313  * must be called in pairs.
2314  *
2315  * Param:
2316  *	int udp_fd: fd to /dev/udp (upper IP stream).
2317  *	int fd: fd to the lower IP stream.
2318  *
2319  * Return:
2320  *	-1 if operation fails, 0 otherwise.
2321  *
2322  * Please see the big block comment above plumb_one_device()
2323  * for the logic of the PLINK/PUNLINK
2324  */
2325 static int
2326 ip_plink(int muxfd, int ipfd_lowstr, int arpfd_lowstr, int orig_arpid)
2327 {
2328 	int ip_muxid;
2329 
2330 	ip_muxid = ioctl(muxfd, I_PLINK, ipfd_lowstr);
2331 	if (ip_muxid < 0) {
2332 		Perror2("I_PLINK", UDP_DEV_NAME);
2333 		return (-1);
2334 	}
2335 
2336 	/*
2337 	 * If there is an arp stream, plink it. If there is no
2338 	 * arp stream, then it is possible that the plumbing
2339 	 * utility could have stored any value in the arp_muxid.
2340 	 * If so, restore it from orig_arpid.
2341 	 */
2342 	if (arpfd_lowstr != -1) {
2343 		if (ioctl(muxfd, I_PLINK, arpfd_lowstr) < 0) {
2344 			Perror2("I_PLINK", UDP_DEV_NAME);
2345 			return (-1);
2346 		}
2347 	} else if (orig_arpid != 0) {
2348 		/* Undo the changes we did in ip_domux2fd */
2349 		lifr.lifr_arp_muxid = orig_arpid;
2350 		lifr.lifr_ip_muxid = ip_muxid;
2351 		(void) ioctl(muxfd, SIOCSLIFMUXID, (caddr_t)&lifr);
2352 	}
2353 
2354 	return (0);
2355 }
2356 
2357 /*
2358  * The real function to perform module insertion/removal.
2359  *
2360  * Param:
2361  *	char *arg: the argument string module_name@position
2362  *	char op: operation, either MODINSERT_OP or MODREMOVE_OP.
2363  *
2364  * Return:
2365  *	Before doing ip_domux2fd(), this function calls exit(1) in case of
2366  *	error.  After ip_domux2fd() is done, it returns -1 for error, 0
2367  *	otherwise.
2368  */
2369 static int
2370 modop(char *arg, char op)
2371 {
2372 	char *pos_p;
2373 	int muxfd;
2374 	int ipfd_lowstr;  /* IP stream (lower stream of mux) to be plinked */
2375 	int arpfd_lowstr; /* ARP stream (lower stream of mux) to be plinked */
2376 	struct strmodconf mod;
2377 	char *at_char = "@";
2378 	char *arg_str;
2379 	int orig_arpid;
2380 
2381 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2382 
2383 	/* Need to save the original string for -a option. */
2384 	if ((arg_str = malloc(strlen(arg) + 1)) == NULL) {
2385 		Perror0("cannot malloc");
2386 		return (-1);
2387 	}
2388 	(void) strcpy(arg_str, arg);
2389 
2390 	if (*arg_str == *at_char) {
2391 		(void) fprintf(stderr,
2392 		    "ifconfig: must supply a module name\n");
2393 		exit(1);
2394 	}
2395 	mod.mod_name = strtok(arg_str, at_char);
2396 	if (strlen(mod.mod_name) > FMNAMESZ) {
2397 		(void) fprintf(stderr, "ifconfig: module name too long: %s\n",
2398 		    mod.mod_name);
2399 		exit(1);
2400 	}
2401 
2402 	/*
2403 	 * Need to make sure that the core TCP/IP stack modules are not
2404 	 * removed.  Otherwise, "bad" things can happen.  If a module
2405 	 * is removed and inserted back, it loses its old state.  But
2406 	 * the modules above it still have the old state.  E.g. IP assumes
2407 	 * fast data path while tunnel after re-inserted assumes that it can
2408 	 * receive M_DATA only in fast data path for which it does not have
2409 	 * any state.  This is a general caveat of _I_REMOVE/_I_INSERT.
2410 	 */
2411 	if (op == MODREMOVE_OP &&
2412 	    (strcmp(mod.mod_name, ARP_MOD_NAME) == 0 ||
2413 	    strcmp(mod.mod_name, IP_MOD_NAME) == 0 ||
2414 	    strcmp(mod.mod_name, TUN_NAME) == 0 ||
2415 	    strcmp(mod.mod_name, ATUN_NAME) == 0 ||
2416 	    strcmp(mod.mod_name, TUN6TO4_NAME) == 0)) {
2417 		(void) fprintf(stderr, "ifconfig: cannot remove %s\n",
2418 		    mod.mod_name);
2419 		exit(1);
2420 	}
2421 
2422 	if ((pos_p = strtok(NULL, at_char)) == NULL) {
2423 		(void) fprintf(stderr, "ifconfig: must supply a position\n");
2424 		exit(1);
2425 	}
2426 	mod.pos = atoi(pos_p);
2427 
2428 	if (ip_domux2fd(&muxfd, &ipfd_lowstr, &arpfd_lowstr,
2429 	    &orig_arpid) < 0) {
2430 		free(arg_str);
2431 		return (-1);
2432 	}
2433 	switch (op) {
2434 	case MODINSERT_OP:
2435 		if (debug > 0) {
2436 			(void) printf("Inserting module %s at %d\n",
2437 			    mod.mod_name, mod.pos);
2438 		}
2439 		if (ioctl(ipfd_lowstr, _I_INSERT, (caddr_t)&mod) < 0) {
2440 			Perror2("fail to insert module", mod.mod_name);
2441 		}
2442 		break;
2443 	case MODREMOVE_OP:
2444 		if (debug > 0) {
2445 			(void) printf("Removing module %s at %d\n",
2446 			    mod.mod_name, mod.pos);
2447 		}
2448 		if (ioctl(ipfd_lowstr, _I_REMOVE, (caddr_t)&mod) < 0) {
2449 			Perror2("fail to remove module", mod.mod_name);
2450 		}
2451 		break;
2452 	default:
2453 		/* Should never get to here. */
2454 		(void) fprintf(stderr, "Unknown operation\n");
2455 		break;
2456 	}
2457 	free(arg_str);
2458 	return (ip_plink(muxfd, ipfd_lowstr, arpfd_lowstr, orig_arpid));
2459 }
2460 
2461 /*
2462  * Set tunnel source address
2463  */
2464 /* ARGSUSED */
2465 static int
2466 setiftsrc(char *addr, int64_t param)
2467 {
2468 	return (settaddr(addr, icfg_set_tunnel_src));
2469 }
2470 
2471 /*
2472  * Set tunnel destination address
2473  */
2474 /* ARGSUSED */
2475 static int
2476 setiftdst(char *addr, int64_t param)
2477 {
2478 	return (settaddr(addr, icfg_set_tunnel_dest));
2479 }
2480 
2481 /*
2482  * sets tunnels src|dst address.  settaddr() expects the following:
2483  * addr: Points to a printable string containing the address to be
2484  *       set, e.g. 129.153.128.110.
2485  * fn:   Pointer to a libinetcfg routine that will do the actual work.
2486  *       The only valid functions are icfg_set_tunnel_src and
2487  *       icfg_set_tunnel_dest.
2488  */
2489 static int
2490 settaddr(char *addr,
2491     int (*fn)(icfg_handle_t, const struct sockaddr *, socklen_t))
2492 {
2493 	icfg_handle_t handle;
2494 	icfg_if_t interface;
2495 	struct sockaddr_storage laddr;
2496 	int lower;
2497 	int rc;
2498 
2499 	if (strchr(name, ':') != NULL) {
2500 		errno = EPERM;
2501 		Perror0_exit("Tunnel params on logical interfaces");
2502 	}
2503 	(void) strncpy(interface.if_name, name, sizeof (interface.if_name));
2504 	interface.if_protocol = SOCKET_AF(af);
2505 
2506 	/* Open interface. */
2507 	if ((rc = icfg_open(&handle, &interface)) != ICFG_SUCCESS)
2508 		Perror0_exit((char *)icfg_errmsg(rc));
2509 
2510 	rc = icfg_get_tunnel_lower(handle, &lower);
2511 	if (rc != ICFG_SUCCESS)
2512 		Perror0_exit((char *)icfg_errmsg(rc));
2513 
2514 	if (lower == AF_INET) {
2515 		in_getaddr(addr, (struct sockaddr *)&laddr, NULL);
2516 	} else {
2517 		in6_getaddr(addr, (struct sockaddr *)&laddr, NULL);
2518 	}
2519 
2520 	/* Call fn to do the real work, and close the interface. */
2521 	rc = (*fn)(handle, (struct sockaddr *)&laddr,
2522 	    sizeof (struct sockaddr_storage));
2523 	icfg_close(handle);
2524 
2525 	if (rc != ICFG_SUCCESS)
2526 		Perror0_exit((char *)icfg_errmsg(rc));
2527 
2528 	return (0);
2529 }
2530 
2531 /* Set tunnel encapsulation limit. */
2532 /* ARGSUSED */
2533 static int
2534 set_tun_encap_limit(char *arg, int64_t param)
2535 {
2536 	short limit;
2537 	icfg_if_t interface;
2538 	icfg_handle_t handle;
2539 	int rc;
2540 
2541 	if (strchr(name, ':') != NULL) {
2542 		errno = EPERM;
2543 		Perror0_exit("Tunnel params on logical interfaces");
2544 	}
2545 
2546 	if ((sscanf(arg, "%hd", &limit) != 1) || (limit < 0) ||
2547 	    (limit > 255)) {
2548 		errno = EINVAL;
2549 		Perror0_exit("Invalid encapsulation limit");
2550 	}
2551 
2552 	/* Open interface for configuration. */
2553 	(void) strncpy(interface.if_name, name, sizeof (interface.if_name));
2554 	interface.if_protocol = SOCKET_AF(af);
2555 	if (icfg_open(&handle, &interface) != ICFG_SUCCESS)
2556 		Perror0_exit("couldn't open interface");
2557 
2558 	rc = icfg_set_tunnel_encaplimit(handle, (int)limit);
2559 	icfg_close(handle);
2560 
2561 	if (rc != ICFG_SUCCESS)
2562 		Perror0_exit("Could not configure tunnel encapsulation limit");
2563 
2564 	return (0);
2565 }
2566 
2567 /* Disable encapsulation limit. */
2568 /* ARGSUSED */
2569 static int
2570 clr_tun_encap_limit(char *arg, int64_t param)
2571 {
2572 	icfg_if_t interface;
2573 	icfg_handle_t handle;
2574 	int rc;
2575 
2576 	if (strchr(name, ':') != NULL) {
2577 		errno = EPERM;
2578 		Perror0_exit("Tunnel params on logical interfaces");
2579 	}
2580 
2581 	/* Open interface for configuration. */
2582 	(void) strncpy(interface.if_name, name, sizeof (interface.if_name));
2583 	interface.if_protocol = SOCKET_AF(af);
2584 	if (icfg_open(&handle, &interface) != ICFG_SUCCESS)
2585 		Perror0_exit("couldn't open interface");
2586 
2587 	rc = icfg_set_tunnel_encaplimit(handle, -1);
2588 	icfg_close(handle);
2589 
2590 	if (rc != ICFG_SUCCESS)
2591 		Perror0_exit((char *)icfg_errmsg(rc));
2592 
2593 	return (0);
2594 }
2595 
2596 /* Set tunnel hop limit. */
2597 /* ARGSUSED */
2598 static int
2599 set_tun_hop_limit(char *arg, int64_t param)
2600 {
2601 	unsigned short limit;
2602 	icfg_if_t interface;
2603 	icfg_handle_t handle;
2604 	int rc;
2605 
2606 	if (strchr(name, ':') != NULL) {
2607 		errno = EPERM;
2608 		Perror0_exit("Tunnel params on logical interfaces");
2609 	}
2610 
2611 	/*
2612 	 * Check limit here since it's really only an 8-bit unsigned quantity.
2613 	 */
2614 	if ((sscanf(arg, "%hu", &limit) != 1) || (limit > 255)) {
2615 		errno = EINVAL;
2616 		Perror0_exit("Invalid hop limit");
2617 	}
2618 
2619 	/* Open interface for configuration. */
2620 	(void) strncpy(interface.if_name, name, sizeof (interface.if_name));
2621 	interface.if_protocol = SOCKET_AF(af);
2622 	if (icfg_open(&handle, &interface) != ICFG_SUCCESS)
2623 		Perror0_exit("couldn't open interface");
2624 
2625 	rc = icfg_set_tunnel_hoplimit(handle, (uint8_t)limit);
2626 	icfg_close(handle);
2627 
2628 	if (rc != ICFG_SUCCESS)
2629 		Perror0_exit("Could not configure tunnel hop limit");
2630 
2631 	return (0);
2632 }
2633 
2634 /* Set zone ID */
2635 static int
2636 setzone(char *arg, int64_t param)
2637 {
2638 	zoneid_t zoneid = GLOBAL_ZONEID;
2639 
2640 	if (param == NEXTARG) {
2641 		/* zone must be active */
2642 		if ((zoneid = getzoneidbyname(arg)) == -1) {
2643 			(void) fprintf(stderr,
2644 			    "ifconfig: unknown zone '%s'\n", arg);
2645 			exit(1);
2646 		}
2647 	}
2648 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2649 	lifr.lifr_zoneid = zoneid;
2650 	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1)
2651 		Perror0_exit("SIOCSLIFZONE");
2652 	return (0);
2653 }
2654 
2655 /* Put interface into all zones */
2656 /* ARGSUSED */
2657 static int
2658 setallzones(char *arg, int64_t param)
2659 {
2660 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2661 	lifr.lifr_zoneid = ALL_ZONES;
2662 	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1)
2663 		Perror0_exit("SIOCSLIFZONE");
2664 	return (0);
2665 }
2666 
2667 /* Set source address to use */
2668 /* ARGSUSED */
2669 static int
2670 setifsrc(char *arg, int64_t param)
2671 {
2672 	uint_t ifindex = 0;
2673 	int rval;
2674 
2675 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2676 
2677 	/*
2678 	 * Argument can be either an interface name or "none". The latter means
2679 	 * that any previous selection is cleared.
2680 	 */
2681 
2682 	rval = strcmp(arg, name);
2683 	if (rval == 0) {
2684 		(void) fprintf(stderr,
2685 		    "ifconfig: Cannot specify same interface for usesrc"
2686 		    " group\n");
2687 		exit(1);
2688 	}
2689 
2690 	rval = strcmp(arg, NONE_STR);
2691 	if (rval != 0) {
2692 		if ((ifindex = if_nametoindex(arg)) == 0) {
2693 			(void) strncpy(lifr.lifr_name, arg, LIFNAMSIZ);
2694 			Perror0_exit("Could not get interface index");
2695 		}
2696 		lifr.lifr_index = ifindex;
2697 	} else {
2698 		if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) != 0)
2699 			Perror0_exit("Not a valid usesrc consumer");
2700 		lifr.lifr_index = 0;
2701 	}
2702 
2703 	if (debug)
2704 		(void) printf("setifsrc: lifr_name %s, lifr_index %d\n",
2705 		    lifr.lifr_name, lifr.lifr_index);
2706 
2707 	if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) == -1) {
2708 		if (rval == 0)
2709 			Perror0_exit("Cannot reset usesrc group");
2710 		else
2711 			Perror0_exit("Could not set source interface");
2712 	}
2713 
2714 	return (0);
2715 }
2716 
2717 /*
2718  * Print the interface status line associated with `ifname'
2719  */
2720 static void
2721 ifstatus(const char *ifname)
2722 {
2723 	uint64_t flags;
2724 	char if_usesrc_name[LIFNAMSIZ];
2725 	char *newbuf;
2726 	int n, numifs, rval = 0;
2727 	struct lifreq *lifrp;
2728 	struct lifsrcof lifs;
2729 
2730 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2731 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2732 		Perror0_exit("status: SIOCGLIFFLAGS");
2733 	}
2734 	flags = lifr.lifr_flags;
2735 
2736 	/*
2737 	 * In V4 compatibility mode, we don't print the IFF_IPV4 flag or
2738 	 * interfaces with IFF_IPV6 set.
2739 	 */
2740 	if (v4compat) {
2741 		flags &= ~IFF_IPV4;
2742 		if (flags & IFF_IPV6)
2743 			return;
2744 	}
2745 
2746 	(void) printf("%s: ", ifname);
2747 	print_flags(flags);
2748 
2749 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2750 	if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) {
2751 		Perror0_exit("status: SIOCGLIFMETRIC");
2752 	} else {
2753 		if (lifr.lifr_metric)
2754 			(void) printf(" metric %d", lifr.lifr_metric);
2755 	}
2756 	if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0)
2757 		(void) printf(" mtu %d", lifr.lifr_metric);
2758 
2759 	/* don't print index or zone when in compatibility mode */
2760 	if (!v4compat) {
2761 		if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0)
2762 			(void) printf(" index %d", lifr.lifr_index);
2763 		if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) >= 0 &&
2764 		    lifr.lifr_zoneid != getzoneid()) {
2765 			char zone_name[ZONENAME_MAX];
2766 
2767 			if (lifr.lifr_zoneid == ALL_ZONES) {
2768 				(void) printf("\n\tall-zones");
2769 			} else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
2770 			    sizeof (zone_name)) < 0) {
2771 				(void) printf("\n\tzone %d", lifr.lifr_zoneid);
2772 			} else {
2773 				(void) printf("\n\tzone %s", zone_name);
2774 			}
2775 		}
2776 	}
2777 
2778 	if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) {
2779 		lifs.lifs_ifindex = lifr.lifr_index;
2780 
2781 		/*
2782 		 * Find the number of interfaces that use this interfaces'
2783 		 * address as a source address
2784 		 */
2785 		lifs.lifs_buf = NULL;
2786 		lifs.lifs_maxlen = 0;
2787 		for (;;) {
2788 			/* The first pass will give the bufsize we need */
2789 			rval = ioctl(s, SIOCGLIFSRCOF, (char *)&lifs);
2790 			if (rval < 0) {
2791 				if (lifs.lifs_buf != NULL) {
2792 					free(lifs.lifs_buf);
2793 					lifs.lifs_buf = NULL;
2794 				}
2795 				lifs.lifs_len = 0;
2796 				break;
2797 			}
2798 			if (lifs.lifs_len <= lifs.lifs_maxlen)
2799 				break;
2800 			/* Use kernel's size + a small margin to avoid loops */
2801 			lifs.lifs_maxlen = lifs.lifs_len +
2802 			    5 * sizeof (struct lifreq);
2803 			/* For the first pass, realloc acts like malloc */
2804 			newbuf = realloc(lifs.lifs_buf, lifs.lifs_maxlen);
2805 			if (newbuf == NULL) {
2806 				if (lifs.lifs_buf != NULL) {
2807 					free(lifs.lifs_buf);
2808 					lifs.lifs_buf = NULL;
2809 				}
2810 				lifs.lifs_len = 0;
2811 				break;
2812 			}
2813 			lifs.lifs_buf = newbuf;
2814 		}
2815 
2816 
2817 		numifs = lifs.lifs_len / sizeof (struct lifreq);
2818 		if (numifs > 0) {
2819 			lifrp = lifs.lifs_req;
2820 			(void) printf("\n\tsrcof");
2821 			for (n = numifs; n > 0; n--, lifrp++) {
2822 				(void) printf(" %s", lifrp->lifr_name);
2823 			}
2824 		}
2825 
2826 		if (lifs.lifs_buf != NULL)
2827 			free(lifs.lifs_buf);
2828 	}
2829 
2830 	/* Find the interface whose source address this interface uses */
2831 	if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) {
2832 		if (lifr.lifr_index != 0) {
2833 			if (if_indextoname(lifr.lifr_index,
2834 			    if_usesrc_name) == NULL) {
2835 				(void) printf("\n\tusesrc ifIndex %d",
2836 				    lifr.lifr_index);
2837 			} else {
2838 				(void) printf("\n\tusesrc %s", if_usesrc_name);
2839 			}
2840 		}
2841 	}
2842 
2843 	(void) putchar('\n');
2844 }
2845 
2846 
2847 /*
2848  * Print the status of the interface.  If an address family was
2849  * specified, show it and it only; otherwise, show them all.
2850  */
2851 static void
2852 status(void)
2853 {
2854 	struct afswtch *p = afp;
2855 	uint64_t flags;
2856 
2857 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2858 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2859 		Perror0_exit("status: SIOCGLIFFLAGS");
2860 	}
2861 
2862 	flags = lifr.lifr_flags;
2863 
2864 	/*
2865 	 * Only print the interface status if the address family matches
2866 	 * the interface family flag.
2867 	 */
2868 	if (p != NULL) {
2869 		if (((p->af_af == AF_INET6) && (flags & IFF_IPV4)) ||
2870 		    ((p->af_af == AF_INET) && (flags & IFF_IPV6)))
2871 			return;
2872 	}
2873 
2874 	/*
2875 	 * In V4 compatibility mode, don't print IFF_IPV6 interfaces.
2876 	 */
2877 	if (v4compat && (flags & IFF_IPV6))
2878 		return;
2879 
2880 	ifstatus(name);
2881 
2882 	if (p != NULL) {
2883 		(*p->af_status)(1, flags);
2884 	} else {
2885 		for (p = afs; p->af_name; p++) {
2886 			(void) close(s);
2887 			s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0);
2888 			/* set global af for use in p->af_status */
2889 			af = p->af_af;
2890 			if (s == -1) {
2891 				Perror0_exit("socket");
2892 			}
2893 			(*p->af_status)(0, flags);
2894 		}
2895 
2896 		/*
2897 		 * Historically, 'ether' has been an address family,
2898 		 * so print it here.
2899 		 */
2900 		print_ifether(name);
2901 	}
2902 }
2903 
2904 /*
2905  * Print the status of the interface in a format that can be used to
2906  * reconfigure the interface later. Code stolen from status() above.
2907  */
2908 /* ARGSUSED */
2909 static int
2910 configinfo(char *null, int64_t param)
2911 {
2912 	struct afswtch *p = afp;
2913 	uint64_t flags;
2914 	char phydevname[LIFNAMSIZ];
2915 	char if_usesrc_name[LIFNAMSIZ];
2916 	char *cp;
2917 
2918 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2919 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2920 		Perror0_exit("status: SIOCGLIFFLAGS");
2921 	}
2922 	flags = lifr.lifr_flags;
2923 
2924 	if (debug) {
2925 		(void) printf("configinfo: name %s flags  0x%llx af_af %d\n",
2926 		    name, flags, p != NULL ? p->af_af : -1);
2927 	}
2928 
2929 	/* remove LIF component */
2930 	(void) strncpy(phydevname, name, sizeof (phydevname));
2931 	cp = strchr(phydevname, ':');
2932 	if (cp) {
2933 		*cp = 0;
2934 	}
2935 	phydevname[sizeof (phydevname) - 1] = '\0';
2936 
2937 	/*
2938 	 * if the interface is IPv4
2939 	 *	if we have a IPv6 address family restriction return
2940 	 *		so it won't print
2941 	 *	if we are in IPv4 compatibility mode, clear out IFF_IPV4
2942 	 *		so we don't print it.
2943 	 */
2944 	if (flags & IFF_IPV4) {
2945 		if (p && p->af_af == AF_INET6)
2946 			return (-1);
2947 		if (v4compat)
2948 			flags &= ~IFF_IPV4;
2949 
2950 		(void) printf("%s inet plumb", phydevname);
2951 	} else if (flags & IFF_IPV6) {
2952 		/*
2953 		 * else if the interface is IPv6
2954 		 *	if we have a IPv4 address family restriction return
2955 		 *	or we are in IPv4 compatibiltiy mode, return.
2956 		 */
2957 		if (p && p->af_af == AF_INET)
2958 			return (-1);
2959 		if (v4compat)
2960 			return (-1);
2961 
2962 		(void) printf("%s inet6 plumb", phydevname);
2963 	}
2964 
2965 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2966 	if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) {
2967 		Perror0_exit("configinfo: SIOCGLIFMETRIC");
2968 	} else {
2969 		if (lifr.lifr_metric)
2970 			(void) printf(" metric %d ", lifr.lifr_metric);
2971 	}
2972 	if (((flags & (IFF_VIRTUAL|IFF_LOOPBACK)) != IFF_VIRTUAL) &&
2973 		ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0)
2974 		(void) printf(" mtu %d", lifr.lifr_metric);
2975 
2976 	/* don't print index when in compatibility mode */
2977 	if (!v4compat) {
2978 		if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0)
2979 			(void) printf(" index %d", lifr.lifr_index);
2980 	}
2981 
2982 	if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) {
2983 		if (lifr.lifr_index != 0) {
2984 			if (if_indextoname(lifr.lifr_index,
2985 			    if_usesrc_name) != NULL) {
2986 				(void) printf(" usesrc %s", if_usesrc_name);
2987 			}
2988 		}
2989 	}
2990 
2991 	if (p != NULL) {
2992 		(*p->af_configinfo)(1, flags);
2993 	} else {
2994 		for (p = afs; p->af_name; p++) {
2995 			(void) close(s);
2996 			s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0);
2997 			/* set global af for use in p->af_configinfo */
2998 			af = p->af_af;
2999 			if (s == -1) {
3000 				Perror0_exit("socket");
3001 			}
3002 			(*p->af_configinfo)(0, flags);
3003 		}
3004 	}
3005 
3006 	(void) printf("\n");
3007 
3008 	return (0);
3009 }
3010 
3011 static void
3012 print_tsec(struct iftun_req *tparams)
3013 {
3014 	ipsec_req_t *ipsr;
3015 
3016 	(void) printf("\ttunnel security settings  ");
3017 	/*
3018 	 * Deal with versioning, for now just point
3019 	 * an ipsec_req_t at ifta_secinfo.  If versions
3020 	 * change, something else will overlay ifta_secinfo.
3021 	 */
3022 	assert(tparams->ifta_vers == IFTUN_VERSION);
3023 
3024 	if (tparams->ifta_flags & IFTUN_COMPLEX_SECURITY) {
3025 		(void) printf("-->  use 'ipsecconf -ln -i %s'",
3026 		    tparams->ifta_lifr_name);
3027 	} else {
3028 		ipsr = (ipsec_req_t *)(&tparams->ifta_secinfo);
3029 		if (ipsr->ipsr_ah_req & IPSEC_PREF_REQUIRED) {
3030 			(void) printf("ah (%s)  ",
3031 			    rparsealg(ipsr->ipsr_auth_alg, IPSEC_PROTO_AH));
3032 		}
3033 		if (ipsr->ipsr_esp_req & IPSEC_PREF_REQUIRED) {
3034 			(void) printf("esp (%s",
3035 			    rparsealg(ipsr->ipsr_esp_alg, IPSEC_PROTO_ESP));
3036 			(void) printf("/%s)",
3037 			    rparsealg(ipsr->ipsr_esp_auth_alg, IPSEC_PROTO_AH));
3038 		}
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 |= DHCP_PRIMARY;
4488 
4489 	if (af != AF_INET)
4490 		type |= DHCP_V6;
4491 
4492 	request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE);
4493 	if (request == NULL) {
4494 		(void) fprintf(stderr, "%s: out of memory\n", caller);
4495 		return (DHCP_EXIT_SYSTEM);
4496 	}
4497 
4498 	error = dhcp_ipc_make_request(request, &reply, timeout);
4499 	if (error != 0) {
4500 		free(request);
4501 		/*
4502 		 * Re-map connect error to not under control if we didn't try a
4503 		 * start operation, as this has to be true and results in a
4504 		 * clearer message, not to mention preserving compatibility
4505 		 * with the days when we always started dhcpagent for every
4506 		 * request.
4507 		 */
4508 		if (error == DHCP_IPC_E_CONNECT && !started)
4509 			error = DHCP_IPC_E_UNKIF;
4510 		(void) fprintf(stderr, "%s: %s: %s\n", caller, ifname,
4511 		    dhcp_ipc_strerror(error));
4512 		return (DHCP_EXIT_FAILURE);
4513 	}
4514 
4515 	error = reply->return_code;
4516 	if (error != 0) {
4517 		free(request);
4518 		free(reply);
4519 
4520 		if (error == DHCP_IPC_E_TIMEOUT && timeout == 0)
4521 			return (DHCP_EXIT_SUCCESS);
4522 
4523 		(void) fprintf(stderr, "%s: %s: %s\n", caller, ifname,
4524 		    dhcp_ipc_strerror(error));
4525 
4526 		if (error == DHCP_IPC_E_TIMEOUT)
4527 			return (DHCP_EXIT_TIMEOUT);
4528 		else
4529 			return (DHCP_EXIT_IF_FAILURE);
4530 	}
4531 
4532 	if (DHCP_IPC_CMD(type) == DHCP_STATUS) {
4533 		(void) printf("%s", dhcp_status_hdr_string());
4534 		(void) printf("%s", dhcp_status_reply_to_string(reply));
4535 	}
4536 
4537 	free(request);
4538 	free(reply);
4539 	return (DHCP_EXIT_SUCCESS);
4540 }
4541 
4542 static void
4543 usage(void)
4544 {
4545 	(void) fprintf(stderr,
4546 	    "usage: ifconfig <interface> | -a[ 4 | 6 | D ][ u | d ][ Z ]\n");
4547 
4548 	(void) fprintf(stderr, "%s",
4549 	    "\t[ <addr_family> ]\n"
4550 	    "\t[ <address>[/<prefix_length>] [ <dest_address> ] ]\n"
4551 	    "\t[ set [ <address>][/<prefix_length>] ]"
4552 	    " [ <address>/<prefix_length>] ]\n"
4553 	    "\t[ destination <dest_address> ]\n"
4554 	    "\t[ addif <address>[/<prefix_length>]"
4555 	    "  [ <dest_address> ] ]\n"
4556 	    "\t[ removeif <address>[/<prefix_length>] ]\n"
4557 	    "\t[ arp | -arp ]\n"
4558 	    "\t[ auto-revarp ]\n"
4559 	    "\t[ broadcast <broad_addr> ]\n"
4560 	    "\t[ index <if_index> ]\n"
4561 	    "\t[ metric <n> ] [ mtu <n> ]\n"
4562 	    "\t[ netmask <mask> ]\n"
4563 	    "\t[ plumb ] [ unplumb ]\n"
4564 	    "\t[ preferred | -preferred ]\n"
4565 	    "\t[ private | -private ]\n"
4566 	    "\t[ local | -local ]\n"
4567 	    "\t[ router | -router ]\n"
4568 	    "\t[ subnet <subnet_address>]\n"
4569 	    "\t[ trailers | -trailers ]\n"
4570 	    "\t[ token <address>/<prefix_length> ]\n"
4571 	    "\t[ tsrc <tunnel_src_address> ]\n"
4572 	    "\t[ tdst <tunnel_dest_address> ]\n"
4573 	    "\t[ auth_algs <tunnel_AH_authentication_algorithm> ]\n"
4574 	    "\t[ encr_algs <tunnel_ESP_encryption_algorithm> ]\n"
4575 	    "\t[ encr_auth_algs <tunnel_ESP_authentication_algorithm> ]\n"
4576 	    "\t[ up ] [ down ]\n"
4577 	    "\t[ xmit | -xmit ]\n"
4578 	    "\t[ modlist ]\n"
4579 	    "\t[ modinsert <module_name@position> ]\n"
4580 	    "\t[ modremove <module_name@position> ]\n"
4581 	    "\t[ group <groupname>] | [ group \"\"]\n"
4582 	    "\t[ deprecated | -deprecated ]\n"
4583 	    "\t[ standby | -standby ]\n"
4584 	    "\t[ failover | -failover ]\n"
4585 	    "\t[ zone <zonename> | -zone ]\n"
4586 	    "\t[ usesrc <interface> ]\n"
4587 	    "\t[ all-zones ]\n");
4588 
4589 	(void) fprintf(stderr, "or\n");
4590 	(void) fprintf(stderr,
4591 	    "\tifconfig <interface> |  -a[ 4 | 6 | D ] [ u | d ]\n");
4592 
4593 	(void) fprintf(stderr, "%s", "\tauto-dhcp | dhcp\n"
4594 	    "\t[ wait <time> | forever ]\n\t[ primary ]\n"
4595 	    "\tstart | drop | ping | release | status | inform\n");
4596 }
4597