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