xref: /illumos-gate/usr/src/lib/libipadm/common/ipadm_prop.c (revision 236f16a23a31bb123a0ccf55b6ee546ee21cebbc)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2013, 2017 by Delphix. All rights reserved.
25  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
26  */
27 
28 /*
29  * This file contains routines that are used to modify/retrieve protocol or
30  * interface property values. It also holds all the supported properties for
31  * both IP interface and protocols in `ipadm_prop_desc_t'. Following protocols
32  * are supported: IP, IPv4, IPv6, TCP, SCTP, UDP and ICMP.
33  *
34  * This file also contains walkers, which walks through the property table and
35  * calls the callback function, of the form `ipadm_prop_wfunc_t' , for every
36  * property in the table.
37  */
38 
39 #include <unistd.h>
40 #include <errno.h>
41 #include <ctype.h>
42 #include <fcntl.h>
43 #include <strings.h>
44 #include <stdlib.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <sys/sockio.h>
48 #include <assert.h>
49 #include <libdllink.h>
50 #include <zone.h>
51 #include "libipadm_impl.h"
52 #include <inet/tunables.h>
53 
54 #define	IPADM_NONESTR		"none"
55 #define	DEF_METRIC_VAL		0	/* default metric value */
56 
57 #define	A_CNT(arr)	(sizeof (arr) / sizeof (arr[0]))
58 
59 static ipadm_status_t	i_ipadm_validate_if(ipadm_handle_t, const char *,
60 			    uint_t, uint_t);
61 
62 /*
63  * Callback functions to retrieve property values from the kernel. These
64  * functions, when required, translate the values from the kernel to a format
65  * suitable for printing. For example: boolean values will be translated
66  * to on/off. They also retrieve DEFAULT, PERM and POSSIBLE values for
67  * a given property.
68  */
69 static ipadm_pd_getf_t	i_ipadm_get_prop, i_ipadm_get_ifprop_flags,
70 			i_ipadm_get_mtu, i_ipadm_get_metric,
71 			i_ipadm_get_usesrc, i_ipadm_get_forwarding,
72 			i_ipadm_get_ecnsack, i_ipadm_get_hostmodel;
73 
74 /*
75  * Callback function to set property values. These functions translate the
76  * values to a format suitable for kernel consumption, allocates the necessary
77  * ioctl buffers and then invokes ioctl().
78  */
79 static ipadm_pd_setf_t	i_ipadm_set_prop, i_ipadm_set_mtu,
80 			i_ipadm_set_ifprop_flags,
81 			i_ipadm_set_metric, i_ipadm_set_usesrc,
82 			i_ipadm_set_forwarding, i_ipadm_set_eprivport,
83 			i_ipadm_set_ecnsack, i_ipadm_set_hostmodel;
84 
85 /* array of protocols we support */
86 static int protocols[] = { MOD_PROTO_IP, MOD_PROTO_RAWIP,
87 			    MOD_PROTO_TCP, MOD_PROTO_UDP,
88 			    MOD_PROTO_SCTP };
89 
90 /*
91  * Supported IP protocol properties.
92  */
93 static ipadm_prop_desc_t ipadm_ip_prop_table[] = {
94 	{ "arp", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
95 	    i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
96 	    i_ipadm_get_ifprop_flags },
97 
98 	{ "forwarding", NULL, IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV4, 0,
99 	    i_ipadm_set_forwarding, i_ipadm_get_onoff,
100 	    i_ipadm_get_forwarding },
101 
102 	{ "metric", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
103 	    i_ipadm_set_metric, NULL, i_ipadm_get_metric },
104 
105 	{ "mtu", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
106 	    i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
107 
108 	{ "exchange_routes", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
109 	    i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
110 	    i_ipadm_get_ifprop_flags },
111 
112 	{ "usesrc", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
113 	    i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
114 
115 	{ "ttl", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4, 0,
116 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
117 
118 	{ "forwarding", NULL, IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV6, 0,
119 	    i_ipadm_set_forwarding, i_ipadm_get_onoff,
120 	    i_ipadm_get_forwarding },
121 
122 	{ "hoplimit", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6, 0,
123 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
124 
125 	{ "metric", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
126 	    i_ipadm_set_metric, NULL, i_ipadm_get_metric },
127 
128 	{ "mtu", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
129 	    i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
130 
131 	{ "nud", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
132 	    i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
133 	    i_ipadm_get_ifprop_flags },
134 
135 	{ "exchange_routes", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
136 	    i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
137 	    i_ipadm_get_ifprop_flags },
138 
139 	{ "usesrc", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
140 	    i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
141 
142 	{ "hostmodel", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6, 0,
143 	    i_ipadm_set_hostmodel, i_ipadm_get_hostmodel,
144 	    i_ipadm_get_hostmodel },
145 
146 	{ "hostmodel", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4, 0,
147 	    i_ipadm_set_hostmodel, i_ipadm_get_hostmodel,
148 	    i_ipadm_get_hostmodel },
149 
150 	{ "standby", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IP, 0,
151 	    i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
152 	    i_ipadm_get_ifprop_flags },
153 
154 
155 	{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
156 };
157 
158 /* possible values for TCP properties `ecn' and `sack' */
159 static const char *ecn_sack_vals[] = {"never", "passive", "active", NULL};
160 
161 /* Supported TCP protocol properties */
162 static ipadm_prop_desc_t ipadm_tcp_prop_table[] = {
163 	{ "congestion_control", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
164 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
165 
166 	{ "ecn", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
167 	    i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack },
168 
169 	{ "extra_priv_ports", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
170 	    IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
171 	    i_ipadm_get_prop },
172 
173 	{ "largest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
174 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
175 
176 	{ "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
177 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
178 
179 	{ "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
180 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
181 
182 	{ "sack", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
183 	    i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack },
184 
185 	{ "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
186 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
187 
188 	{ "smallest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
189 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
190 
191 	{ "smallest_nonpriv_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
192 	    0, i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
193 
194 	{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
195 };
196 
197 /* Supported UDP protocol properties */
198 static ipadm_prop_desc_t ipadm_udp_prop_table[] = {
199 	{ "extra_priv_ports", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
200 	    IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
201 	    i_ipadm_get_prop },
202 
203 	{ "largest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
204 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
205 
206 	{ "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
207 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
208 
209 	{ "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
210 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
211 
212 	{ "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
213 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
214 
215 	{ "smallest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
216 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
217 
218 	{ "smallest_nonpriv_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
219 	    0, i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
220 
221 	{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
222 };
223 
224 /* Supported SCTP protocol properties */
225 static ipadm_prop_desc_t ipadm_sctp_prop_table[] = {
226 	{ "extra_priv_ports", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
227 	    IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
228 	    i_ipadm_get_prop },
229 
230 	{ "largest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
231 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
232 
233 	{ "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
234 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
235 
236 	{ "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
237 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
238 
239 	{ "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
240 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
241 
242 	{ "smallest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
243 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
244 
245 	{ "smallest_nonpriv_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
246 	    0, i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
247 
248 	{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
249 };
250 
251 /* Supported ICMP protocol properties */
252 static ipadm_prop_desc_t ipadm_icmp_prop_table[] = {
253 	{ "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 0,
254 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
255 
256 	{ "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 0,
257 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
258 
259 	{ "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 0,
260 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
261 
262 	{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
263 };
264 
265 /*
266  * A dummy private property structure, used while handling private
267  * protocol properties (properties not yet supported by libipadm).
268  */
269 static const ipadm_prop_desc_t ipadm_privprop_template =
270 	{ NULL, NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_NONE, 0,
271 	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop };
272 
273 /*
274  * Returns the property description table, for the given protocol
275  */
276 static ipadm_prop_desc_t *
i_ipadm_get_propdesc_table(uint_t proto)277 i_ipadm_get_propdesc_table(uint_t proto)
278 {
279 	switch (proto) {
280 	case MOD_PROTO_IP:
281 	case MOD_PROTO_IPV4:
282 	case MOD_PROTO_IPV6:
283 		return (ipadm_ip_prop_table);
284 	case MOD_PROTO_RAWIP:
285 		return (ipadm_icmp_prop_table);
286 	case MOD_PROTO_TCP:
287 		return (ipadm_tcp_prop_table);
288 	case MOD_PROTO_UDP:
289 		return (ipadm_udp_prop_table);
290 	case MOD_PROTO_SCTP:
291 		return (ipadm_sctp_prop_table);
292 	}
293 
294 	return (NULL);
295 }
296 
297 static ipadm_prop_desc_t *
i_ipadm_get_prop_desc(const char * pname,uint_t proto,int * errp)298 i_ipadm_get_prop_desc(const char *pname, uint_t proto, int *errp)
299 {
300 	int		err = 0;
301 	boolean_t	matched_name = B_FALSE;
302 	ipadm_prop_desc_t *ipdp = NULL, *ipdtbl;
303 
304 	if ((ipdtbl = i_ipadm_get_propdesc_table(proto)) == NULL) {
305 		err = EINVAL;
306 		goto ret;
307 	}
308 
309 	for (ipdp = ipdtbl; ipdp->ipd_name != NULL; ipdp++) {
310 		if (strcmp(pname, ipdp->ipd_name) == 0 ||
311 		    (ipdp->ipd_old_name != NULL &&
312 		    strcmp(pname, ipdp->ipd_old_name) == 0)) {
313 			matched_name = B_TRUE;
314 			if (ipdp->ipd_proto == proto)
315 				break;
316 		}
317 	}
318 
319 	if (ipdp->ipd_name == NULL) {
320 		err = ENOENT;
321 		/* if we matched name, but failed protocol check */
322 		if (matched_name)
323 			err = EPROTO;
324 		ipdp = NULL;
325 	}
326 ret:
327 	if (errp != NULL)
328 		*errp = err;
329 	return (ipdp);
330 }
331 
332 char *
ipadm_proto2str(uint_t proto)333 ipadm_proto2str(uint_t proto)
334 {
335 	switch (proto) {
336 	case MOD_PROTO_IP:
337 		return ("ip");
338 	case MOD_PROTO_IPV4:
339 		return ("ipv4");
340 	case MOD_PROTO_IPV6:
341 		return ("ipv6");
342 	case MOD_PROTO_RAWIP:
343 		return ("icmp");
344 	case MOD_PROTO_TCP:
345 		return ("tcp");
346 	case MOD_PROTO_UDP:
347 		return ("udp");
348 	case MOD_PROTO_SCTP:
349 		return ("sctp");
350 	}
351 
352 	return (NULL);
353 }
354 
355 uint_t
ipadm_str2proto(const char * protostr)356 ipadm_str2proto(const char *protostr)
357 {
358 	if (protostr == NULL)
359 		return (MOD_PROTO_NONE);
360 	if (strcmp(protostr, "tcp") == 0)
361 		return (MOD_PROTO_TCP);
362 	else if (strcmp(protostr, "udp") == 0)
363 		return (MOD_PROTO_UDP);
364 	else if (strcmp(protostr, "ip") == 0)
365 		return (MOD_PROTO_IP);
366 	else if (strcmp(protostr, "ipv4") == 0)
367 		return (MOD_PROTO_IPV4);
368 	else if (strcmp(protostr, "ipv6") == 0)
369 		return (MOD_PROTO_IPV6);
370 	else if (strcmp(protostr, "icmp") == 0)
371 		return (MOD_PROTO_RAWIP);
372 	else if (strcmp(protostr, "sctp") == 0)
373 		return (MOD_PROTO_SCTP);
374 	else if (strcmp(protostr, "arp") == 0)
375 		return (MOD_PROTO_IP);
376 
377 	return (MOD_PROTO_NONE);
378 }
379 
380 /* ARGSUSED */
381 static ipadm_status_t
i_ipadm_set_mtu(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t proto,uint_t flags)382 i_ipadm_set_mtu(ipadm_handle_t iph, const void *arg,
383     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
384 {
385 	struct lifreq	lifr;
386 	char		*endp;
387 	uint_t		mtu;
388 	int		s;
389 	const char	*ifname = arg;
390 	char		val[MAXPROPVALLEN];
391 
392 	/* to reset MTU first retrieve the default MTU and then set it */
393 	if (flags & IPADM_OPT_DEFAULT) {
394 		ipadm_status_t	status;
395 		uint_t		size = MAXPROPVALLEN;
396 
397 		status = i_ipadm_get_prop(iph, arg, pdp, val, &size,
398 		    proto, MOD_PROP_DEFAULT);
399 		if (status != IPADM_SUCCESS)
400 			return (status);
401 		pval = val;
402 	}
403 
404 	errno = 0;
405 	mtu = (uint_t)strtol(pval, &endp, 10);
406 	if (errno != 0 || *endp != '\0')
407 		return (IPADM_INVALID_ARG);
408 
409 	bzero(&lifr, sizeof (lifr));
410 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
411 	lifr.lifr_mtu = mtu;
412 
413 	s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
414 	if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0)
415 		return (ipadm_errno2status(errno));
416 
417 	return (IPADM_SUCCESS);
418 }
419 
420 /* ARGSUSED */
421 static ipadm_status_t
i_ipadm_set_metric(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t proto,uint_t flags)422 i_ipadm_set_metric(ipadm_handle_t iph, const void *arg,
423     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
424 {
425 	struct lifreq	lifr;
426 	char		*endp;
427 	int		metric;
428 	const char	*ifname = arg;
429 	int		s;
430 
431 	/* if we are resetting, set the value to its default value */
432 	if (flags & IPADM_OPT_DEFAULT) {
433 		metric = DEF_METRIC_VAL;
434 	} else {
435 		errno = 0;
436 		metric = (uint_t)strtol(pval, &endp, 10);
437 		if (errno != 0 || *endp != '\0')
438 			return (IPADM_INVALID_ARG);
439 	}
440 
441 	bzero(&lifr, sizeof (lifr));
442 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
443 	lifr.lifr_metric = metric;
444 
445 	s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
446 
447 	if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0)
448 		return (ipadm_errno2status(errno));
449 
450 	return (IPADM_SUCCESS);
451 }
452 
453 /* ARGSUSED */
454 static ipadm_status_t
i_ipadm_set_usesrc(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t proto,uint_t flags)455 i_ipadm_set_usesrc(ipadm_handle_t iph, const void *arg,
456     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
457 {
458 	struct lifreq	lifr;
459 	const char	*ifname = arg;
460 	int		s;
461 	uint_t		ifindex = 0;
462 
463 	/* if we are resetting, set the value to its default value */
464 	if (flags & IPADM_OPT_DEFAULT)
465 		pval = IPADM_NONESTR;
466 
467 	/*
468 	 * cannot specify logical interface name. We can also filter out other
469 	 * bogus interface names here itself through i_ipadm_validate_ifname().
470 	 */
471 	if (strcmp(pval, IPADM_NONESTR) != 0 &&
472 	    !i_ipadm_validate_ifname(iph, pval))
473 		return (IPADM_INVALID_ARG);
474 
475 	bzero(&lifr, sizeof (lifr));
476 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
477 
478 	s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
479 
480 	if (strcmp(pval, IPADM_NONESTR) != 0) {
481 		if ((ifindex = if_nametoindex(pval)) == 0)
482 			return (ipadm_errno2status(errno));
483 		lifr.lifr_index = ifindex;
484 	} else {
485 		if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
486 			return (ipadm_errno2status(errno));
487 		lifr.lifr_index = 0;
488 	}
489 	if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) < 0)
490 		return (ipadm_errno2status(errno));
491 
492 	return (IPADM_SUCCESS);
493 }
494 
495 static struct hostmodel_strval {
496 	char *esm_str;
497 	ip_hostmodel_t esm_val;
498 } esm_arr[] = {
499 	{"weak", IP_WEAK_ES},
500 	{"src-priority", IP_SRC_PRI_ES},
501 	{"strong", IP_STRONG_ES},
502 	{"custom", IP_MAXVAL_ES}
503 };
504 
505 static ip_hostmodel_t
i_ipadm_hostmodel_str2val(const char * pval)506 i_ipadm_hostmodel_str2val(const char *pval)
507 {
508 	int i;
509 
510 	for (i = 0; i < A_CNT(esm_arr); i++) {
511 		if (esm_arr[i].esm_str != NULL &&
512 		    strcmp(pval, esm_arr[i].esm_str) == 0) {
513 			return (esm_arr[i].esm_val);
514 		}
515 	}
516 	return (IP_MAXVAL_ES);
517 }
518 
519 static char *
i_ipadm_hostmodel_val2str(ip_hostmodel_t pval)520 i_ipadm_hostmodel_val2str(ip_hostmodel_t pval)
521 {
522 	int i;
523 
524 	for (i = 0; i < A_CNT(esm_arr); i++) {
525 		if (esm_arr[i].esm_val == pval)
526 			return (esm_arr[i].esm_str);
527 	}
528 	return (NULL);
529 }
530 
531 /* ARGSUSED */
532 static ipadm_status_t
i_ipadm_set_hostmodel(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t proto,uint_t flags)533 i_ipadm_set_hostmodel(ipadm_handle_t iph, const void *arg,
534     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
535 {
536 	ip_hostmodel_t hostmodel;
537 	char val[11]; /* covers uint32_max as a string */
538 
539 	if ((flags & IPADM_OPT_DEFAULT) == 0) {
540 		hostmodel = i_ipadm_hostmodel_str2val(pval);
541 		if (hostmodel == IP_MAXVAL_ES)
542 			return (IPADM_INVALID_ARG);
543 		(void) snprintf(val, sizeof (val), "%d", hostmodel);
544 		pval = val;
545 	}
546 	return (i_ipadm_set_prop(iph, NULL, pdp, pval, proto, flags));
547 }
548 
549 /* ARGSUSED */
550 static ipadm_status_t
i_ipadm_get_hostmodel(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)551 i_ipadm_get_hostmodel(ipadm_handle_t iph, const void *arg,
552     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
553     uint_t valtype)
554 {
555 	ip_hostmodel_t hostmodel;
556 	char *cp;
557 	size_t nbytes;
558 	ipadm_status_t status;
559 
560 	switch (valtype) {
561 	case MOD_PROP_PERM:
562 		nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
563 		break;
564 	case MOD_PROP_DEFAULT:
565 		nbytes = snprintf(buf, *bufsize, "weak");
566 		break;
567 	case MOD_PROP_ACTIVE:
568 		status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
569 		    valtype);
570 		if (status != IPADM_SUCCESS)
571 			return (status);
572 		bcopy(buf, &hostmodel, sizeof (hostmodel));
573 		cp = i_ipadm_hostmodel_val2str(hostmodel);
574 		nbytes = snprintf(buf, *bufsize, "%s",
575 		    (cp != NULL ? cp : "?"));
576 		break;
577 	case MOD_PROP_POSSIBLE:
578 		nbytes = snprintf(buf, *bufsize, "strong,src-priority,weak");
579 		break;
580 	default:
581 		return (IPADM_INVALID_ARG);
582 	}
583 	if (nbytes >= *bufsize) {
584 		/* insufficient buffer space */
585 		*bufsize = nbytes + 1;
586 		return (IPADM_NO_BUFS);
587 	}
588 	return (IPADM_SUCCESS);
589 }
590 
591 /* ARGSUSED */
592 static ipadm_status_t
i_ipadm_set_ifprop_flags(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t proto,uint_t flags)593 i_ipadm_set_ifprop_flags(ipadm_handle_t iph, const void *arg,
594     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
595 {
596 	ipadm_status_t	status = IPADM_SUCCESS;
597 	const char	*ifname = arg;
598 	uint64_t	on_flags = 0, off_flags = 0;
599 	boolean_t	on = B_FALSE;
600 	sa_family_t	af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
601 
602 	/* if we are resetting, set the value to its default value */
603 	if (flags & IPADM_OPT_DEFAULT) {
604 		if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
605 		    strcmp(pdp->ipd_name, "arp") == 0 ||
606 		    strcmp(pdp->ipd_name, "nud") == 0) {
607 			pval = IPADM_ONSTR;
608 		} else if (strcmp(pdp->ipd_name, "forwarding") == 0 ||
609 		    strcmp(pdp->ipd_name, "standby") == 0) {
610 			pval = IPADM_OFFSTR;
611 		} else {
612 			return (IPADM_PROP_UNKNOWN);
613 		}
614 	}
615 
616 	if (strcmp(pval, IPADM_ONSTR) == 0)
617 		on = B_TRUE;
618 	else if (strcmp(pval, IPADM_OFFSTR) == 0)
619 		on = B_FALSE;
620 	else
621 		return (IPADM_INVALID_ARG);
622 
623 	if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
624 		if (on)
625 			off_flags = IFF_NORTEXCH;
626 		else
627 			on_flags = IFF_NORTEXCH;
628 	} else if (strcmp(pdp->ipd_name, "arp") == 0) {
629 		if (on)
630 			off_flags = IFF_NOARP;
631 		else
632 			on_flags = IFF_NOARP;
633 	} else if (strcmp(pdp->ipd_name, "nud") == 0) {
634 		if (on)
635 			off_flags = IFF_NONUD;
636 		else
637 			on_flags = IFF_NONUD;
638 	} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
639 		if (on)
640 			on_flags = IFF_ROUTER;
641 		else
642 			off_flags = IFF_ROUTER;
643 	} else if (strcmp(pdp->ipd_name, "standby") == 0) {
644 		if (on)
645 			on_flags = IFF_STANDBY;
646 		else
647 			off_flags = IFF_STANDBY;
648 	}
649 
650 	if (on_flags || off_flags)  {
651 		status = i_ipadm_set_flags(iph, ifname, af, on_flags,
652 		    off_flags);
653 	}
654 	return (status);
655 }
656 
657 /* ARGSUSED */
658 static ipadm_status_t
i_ipadm_set_eprivport(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t proto,uint_t flags)659 i_ipadm_set_eprivport(ipadm_handle_t iph, const void *arg,
660     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
661 {
662 	nvlist_t	*portsnvl = NULL;
663 	nvpair_t	*nvp;
664 	ipadm_status_t	status = IPADM_SUCCESS;
665 	uint_t		count = 0;
666 
667 	if (flags & IPADM_OPT_DEFAULT) {
668 		assert(pval == NULL);
669 		return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
670 	}
671 
672 	if ((status = ipadm_str2nvlist(pval, &portsnvl, IPADM_NORVAL)) != 0)
673 		return (status);
674 
675 	/* count the number of ports */
676 	for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
677 	    nvp = nvlist_next_nvpair(portsnvl, nvp)) {
678 		++count;
679 	}
680 
681 	if (iph->iph_flags & IPH_INIT) {
682 		flags |= IPADM_OPT_APPEND;
683 	} else if (count > 1) {
684 		/*
685 		 * We allow only one port to be added, removed or
686 		 * assigned at a time.
687 		 *
688 		 * However on reboot, while initializing protocol
689 		 * properties, extra_priv_ports might have multiple
690 		 * values. Only in that case we allow setting multiple
691 		 * values.
692 		 */
693 		nvlist_free(portsnvl);
694 		return (IPADM_INVALID_ARG);
695 	}
696 
697 	for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
698 	    nvp = nvlist_next_nvpair(portsnvl, nvp)) {
699 		status = i_ipadm_set_prop(iph, arg, pdp, nvpair_name(nvp),
700 		    proto, flags);
701 		if (status != IPADM_SUCCESS)
702 			break;
703 	}
704 	nvlist_free(portsnvl);
705 	return (status);
706 }
707 
708 /* ARGSUSED */
709 static ipadm_status_t
i_ipadm_set_forwarding(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t proto,uint_t flags)710 i_ipadm_set_forwarding(ipadm_handle_t iph, const void *arg,
711     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
712 {
713 	const char	*ifname = arg;
714 	ipadm_status_t	status;
715 
716 	/*
717 	 * if interface name is provided, then set forwarding using the
718 	 * IFF_ROUTER flag
719 	 */
720 	if (ifname != NULL) {
721 		status = i_ipadm_set_ifprop_flags(iph, ifname, pdp, pval,
722 		    proto, flags);
723 	} else {
724 		char	*val = NULL;
725 
726 		/*
727 		 * if the caller is IPH_LEGACY, `pval' already contains
728 		 * numeric values.
729 		 */
730 		if (!(flags & IPADM_OPT_DEFAULT) &&
731 		    !(iph->iph_flags & IPH_LEGACY)) {
732 
733 			if (strcmp(pval, IPADM_ONSTR) == 0)
734 				val = "1";
735 			else if (strcmp(pval, IPADM_OFFSTR) == 0)
736 				val = "0";
737 			else
738 				return (IPADM_INVALID_ARG);
739 			pval = val;
740 		}
741 
742 		status = i_ipadm_set_prop(iph, ifname, pdp, pval, proto, flags);
743 	}
744 
745 	return (status);
746 }
747 
748 /* ARGSUSED */
749 static ipadm_status_t
i_ipadm_set_ecnsack(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t proto,uint_t flags)750 i_ipadm_set_ecnsack(ipadm_handle_t iph, const void *arg,
751     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
752 {
753 	uint_t		i;
754 	char		val[MAXPROPVALLEN];
755 
756 	/* if IPH_LEGACY is set, `pval' already contains numeric values */
757 	if (!(flags & IPADM_OPT_DEFAULT) && !(iph->iph_flags & IPH_LEGACY)) {
758 		for (i = 0; ecn_sack_vals[i] != NULL; i++) {
759 			if (strcmp(pval, ecn_sack_vals[i]) == 0)
760 				break;
761 		}
762 		if (ecn_sack_vals[i] == NULL)
763 			return (IPADM_INVALID_ARG);
764 		(void) snprintf(val, MAXPROPVALLEN, "%d", i);
765 		pval = val;
766 	}
767 
768 	return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
769 }
770 
771 /* ARGSUSED */
772 ipadm_status_t
i_ipadm_get_ecnsack(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)773 i_ipadm_get_ecnsack(ipadm_handle_t iph, const void *arg,
774     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
775     uint_t valtype)
776 {
777 	ipadm_status_t	status = IPADM_SUCCESS;
778 	uint_t		i, nbytes = 0;
779 
780 	switch (valtype) {
781 	case MOD_PROP_POSSIBLE:
782 		for (i = 0; ecn_sack_vals[i] != NULL; i++) {
783 			if (i == 0)
784 				nbytes += snprintf(buf + nbytes,
785 				    *bufsize - nbytes, "%s", ecn_sack_vals[i]);
786 			else
787 				nbytes += snprintf(buf + nbytes,
788 				    *bufsize - nbytes, ",%s", ecn_sack_vals[i]);
789 			if (nbytes >= *bufsize)
790 				break;
791 		}
792 		break;
793 	case MOD_PROP_PERM:
794 	case MOD_PROP_DEFAULT:
795 	case MOD_PROP_ACTIVE:
796 		status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
797 		    valtype);
798 
799 		/*
800 		 * If IPH_LEGACY is set, do not convert the value returned
801 		 * from kernel,
802 		 */
803 		if (iph->iph_flags & IPH_LEGACY)
804 			break;
805 
806 		/*
807 		 * For current and default value, convert the value returned
808 		 * from kernel to more discrete representation.
809 		 */
810 		if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
811 		    valtype == MOD_PROP_DEFAULT)) {
812 			i = atoi(buf);
813 			assert(i < 3);
814 			nbytes = snprintf(buf, *bufsize, "%s",
815 			    ecn_sack_vals[i]);
816 		}
817 		break;
818 	default:
819 		return (IPADM_INVALID_ARG);
820 	}
821 	if (nbytes >= *bufsize) {
822 		/* insufficient buffer space */
823 		*bufsize = nbytes + 1;
824 		return (IPADM_NO_BUFS);
825 	}
826 
827 	return (status);
828 }
829 
830 /* ARGSUSED */
831 static ipadm_status_t
i_ipadm_get_forwarding(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)832 i_ipadm_get_forwarding(ipadm_handle_t iph, const void *arg,
833     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
834     uint_t valtype)
835 {
836 	const char	*ifname = arg;
837 	ipadm_status_t	status = IPADM_SUCCESS;
838 
839 	/*
840 	 * if interface name is provided, then get forwarding status using
841 	 * SIOCGLIFFLAGS
842 	 */
843 	if (ifname != NULL) {
844 		status = i_ipadm_get_ifprop_flags(iph, ifname, pdp,
845 		    buf, bufsize, pdp->ipd_proto, valtype);
846 	} else {
847 		status = i_ipadm_get_prop(iph, ifname, pdp, buf,
848 		    bufsize, proto, valtype);
849 		/*
850 		 * If IPH_LEGACY is set, do not convert the value returned
851 		 * from kernel,
852 		 */
853 		if (iph->iph_flags & IPH_LEGACY)
854 			goto ret;
855 		if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
856 		    valtype == MOD_PROP_DEFAULT)) {
857 			uint_t	val = atoi(buf);
858 
859 			(void) snprintf(buf, *bufsize,
860 			    (val == 1 ? IPADM_ONSTR : IPADM_OFFSTR));
861 		}
862 	}
863 
864 ret:
865 	return (status);
866 }
867 
868 /* ARGSUSED */
869 static ipadm_status_t
i_ipadm_get_mtu(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)870 i_ipadm_get_mtu(ipadm_handle_t iph, const void *arg,
871     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
872     uint_t valtype)
873 {
874 	struct lifreq	lifr;
875 	const char	*ifname = arg;
876 	size_t		nbytes;
877 	int		s;
878 
879 	switch (valtype) {
880 	case MOD_PROP_PERM:
881 		nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
882 		break;
883 	case MOD_PROP_DEFAULT:
884 	case MOD_PROP_POSSIBLE:
885 		return (i_ipadm_get_prop(iph, arg, pdp, buf, bufsize,
886 		    proto, valtype));
887 	case MOD_PROP_ACTIVE:
888 		bzero(&lifr, sizeof (lifr));
889 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
890 		s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
891 
892 		if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) < 0)
893 			return (ipadm_errno2status(errno));
894 		nbytes = snprintf(buf, *bufsize, "%u", lifr.lifr_mtu);
895 		break;
896 	default:
897 		return (IPADM_INVALID_ARG);
898 	}
899 	if (nbytes >= *bufsize) {
900 		/* insufficient buffer space */
901 		*bufsize = nbytes + 1;
902 		return (IPADM_NO_BUFS);
903 	}
904 	return (IPADM_SUCCESS);
905 }
906 
907 /* ARGSUSED */
908 static ipadm_status_t
i_ipadm_get_metric(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)909 i_ipadm_get_metric(ipadm_handle_t iph, const void *arg,
910     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
911     uint_t valtype)
912 {
913 	struct lifreq	lifr;
914 	const char	*ifname = arg;
915 	size_t		nbytes;
916 	int		s, val;
917 
918 	switch (valtype) {
919 	case MOD_PROP_PERM:
920 		val = MOD_PROP_PERM_RW;
921 		break;
922 	case MOD_PROP_DEFAULT:
923 		val = DEF_METRIC_VAL;
924 		break;
925 	case MOD_PROP_ACTIVE:
926 		bzero(&lifr, sizeof (lifr));
927 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
928 
929 		s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
930 		if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0)
931 			return (ipadm_errno2status(errno));
932 		val = lifr.lifr_metric;
933 		break;
934 	default:
935 		return (IPADM_INVALID_ARG);
936 	}
937 	nbytes = snprintf(buf, *bufsize, "%d", val);
938 	if (nbytes >= *bufsize) {
939 		/* insufficient buffer space */
940 		*bufsize = nbytes + 1;
941 		return (IPADM_NO_BUFS);
942 	}
943 
944 	return (IPADM_SUCCESS);
945 }
946 
947 /* ARGSUSED */
948 static ipadm_status_t
i_ipadm_get_usesrc(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * ipd,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)949 i_ipadm_get_usesrc(ipadm_handle_t iph, const void *arg,
950     ipadm_prop_desc_t *ipd, char *buf, uint_t *bufsize, uint_t proto,
951     uint_t valtype)
952 {
953 	struct lifreq	lifr;
954 	const char	*ifname = arg;
955 	int		s;
956 	char		if_name[IF_NAMESIZE];
957 	size_t		nbytes;
958 
959 	switch (valtype) {
960 	case MOD_PROP_PERM:
961 		nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
962 		break;
963 	case MOD_PROP_DEFAULT:
964 		nbytes = snprintf(buf, *bufsize, "%s", IPADM_NONESTR);
965 		break;
966 	case MOD_PROP_ACTIVE:
967 		bzero(&lifr, sizeof (lifr));
968 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
969 
970 		s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
971 		if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
972 			return (ipadm_errno2status(errno));
973 		if (lifr.lifr_index == 0) {
974 			/* no src address was set, so print 'none' */
975 			(void) strlcpy(if_name, IPADM_NONESTR,
976 			    sizeof (if_name));
977 		} else if (if_indextoname(lifr.lifr_index, if_name) == NULL) {
978 			return (ipadm_errno2status(errno));
979 		}
980 		nbytes = snprintf(buf, *bufsize, "%s", if_name);
981 		break;
982 	default:
983 		return (IPADM_INVALID_ARG);
984 	}
985 	if (nbytes >= *bufsize) {
986 		/* insufficient buffer space */
987 		*bufsize = nbytes + 1;
988 		return (IPADM_NO_BUFS);
989 	}
990 	return (IPADM_SUCCESS);
991 }
992 
993 /* ARGSUSED */
994 static ipadm_status_t
i_ipadm_get_ifprop_flags(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)995 i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg,
996     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
997     uint_t valtype)
998 {
999 	uint64_t	intf_flags;
1000 	char		*val;
1001 	size_t		nbytes;
1002 	const char	*ifname = arg;
1003 	sa_family_t	af;
1004 	ipadm_status_t	status = IPADM_SUCCESS;
1005 
1006 	switch (valtype) {
1007 	case MOD_PROP_PERM:
1008 		nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
1009 		break;
1010 	case MOD_PROP_DEFAULT:
1011 		if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
1012 		    strcmp(pdp->ipd_name, "arp") == 0 ||
1013 		    strcmp(pdp->ipd_name, "nud") == 0) {
1014 			val = IPADM_ONSTR;
1015 		} else if (strcmp(pdp->ipd_name, "forwarding") == 0 ||
1016 		    strcmp(pdp->ipd_name, "standby") == 0) {
1017 			val = IPADM_OFFSTR;
1018 		} else {
1019 			return (IPADM_PROP_UNKNOWN);
1020 		}
1021 		nbytes = snprintf(buf, *bufsize, "%s", val);
1022 		break;
1023 	case MOD_PROP_ACTIVE:
1024 		af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
1025 		status = i_ipadm_get_flags(iph, ifname, af, &intf_flags);
1026 		if (status != IPADM_SUCCESS)
1027 			return (status);
1028 
1029 		val = IPADM_OFFSTR;
1030 		if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
1031 			if (!(intf_flags & IFF_NORTEXCH))
1032 				val = IPADM_ONSTR;
1033 		} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
1034 			if (intf_flags & IFF_ROUTER)
1035 				val = IPADM_ONSTR;
1036 		} else if (strcmp(pdp->ipd_name, "arp") == 0) {
1037 			if (!(intf_flags & IFF_NOARP))
1038 				val = IPADM_ONSTR;
1039 		} else if (strcmp(pdp->ipd_name, "nud") == 0) {
1040 			if (!(intf_flags & IFF_NONUD))
1041 				val = IPADM_ONSTR;
1042 		} else if (strcmp(pdp->ipd_name, "standby") == 0) {
1043 			if (intf_flags & IFF_STANDBY)
1044 				val = IPADM_ONSTR;
1045 		}
1046 		nbytes = snprintf(buf, *bufsize, "%s", val);
1047 		break;
1048 	default:
1049 		return (IPADM_INVALID_ARG);
1050 	}
1051 	if (nbytes >= *bufsize) {
1052 		/* insufficient buffer space */
1053 		*bufsize = nbytes + 1;
1054 		status = IPADM_NO_BUFS;
1055 	}
1056 
1057 	return (status);
1058 }
1059 
1060 static void
i_ipadm_perm2str(char * buf,uint_t * bufsize)1061 i_ipadm_perm2str(char *buf, uint_t *bufsize)
1062 {
1063 	uint_t perm = atoi(buf);
1064 
1065 	(void) snprintf(buf, *bufsize, "%c%c",
1066 	    ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
1067 	    ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
1068 }
1069 
1070 /* ARGSUSED */
1071 static ipadm_status_t
i_ipadm_get_prop(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)1072 i_ipadm_get_prop(ipadm_handle_t iph, const void *arg,
1073     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
1074     uint_t valtype)
1075 {
1076 	ipadm_status_t	status = IPADM_SUCCESS;
1077 	const char	*ifname = arg;
1078 	mod_ioc_prop_t	*mip;
1079 	char		*pname = pdp->ipd_name;
1080 	uint_t		iocsize;
1081 
1082 	/* allocate sufficient ioctl buffer to retrieve value */
1083 	iocsize = sizeof (mod_ioc_prop_t) + *bufsize - 1;
1084 	if ((mip = calloc(1, iocsize)) == NULL)
1085 		return (IPADM_NO_BUFS);
1086 
1087 	mip->mpr_version = MOD_PROP_VERSION;
1088 	mip->mpr_flags = valtype;
1089 	mip->mpr_proto = proto;
1090 	if (ifname != NULL) {
1091 		(void) strlcpy(mip->mpr_ifname, ifname,
1092 		    sizeof (mip->mpr_ifname));
1093 	}
1094 	(void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
1095 	mip->mpr_valsize = *bufsize;
1096 
1097 	if (i_ipadm_strioctl(iph->iph_sock, SIOCGETPROP, (char *)mip,
1098 	    iocsize) < 0) {
1099 		if (errno == ENOENT)
1100 			status = IPADM_PROP_UNKNOWN;
1101 		else
1102 			status = ipadm_errno2status(errno);
1103 	} else {
1104 		bcopy(mip->mpr_val, buf, *bufsize);
1105 	}
1106 
1107 	free(mip);
1108 	return (status);
1109 }
1110 
1111 /*
1112  * Populates the ipmgmt_prop_arg_t based on the class of property.
1113  *
1114  * For private protocol properties, while persisting information in ipadm
1115  * data store, to ensure there is no collision of namespace between ipadm
1116  * private nvpair names (which also starts with '_', see ipadm_ipmgmt.h)
1117  * and private protocol property names, we will prepend IPADM_PRIV_PROP_PREFIX
1118  * to property names.
1119  */
1120 static void
i_ipadm_populate_proparg(ipmgmt_prop_arg_t * pargp,ipadm_prop_desc_t * pdp,const char * pval,const void * object)1121 i_ipadm_populate_proparg(ipmgmt_prop_arg_t *pargp, ipadm_prop_desc_t *pdp,
1122     const char *pval, const void *object)
1123 {
1124 	const struct ipadm_addrobj_s *ipaddr;
1125 	uint_t		class = pdp->ipd_class;
1126 	uint_t		proto = pdp->ipd_proto;
1127 
1128 	(void) strlcpy(pargp->ia_pname, pdp->ipd_name,
1129 	    sizeof (pargp->ia_pname));
1130 	if (pval != NULL)
1131 		(void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
1132 
1133 	switch (class) {
1134 	case IPADMPROP_CLASS_MODULE:
1135 		/* if it's a private property then add the prefix. */
1136 		if (pdp->ipd_name[0] == '_') {
1137 			(void) snprintf(pargp->ia_pname,
1138 			    sizeof (pargp->ia_pname), "_%s", pdp->ipd_name);
1139 		}
1140 		(void) strlcpy(pargp->ia_module, object,
1141 		    sizeof (pargp->ia_module));
1142 		break;
1143 	case IPADMPROP_CLASS_MODIF:
1144 		/* check if object is protostr or an ifname */
1145 		if (ipadm_str2proto(object) != MOD_PROTO_NONE) {
1146 			(void) strlcpy(pargp->ia_module, object,
1147 			    sizeof (pargp->ia_module));
1148 			break;
1149 		}
1150 		/* it's an interface property, fall through */
1151 		/* FALLTHRU */
1152 	case IPADMPROP_CLASS_IF:
1153 		(void) strlcpy(pargp->ia_ifname, object,
1154 		    sizeof (pargp->ia_ifname));
1155 		(void) strlcpy(pargp->ia_module, ipadm_proto2str(proto),
1156 		    sizeof (pargp->ia_module));
1157 		break;
1158 	case IPADMPROP_CLASS_ADDR:
1159 		ipaddr = object;
1160 		(void) strlcpy(pargp->ia_ifname, ipaddr->ipadm_ifname,
1161 		    sizeof (pargp->ia_ifname));
1162 		(void) strlcpy(pargp->ia_aobjname, ipaddr->ipadm_aobjname,
1163 		    sizeof (pargp->ia_aobjname));
1164 		break;
1165 	}
1166 }
1167 
1168 /*
1169  * Common function to retrieve property value for a given interface `ifname' or
1170  * for a given protocol `proto'. The property name is in `pname'.
1171  *
1172  * `valtype' determines the type of value that will be retrieved.
1173  *	IPADM_OPT_ACTIVE -	current value of the property (active config)
1174  *	IPADM_OPT_PERSIST -	value of the property from persistent store
1175  *	IPADM_OPT_DEFAULT -	default hard coded value (boot-time value)
1176  *	IPADM_OPT_PERM -	read/write permissions for the value
1177  *	IPADM_OPT_POSSIBLE -	range of values
1178  */
1179 static ipadm_status_t
i_ipadm_getprop_common(ipadm_handle_t iph,const char * ifname,const char * pname,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)1180 i_ipadm_getprop_common(ipadm_handle_t iph, const char *ifname,
1181     const char *pname, char *buf, uint_t *bufsize, uint_t proto,
1182     uint_t valtype)
1183 {
1184 	ipadm_status_t		status = IPADM_SUCCESS;
1185 	ipadm_prop_desc_t	*pdp;
1186 	char			priv_propname[MAXPROPNAMELEN];
1187 	ipadm_prop_desc_t	ipadm_privprop = ipadm_privprop_template;
1188 	boolean_t		is_if = (ifname != NULL);
1189 	int			err = 0;
1190 
1191 	pdp = i_ipadm_get_prop_desc(pname, proto, &err);
1192 	if (err == EPROTO)
1193 		return (IPADM_BAD_PROTOCOL);
1194 	/* there are no private interface properties */
1195 	if (is_if && err == ENOENT)
1196 		return (IPADM_PROP_UNKNOWN);
1197 
1198 	if (pdp != NULL) {
1199 		/*
1200 		 * check whether the property can be
1201 		 * applied on an interface
1202 		 */
1203 		if (is_if && !(pdp->ipd_class & IPADMPROP_CLASS_IF))
1204 			return (IPADM_INVALID_ARG);
1205 		/*
1206 		 * check whether the property can be
1207 		 * applied on a module
1208 		 */
1209 		if (!is_if && !(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
1210 			return (IPADM_INVALID_ARG);
1211 
1212 	} else {
1213 		/* private protocol properties, pass it to kernel directly */
1214 		pdp = &ipadm_privprop;
1215 		(void) strlcpy(priv_propname, pname, sizeof (priv_propname));
1216 		pdp->ipd_name = priv_propname;
1217 	}
1218 
1219 	switch (valtype) {
1220 	case IPADM_OPT_PERM:
1221 		status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1222 		    MOD_PROP_PERM);
1223 		if (status == IPADM_SUCCESS)
1224 			i_ipadm_perm2str(buf, bufsize);
1225 		break;
1226 	case IPADM_OPT_ACTIVE:
1227 		status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1228 		    MOD_PROP_ACTIVE);
1229 		break;
1230 	case IPADM_OPT_DEFAULT:
1231 		status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1232 		    MOD_PROP_DEFAULT);
1233 		break;
1234 	case IPADM_OPT_POSSIBLE:
1235 		if (pdp->ipd_get_range != NULL) {
1236 			status = pdp->ipd_get_range(iph, ifname, pdp, buf,
1237 			    bufsize, proto, MOD_PROP_POSSIBLE);
1238 			break;
1239 		}
1240 		buf[0] = '\0';
1241 		break;
1242 	case IPADM_OPT_PERSIST:
1243 		/* retrieve from database */
1244 		if (is_if)
1245 			status = i_ipadm_get_persist_propval(iph, pdp, buf,
1246 			    bufsize, ifname);
1247 		else
1248 			status = i_ipadm_get_persist_propval(iph, pdp, buf,
1249 			    bufsize, ipadm_proto2str(proto));
1250 		break;
1251 	default:
1252 		status = IPADM_INVALID_ARG;
1253 		break;
1254 	}
1255 	return (status);
1256 }
1257 
1258 /*
1259  * Get protocol property of the specified protocol.
1260  */
1261 ipadm_status_t
ipadm_get_prop(ipadm_handle_t iph,const char * pname,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)1262 ipadm_get_prop(ipadm_handle_t iph, const char *pname, char *buf,
1263     uint_t *bufsize, uint_t proto, uint_t valtype)
1264 {
1265 	/*
1266 	 * validate the arguments of the function.
1267 	 */
1268 	if (iph == NULL || pname == NULL || buf == NULL ||
1269 	    bufsize == NULL || *bufsize == 0) {
1270 		return (IPADM_INVALID_ARG);
1271 	}
1272 	/*
1273 	 * Do we support this proto, if not return error.
1274 	 */
1275 	if (ipadm_proto2str(proto) == NULL)
1276 		return (IPADM_NOTSUP);
1277 
1278 	return (i_ipadm_getprop_common(iph, NULL, pname, buf, bufsize,
1279 	    proto, valtype));
1280 }
1281 
1282 /*
1283  * Get interface property of the specified interface.
1284  */
1285 ipadm_status_t
ipadm_get_ifprop(ipadm_handle_t iph,const char * ifname,const char * pname,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)1286 ipadm_get_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
1287     char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
1288 {
1289 	/* validate the arguments of the function. */
1290 	if (iph == NULL || pname == NULL || buf == NULL ||
1291 	    bufsize == NULL || *bufsize == 0) {
1292 		return (IPADM_INVALID_ARG);
1293 	}
1294 
1295 	/* Do we support this proto, if not return error. */
1296 	if (ipadm_proto2str(proto) == NULL)
1297 		return (IPADM_NOTSUP);
1298 
1299 	/*
1300 	 * check if interface name is provided for interface property and
1301 	 * is valid.
1302 	 */
1303 	if (!i_ipadm_validate_ifname(iph, ifname))
1304 		return (IPADM_INVALID_ARG);
1305 
1306 	return (i_ipadm_getprop_common(iph, ifname, pname, buf, bufsize,
1307 	    proto, valtype));
1308 }
1309 
1310 /*
1311  * Allocates sufficient ioctl buffers and copies property name and the
1312  * value, among other things. If the flag IPADM_OPT_DEFAULT is set, then
1313  * `pval' will be NULL and it instructs the kernel to reset the current
1314  * value to property's default value.
1315  */
1316 static ipadm_status_t
i_ipadm_set_prop(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t proto,uint_t flags)1317 i_ipadm_set_prop(ipadm_handle_t iph, const void *arg,
1318     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
1319 {
1320 	ipadm_status_t	status = IPADM_SUCCESS;
1321 	const char	*ifname = arg;
1322 	mod_ioc_prop_t	*mip;
1323 	char		*pname = pdp->ipd_name;
1324 	uint_t		valsize, iocsize;
1325 	uint_t		iocflags = 0;
1326 
1327 	if (flags & IPADM_OPT_DEFAULT) {
1328 		iocflags |= MOD_PROP_DEFAULT;
1329 	} else if (flags & IPADM_OPT_ACTIVE) {
1330 		iocflags |= MOD_PROP_ACTIVE;
1331 		if (flags & IPADM_OPT_APPEND)
1332 			iocflags |= MOD_PROP_APPEND;
1333 		else if (flags & IPADM_OPT_REMOVE)
1334 			iocflags |= MOD_PROP_REMOVE;
1335 	}
1336 
1337 	if (pval != NULL) {
1338 		valsize = strlen(pval);
1339 		iocsize = sizeof (mod_ioc_prop_t) + valsize - 1;
1340 	} else {
1341 		valsize = 0;
1342 		iocsize = sizeof (mod_ioc_prop_t);
1343 	}
1344 
1345 	if ((mip = calloc(1, iocsize)) == NULL)
1346 		return (IPADM_NO_BUFS);
1347 
1348 	mip->mpr_version = MOD_PROP_VERSION;
1349 	mip->mpr_flags = iocflags;
1350 	mip->mpr_proto = proto;
1351 	if (ifname != NULL) {
1352 		(void) strlcpy(mip->mpr_ifname, ifname,
1353 		    sizeof (mip->mpr_ifname));
1354 	}
1355 
1356 	(void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
1357 	mip->mpr_valsize = valsize;
1358 	if (pval != NULL)
1359 		bcopy(pval, mip->mpr_val, valsize);
1360 
1361 	if (i_ipadm_strioctl(iph->iph_sock, SIOCSETPROP, (char *)mip,
1362 	    iocsize) < 0) {
1363 		if (errno == ENOENT)
1364 			status = IPADM_PROP_UNKNOWN;
1365 		else
1366 			status = ipadm_errno2status(errno);
1367 	}
1368 	free(mip);
1369 	return (status);
1370 }
1371 
1372 /*
1373  * Common function for modifying both protocol/interface property.
1374  *
1375  * If:
1376  *   IPADM_OPT_PERSIST is set then the value is persisted.
1377  *   IPADM_OPT_DEFAULT is set then the default value for the property will
1378  *		       be applied.
1379  */
1380 static ipadm_status_t
i_ipadm_setprop_common(ipadm_handle_t iph,const char * ifname,const char * pname,const char * buf,uint_t proto,uint_t pflags)1381 i_ipadm_setprop_common(ipadm_handle_t iph, const char *ifname,
1382     const char *pname, const char *buf, uint_t proto, uint_t pflags)
1383 {
1384 	ipadm_status_t		status = IPADM_SUCCESS;
1385 	boolean_t		persist = (pflags & IPADM_OPT_PERSIST);
1386 	boolean_t		reset = (pflags & IPADM_OPT_DEFAULT);
1387 	ipadm_prop_desc_t	*pdp;
1388 	boolean_t		is_if = (ifname != NULL);
1389 	char			priv_propname[MAXPROPNAMELEN];
1390 	ipadm_prop_desc_t	ipadm_privprop = ipadm_privprop_template;
1391 	int			err = 0;
1392 
1393 	/* Check that property value is within the allowed size */
1394 	if (!reset && strnlen(buf, MAXPROPVALLEN) >= MAXPROPVALLEN)
1395 		return (IPADM_INVALID_ARG);
1396 
1397 	pdp = i_ipadm_get_prop_desc(pname, proto, &err);
1398 	if (err == EPROTO)
1399 		return (IPADM_BAD_PROTOCOL);
1400 	/* there are no private interface properties */
1401 	if (is_if && err == ENOENT)
1402 		return (IPADM_PROP_UNKNOWN);
1403 
1404 	if (pdp != NULL) {
1405 		/* do some sanity checks */
1406 		if (is_if) {
1407 			if (!(pdp->ipd_class & IPADMPROP_CLASS_IF))
1408 				return (IPADM_INVALID_ARG);
1409 		} else {
1410 			if (!(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
1411 				return (IPADM_INVALID_ARG);
1412 		}
1413 		/*
1414 		 * if the property is not multi-valued and IPADM_OPT_APPEND or
1415 		 * IPADM_OPT_REMOVE is specified, return IPADM_INVALID_ARG.
1416 		 */
1417 		if (!(pdp->ipd_flags & IPADMPROP_MULVAL) && (pflags &
1418 		    (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1419 			return (IPADM_INVALID_ARG);
1420 		}
1421 	} else {
1422 		/* private protocol property, pass it to kernel directly */
1423 		pdp = &ipadm_privprop;
1424 		(void) strlcpy(priv_propname, pname, sizeof (priv_propname));
1425 		pdp->ipd_name = priv_propname;
1426 	}
1427 
1428 	status = pdp->ipd_set(iph, ifname, pdp, buf, proto, pflags);
1429 	if (status != IPADM_SUCCESS)
1430 		return (status);
1431 
1432 	if (persist) {
1433 		if (is_if)
1434 			status = i_ipadm_persist_propval(iph, pdp, buf, ifname,
1435 			    pflags);
1436 		else
1437 			status = i_ipadm_persist_propval(iph, pdp, buf,
1438 			    ipadm_proto2str(proto), pflags);
1439 	}
1440 	return (status);
1441 }
1442 
1443 /*
1444  * Sets the property value of the specified interface
1445  */
1446 ipadm_status_t
ipadm_set_ifprop(ipadm_handle_t iph,const char * ifname,const char * pname,const char * buf,uint_t proto,uint_t pflags)1447 ipadm_set_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
1448     const char *buf, uint_t proto, uint_t pflags)
1449 {
1450 	boolean_t	reset = (pflags & IPADM_OPT_DEFAULT);
1451 	ipadm_status_t	status;
1452 
1453 	/* check for solaris.network.interface.config authorization */
1454 	if (!ipadm_check_auth())
1455 		return (IPADM_EAUTH);
1456 	/*
1457 	 * validate the arguments of the function.
1458 	 */
1459 	if (iph == NULL || pname == NULL || (!reset && buf == NULL) ||
1460 	    pflags == 0 || pflags == IPADM_OPT_PERSIST ||
1461 	    (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT))) {
1462 		return (IPADM_INVALID_ARG);
1463 	}
1464 
1465 	/*
1466 	 * Do we support this protocol, if not return error.
1467 	 */
1468 	if (ipadm_proto2str(proto) == NULL)
1469 		return (IPADM_NOTSUP);
1470 
1471 	/*
1472 	 * Validate the interface and check if a persistent
1473 	 * operation is performed on a temporary object.
1474 	 */
1475 	status = i_ipadm_validate_if(iph, ifname, proto, pflags);
1476 	if (status != IPADM_SUCCESS)
1477 		return (status);
1478 
1479 	return (i_ipadm_setprop_common(iph, ifname, pname, buf, proto,
1480 	    pflags));
1481 }
1482 
1483 /*
1484  * Sets the property value of the specified protocol.
1485  */
1486 ipadm_status_t
ipadm_set_prop(ipadm_handle_t iph,const char * pname,const char * buf,uint_t proto,uint_t pflags)1487 ipadm_set_prop(ipadm_handle_t iph, const char *pname, const char *buf,
1488     uint_t proto, uint_t pflags)
1489 {
1490 	boolean_t	reset = (pflags & IPADM_OPT_DEFAULT);
1491 
1492 	/* check for solaris.network.interface.config authorization */
1493 	if (!ipadm_check_auth())
1494 		return (IPADM_EAUTH);
1495 	/*
1496 	 * validate the arguments of the function.
1497 	 */
1498 	if (iph == NULL || pname == NULL ||(!reset && buf == NULL) ||
1499 	    pflags == 0 || pflags == IPADM_OPT_PERSIST ||
1500 	    (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT|
1501 	    IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1502 		return (IPADM_INVALID_ARG);
1503 	}
1504 
1505 	/*
1506 	 * Do we support this proto, if not return error.
1507 	 */
1508 	if (ipadm_proto2str(proto) == NULL)
1509 		return (IPADM_NOTSUP);
1510 
1511 	return (i_ipadm_setprop_common(iph, NULL, pname, buf, proto,
1512 	    pflags));
1513 }
1514 
1515 /* helper function for ipadm_walk_proptbl */
1516 static void
i_ipadm_walk_proptbl(ipadm_prop_desc_t * pdtbl,uint_t proto,uint_t class,ipadm_prop_wfunc_t * func,void * arg)1517 i_ipadm_walk_proptbl(ipadm_prop_desc_t *pdtbl, uint_t proto, uint_t class,
1518     ipadm_prop_wfunc_t *func, void *arg)
1519 {
1520 	ipadm_prop_desc_t	*pdp;
1521 
1522 	for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1523 		if (!(pdp->ipd_class & class))
1524 			continue;
1525 
1526 		if (proto != MOD_PROTO_NONE && !(pdp->ipd_proto & proto))
1527 			continue;
1528 
1529 		/*
1530 		 * we found a class specific match, call the
1531 		 * user callback function.
1532 		 */
1533 		if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
1534 			break;
1535 	}
1536 }
1537 
1538 /*
1539  * Walks through all the properties, for a given protocol and property class
1540  * (protocol or interface).
1541  *
1542  * Further if proto == MOD_PROTO_NONE, then it walks through all the supported
1543  * protocol property tables.
1544  */
1545 ipadm_status_t
ipadm_walk_proptbl(uint_t proto,uint_t class,ipadm_prop_wfunc_t * func,void * arg)1546 ipadm_walk_proptbl(uint_t proto, uint_t class, ipadm_prop_wfunc_t *func,
1547     void *arg)
1548 {
1549 	ipadm_prop_desc_t	*pdtbl;
1550 	ipadm_status_t		status = IPADM_SUCCESS;
1551 	int			i;
1552 	int			count = A_CNT(protocols);
1553 
1554 	if (func == NULL)
1555 		return (IPADM_INVALID_ARG);
1556 
1557 	switch (class) {
1558 	case IPADMPROP_CLASS_ADDR:
1559 		pdtbl = ipadm_addrprop_table;
1560 		break;
1561 	case IPADMPROP_CLASS_IF:
1562 	case IPADMPROP_CLASS_MODULE:
1563 		pdtbl = i_ipadm_get_propdesc_table(proto);
1564 		if (pdtbl == NULL && proto != MOD_PROTO_NONE)
1565 			return (IPADM_INVALID_ARG);
1566 		break;
1567 	default:
1568 		return (IPADM_INVALID_ARG);
1569 	}
1570 
1571 	if (pdtbl != NULL) {
1572 		/*
1573 		 * proto will be MOD_PROTO_NONE in the case of
1574 		 * IPADMPROP_CLASS_ADDR.
1575 		 */
1576 		i_ipadm_walk_proptbl(pdtbl, proto, class, func, arg);
1577 	} else {
1578 		/* Walk thru all the protocol tables, we support */
1579 		for (i = 0; i < count; i++) {
1580 			pdtbl = i_ipadm_get_propdesc_table(protocols[i]);
1581 			i_ipadm_walk_proptbl(pdtbl, protocols[i], class, func,
1582 			    arg);
1583 		}
1584 	}
1585 	return (status);
1586 }
1587 
1588 /*
1589  * Given a property name, walks through all the instances of a property name.
1590  * Some properties have two instances one for v4 interfaces and another for v6
1591  * interfaces. For example: MTU. MTU can have different values for v4 and v6.
1592  * Therefore there are two properties for 'MTU'.
1593  *
1594  * This function invokes `func' for every instance of property `pname'
1595  */
1596 ipadm_status_t
ipadm_walk_prop(const char * pname,uint_t proto,uint_t class,ipadm_prop_wfunc_t * func,void * arg)1597 ipadm_walk_prop(const char *pname, uint_t proto, uint_t class,
1598     ipadm_prop_wfunc_t *func, void *arg)
1599 {
1600 	ipadm_prop_desc_t	*pdtbl, *pdp;
1601 	ipadm_status_t		status = IPADM_SUCCESS;
1602 	boolean_t		matched = B_FALSE;
1603 
1604 	if (pname == NULL || func == NULL)
1605 		return (IPADM_INVALID_ARG);
1606 
1607 	switch (class) {
1608 	case IPADMPROP_CLASS_ADDR:
1609 		pdtbl = ipadm_addrprop_table;
1610 		break;
1611 	case IPADMPROP_CLASS_IF:
1612 	case IPADMPROP_CLASS_MODULE:
1613 		pdtbl = i_ipadm_get_propdesc_table(proto);
1614 		break;
1615 	default:
1616 		return (IPADM_INVALID_ARG);
1617 	}
1618 
1619 	if (pdtbl == NULL)
1620 		return (IPADM_INVALID_ARG);
1621 
1622 	for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1623 		if (strcmp(pname, pdp->ipd_name) != 0)
1624 			continue;
1625 		if (!(pdp->ipd_proto & proto))
1626 			continue;
1627 		matched = B_TRUE;
1628 		/* we found a match, call the callback function */
1629 		if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
1630 			break;
1631 	}
1632 	if (!matched)
1633 		status = IPADM_PROP_UNKNOWN;
1634 	return (status);
1635 }
1636 
1637 /* ARGSUSED */
1638 ipadm_status_t
i_ipadm_get_onoff(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * dp,char * buf,uint_t * bufsize,uint_t proto,uint_t valtype)1639 i_ipadm_get_onoff(ipadm_handle_t iph, const void *arg, ipadm_prop_desc_t *dp,
1640     char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
1641 {
1642 	(void) snprintf(buf, *bufsize, "%s,%s", IPADM_ONSTR, IPADM_OFFSTR);
1643 	return (IPADM_SUCCESS);
1644 }
1645 
1646 /*
1647  * Makes a door call to ipmgmtd to retrieve the persisted property value
1648  */
1649 ipadm_status_t
i_ipadm_get_persist_propval(ipadm_handle_t iph,ipadm_prop_desc_t * pdp,char * gbuf,uint_t * gbufsize,const void * object)1650 i_ipadm_get_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
1651     char *gbuf, uint_t *gbufsize, const void *object)
1652 {
1653 	ipmgmt_prop_arg_t	parg;
1654 	ipmgmt_getprop_rval_t	rval, *rvalp;
1655 	size_t			nbytes;
1656 	int			err = 0;
1657 
1658 	bzero(&parg, sizeof (parg));
1659 	parg.ia_cmd = IPMGMT_CMD_GETPROP;
1660 	i_ipadm_populate_proparg(&parg, pdp, NULL, object);
1661 
1662 	rvalp = &rval;
1663 	err = ipadm_door_call(iph, &parg, sizeof (parg), (void **)&rvalp,
1664 	    sizeof (rval), B_FALSE);
1665 	if (err == 0) {
1666 		/* assert that rvalp was not reallocated */
1667 		assert(rvalp == &rval);
1668 
1669 		/* `ir_pval' contains the property value */
1670 		nbytes = snprintf(gbuf, *gbufsize, "%s", rvalp->ir_pval);
1671 		if (nbytes >= *gbufsize) {
1672 			/* insufficient buffer space */
1673 			*gbufsize = nbytes + 1;
1674 			err = ENOBUFS;
1675 		}
1676 	}
1677 	return (ipadm_errno2status(err));
1678 }
1679 
1680 /*
1681  * Persists the property value for a given property in the data store
1682  */
1683 ipadm_status_t
i_ipadm_persist_propval(ipadm_handle_t iph,ipadm_prop_desc_t * pdp,const char * pval,const void * object,uint_t flags)1684 i_ipadm_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
1685     const char *pval, const void *object, uint_t flags)
1686 {
1687 	ipmgmt_prop_arg_t	parg;
1688 	int			err = 0;
1689 
1690 	bzero(&parg, sizeof (parg));
1691 	i_ipadm_populate_proparg(&parg, pdp, pval, object);
1692 	/*
1693 	 * Check if value to be persisted need to be appended or removed. This
1694 	 * is required for multi-valued property.
1695 	 */
1696 	if (flags & IPADM_OPT_APPEND)
1697 		parg.ia_flags |= IPMGMT_APPEND;
1698 	if (flags & IPADM_OPT_REMOVE)
1699 		parg.ia_flags |= IPMGMT_REMOVE;
1700 
1701 	if (flags & (IPADM_OPT_DEFAULT|IPADM_OPT_REMOVE))
1702 		parg.ia_cmd = IPMGMT_CMD_RESETPROP;
1703 	else
1704 		parg.ia_cmd = IPMGMT_CMD_SETPROP;
1705 
1706 	err = ipadm_door_call(iph, &parg, sizeof (parg), NULL, 0, B_FALSE);
1707 
1708 	/*
1709 	 * its fine if there were no entry in the DB to delete. The user
1710 	 * might be changing property value, which was not changed
1711 	 * persistently.
1712 	 */
1713 	if (err == ENOENT)
1714 		err = 0;
1715 	return (ipadm_errno2status(err));
1716 }
1717 
1718 /*
1719  * This is called from ipadm_set_ifprop() to validate the set operation.
1720  * It does the following steps:
1721  * 1. Validates the interface name.
1722  * 2. In case of a persistent operation, verifies that the
1723  *	interface is persistent.
1724  */
1725 static ipadm_status_t
i_ipadm_validate_if(ipadm_handle_t iph,const char * ifname,uint_t proto,uint_t flags)1726 i_ipadm_validate_if(ipadm_handle_t iph, const char *ifname,
1727     uint_t proto, uint_t flags)
1728 {
1729 	sa_family_t	af, other_af;
1730 	ipadm_status_t	status;
1731 	boolean_t	p_exists;
1732 	boolean_t	af_exists, other_af_exists, a_exists;
1733 
1734 	/* Check if the interface name is valid. */
1735 	if (!i_ipadm_validate_ifname(iph, ifname))
1736 		return (IPADM_INVALID_ARG);
1737 
1738 	af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
1739 
1740 	/* Check if interface exists in the persistent configuration. */
1741 	status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1742 	if (status != IPADM_SUCCESS)
1743 		return (status);
1744 
1745 	/* Check if interface exists in the active configuration. */
1746 	af_exists = ipadm_if_enabled(iph, ifname, af);
1747 	other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1748 	other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
1749 	a_exists = (af_exists || other_af_exists);
1750 	if (!a_exists && p_exists)
1751 		return (IPADM_OP_DISABLE_OBJ);
1752 	if (!af_exists)
1753 		return (IPADM_ENXIO);
1754 
1755 	/*
1756 	 * If a persistent operation is requested, check if the underlying
1757 	 * IP interface is persistent.
1758 	 */
1759 	if ((flags & IPADM_OPT_PERSIST) && !p_exists)
1760 		return (IPADM_TEMPORARY_OBJ);
1761 	return (IPADM_SUCCESS);
1762 }
1763 
1764 /*
1765  * Private protocol properties namespace scheme:
1766  *
1767  * PSARC 2010/080 identified the private protocol property names to be the
1768  * leading protocol names. For e.g. tcp_strong_iss, ip_strict_src_multihoming,
1769  * et al,. However to be consistent with private data-link property names,
1770  * which starts with '_', private protocol property names will start with '_'.
1771  * For e.g. _strong_iss, _strict_src_multihoming, et al,.
1772  */
1773 
1774 /* maps new private protocol property name to the old private property name */
1775 typedef struct ipadm_oname2nname_map {
1776 	char	*iom_oname;
1777 	char	*iom_nname;
1778 	uint_t	iom_proto;
1779 } ipadm_oname2nname_map_t;
1780 
1781 /*
1782  * IP is a special case. It isn't straight forward to derive the legacy name
1783  * from the new name and vice versa. No set standard was followed in naming
1784  * the properties and hence we need a table to capture the mapping.
1785  */
1786 static ipadm_oname2nname_map_t name_map[] = {
1787 	{ "arp_probe_delay",		"_arp_probe_delay",
1788 	    MOD_PROTO_IP },
1789 	{ "arp_fastprobe_delay",	"_arp_fastprobe_delay",
1790 	    MOD_PROTO_IP },
1791 	{ "arp_probe_interval",		"_arp_probe_interval",
1792 	    MOD_PROTO_IP },
1793 	{ "arp_fastprobe_interval",	"_arp_fastprobe_interval",
1794 	    MOD_PROTO_IP },
1795 	{ "arp_probe_count",		"_arp_probe_count",
1796 	    MOD_PROTO_IP },
1797 	{ "arp_fastprobe_count",	"_arp_fastprobe_count",
1798 	    MOD_PROTO_IP },
1799 	{ "arp_defend_interval",	"_arp_defend_interval",
1800 	    MOD_PROTO_IP },
1801 	{ "arp_defend_rate",		"_arp_defend_rate",
1802 	    MOD_PROTO_IP },
1803 	{ "arp_defend_period",		"_arp_defend_period",
1804 	    MOD_PROTO_IP },
1805 	{ "ndp_defend_interval",	"_ndp_defend_interval",
1806 	    MOD_PROTO_IP },
1807 	{ "ndp_defend_rate",		"_ndp_defend_rate",
1808 	    MOD_PROTO_IP },
1809 	{ "ndp_defend_period",		"_ndp_defend_period",
1810 	    MOD_PROTO_IP },
1811 	{ "igmp_max_version",		"_igmp_max_version",
1812 	    MOD_PROTO_IP },
1813 	{ "mld_max_version",		"_mld_max_version",
1814 	    MOD_PROTO_IP },
1815 	{ "ipsec_override_persocket_policy", "_ipsec_override_persocket_policy",
1816 	    MOD_PROTO_IP },
1817 	{ "ipsec_policy_log_interval",	"_ipsec_policy_log_interval",
1818 	    MOD_PROTO_IP },
1819 	{ "icmp_accept_clear_messages",	"_icmp_accept_clear_messages",
1820 	    MOD_PROTO_IP },
1821 	{ "igmp_accept_clear_messages",	"_igmp_accept_clear_messages",
1822 	    MOD_PROTO_IP },
1823 	{ "pim_accept_clear_messages",	"_pim_accept_clear_messages",
1824 	    MOD_PROTO_IP },
1825 	{ "ip_respond_to_echo_multicast", "_respond_to_echo_multicast",
1826 	    MOD_PROTO_IPV4 },
1827 	{ "ip_send_redirects",		"_send_redirects",
1828 	    MOD_PROTO_IPV4 },
1829 	{ "ip_forward_src_routed",	"_forward_src_routed",
1830 	    MOD_PROTO_IPV4 },
1831 	{ "ip_icmp_return_data_bytes",	"_icmp_return_data_bytes",
1832 	    MOD_PROTO_IPV4 },
1833 	{ "ip_ignore_redirect",		"_ignore_redirect",
1834 	    MOD_PROTO_IPV4 },
1835 	{ "ip_strict_dst_multihoming",	"_strict_dst_multihoming",
1836 	    MOD_PROTO_IPV4 },
1837 	{ "ip_reasm_timeout",		"_reasm_timeout",
1838 	    MOD_PROTO_IPV4 },
1839 	{ "ip_strict_src_multihoming",	"_strict_src_multihoming",
1840 	    MOD_PROTO_IPV4 },
1841 	{ "ipv4_dad_announce_interval",	"_dad_announce_interval",
1842 	    MOD_PROTO_IPV4 },
1843 	{ "ipv4_icmp_return_pmtu",	"_icmp_return_pmtu",
1844 	    MOD_PROTO_IPV4 },
1845 	{ "ipv6_dad_announce_interval",	"_dad_announce_interval",
1846 	    MOD_PROTO_IPV6 },
1847 	{ "ipv6_icmp_return_pmtu",	"_icmp_return_pmtu",
1848 	    MOD_PROTO_IPV6 },
1849 	{ NULL, NULL, MOD_PROTO_NONE }
1850 };
1851 
1852 /*
1853  * Following API returns a new property name in `nname' for the given legacy
1854  * property name in `oname'.
1855  */
1856 int
ipadm_legacy2new_propname(const char * oname,char * nname,uint_t nnamelen,uint_t * proto)1857 ipadm_legacy2new_propname(const char *oname, char *nname, uint_t nnamelen,
1858     uint_t *proto)
1859 {
1860 	const char	*str;
1861 	ipadm_oname2nname_map_t *ionmp;
1862 
1863 	/* if it's a public property, there is nothing to return */
1864 	if (i_ipadm_get_prop_desc(oname, *proto, NULL) != NULL)
1865 		return (-1);
1866 
1867 	/*
1868 	 * we didn't find the `oname' in the table, check if the property
1869 	 * name begins with a leading protocol.
1870 	 */
1871 	str = oname;
1872 	switch (*proto) {
1873 	case MOD_PROTO_TCP:
1874 		if (strstr(oname, "tcp_") == oname)
1875 			str += strlen("tcp");
1876 		break;
1877 	case MOD_PROTO_SCTP:
1878 		if (strstr(oname, "sctp_") == oname)
1879 			str += strlen("sctp");
1880 		break;
1881 	case MOD_PROTO_UDP:
1882 		if (strstr(oname, "udp_") == oname)
1883 			str += strlen("udp");
1884 		break;
1885 	case MOD_PROTO_RAWIP:
1886 		if (strstr(oname, "icmp_") == oname)
1887 			str += strlen("icmp");
1888 		break;
1889 	case MOD_PROTO_IP:
1890 	case MOD_PROTO_IPV4:
1891 	case MOD_PROTO_IPV6:
1892 		if (strstr(oname, "ip6_") == oname) {
1893 			*proto = MOD_PROTO_IPV6;
1894 			str += strlen("ip6");
1895 		} else {
1896 			for (ionmp = name_map; ionmp->iom_oname != NULL;
1897 			    ionmp++) {
1898 				if (strcmp(oname, ionmp->iom_oname) == 0) {
1899 					str = ionmp->iom_nname;
1900 					*proto = ionmp->iom_proto;
1901 					break;
1902 				}
1903 			}
1904 			if (ionmp->iom_oname != NULL)
1905 				break;
1906 
1907 			if (strstr(oname, "ip_") == oname) {
1908 				*proto = MOD_PROTO_IP;
1909 				str += strlen("ip");
1910 			}
1911 		}
1912 		break;
1913 	default:
1914 		return (-1);
1915 	}
1916 	(void) snprintf(nname, nnamelen, "%s", str);
1917 	return (0);
1918 }
1919 
1920 /*
1921  * Following API is required for ndd.c alone. To maintain backward
1922  * compatibility with ndd output, we need to print the legacy name
1923  * for the new name.
1924  */
1925 int
ipadm_new2legacy_propname(const char * oname,char * nname,uint_t nnamelen,uint_t proto)1926 ipadm_new2legacy_propname(const char *oname, char *nname,
1927     uint_t nnamelen, uint_t proto)
1928 {
1929 	char	*prefix;
1930 	ipadm_oname2nname_map_t *ionmp;
1931 
1932 	/* if it's a public property, there is nothing to prepend */
1933 	if (i_ipadm_get_prop_desc(oname, proto, NULL) != NULL)
1934 		return (-1);
1935 
1936 	switch (proto) {
1937 	case MOD_PROTO_TCP:
1938 		prefix = "tcp";
1939 		break;
1940 	case MOD_PROTO_SCTP:
1941 		prefix = "sctp";
1942 		break;
1943 	case MOD_PROTO_UDP:
1944 		prefix = "udp";
1945 		break;
1946 	case MOD_PROTO_RAWIP:
1947 		prefix = "icmp";
1948 		break;
1949 	case MOD_PROTO_IP:
1950 	case MOD_PROTO_IPV4:
1951 	case MOD_PROTO_IPV6:
1952 		/* handle special case for IP */
1953 		for (ionmp = name_map; ionmp->iom_oname != NULL; ionmp++) {
1954 			if (strcmp(oname, ionmp->iom_nname) == 0 &&
1955 			    ionmp->iom_proto == proto) {
1956 				(void) strlcpy(nname, ionmp->iom_oname,
1957 				    nnamelen);
1958 				return (0);
1959 			}
1960 		}
1961 		if (proto == MOD_PROTO_IPV6)
1962 			prefix = "ip6";
1963 		else
1964 			prefix = "ip";
1965 		break;
1966 	default:
1967 		return (-1);
1968 	}
1969 	(void) snprintf(nname, nnamelen, "%s%s", prefix, oname);
1970 	return (0);
1971 }
1972