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