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