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