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