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