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 char *
275 ipadm_proto2str(uint_t proto)
276 {
277 	switch (proto) {
278 	case MOD_PROTO_IP:
279 		return ("ip");
280 	case MOD_PROTO_IPV4:
281 		return ("ipv4");
282 	case MOD_PROTO_IPV6:
283 		return ("ipv6");
284 	case MOD_PROTO_RAWIP:
285 		return ("icmp");
286 	case MOD_PROTO_TCP:
287 		return ("tcp");
288 	case MOD_PROTO_UDP:
289 		return ("udp");
290 	case MOD_PROTO_SCTP:
291 		return ("sctp");
292 	}
293 
294 	return (NULL);
295 }
296 
297 uint_t
298 ipadm_str2proto(const char *protostr)
299 {
300 	if (protostr == NULL)
301 		return (MOD_PROTO_NONE);
302 	if (strcmp(protostr, "tcp") == 0)
303 		return (MOD_PROTO_TCP);
304 	else if (strcmp(protostr, "udp") == 0)
305 		return (MOD_PROTO_UDP);
306 	else if (strcmp(protostr, "ip") == 0)
307 		return (MOD_PROTO_IP);
308 	else if (strcmp(protostr, "ipv4") == 0)
309 		return (MOD_PROTO_IPV4);
310 	else if (strcmp(protostr, "ipv6") == 0)
311 		return (MOD_PROTO_IPV6);
312 	else if (strcmp(protostr, "icmp") == 0)
313 		return (MOD_PROTO_RAWIP);
314 	else if (strcmp(protostr, "sctp") == 0)
315 		return (MOD_PROTO_SCTP);
316 	else if (strcmp(protostr, "arp") == 0)
317 		return (MOD_PROTO_IP);
318 
319 	return (MOD_PROTO_NONE);
320 }
321 
322 /* ARGSUSED */
323 static ipadm_status_t
324 i_ipadm_set_mtu(ipadm_handle_t iph, const void *arg,
325     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
326 {
327 	struct lifreq	lifr;
328 	char		*endp;
329 	uint_t		mtu;
330 	int		s;
331 	const char	*ifname = arg;
332 	char		val[MAXPROPVALLEN];
333 
334 	/* to reset MTU first retrieve the default MTU and then set it */
335 	if (flags & IPADM_OPT_DEFAULT) {
336 		ipadm_status_t	status;
337 		uint_t		size = MAXPROPVALLEN;
338 
339 		status = i_ipadm_get_prop(iph, arg, pdp, val, &size,
340 		    proto, MOD_PROP_DEFAULT);
341 		if (status != IPADM_SUCCESS)
342 			return (status);
343 		pval = val;
344 	}
345 
346 	errno = 0;
347 	mtu = (uint_t)strtol(pval, &endp, 10);
348 	if (errno != 0 || *endp != '\0')
349 		return (IPADM_INVALID_ARG);
350 
351 	bzero(&lifr, sizeof (lifr));
352 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
353 	lifr.lifr_mtu = mtu;
354 
355 	s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
356 	if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0)
357 		return (ipadm_errno2status(errno));
358 
359 	return (IPADM_SUCCESS);
360 }
361 
362 /* ARGSUSED */
363 static ipadm_status_t
364 i_ipadm_set_metric(ipadm_handle_t iph, const void *arg,
365     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
366 {
367 	struct lifreq	lifr;
368 	char		*endp;
369 	int		metric;
370 	const char	*ifname = arg;
371 	int		s;
372 
373 	/* if we are resetting, set the value to its default value */
374 	if (flags & IPADM_OPT_DEFAULT) {
375 		metric = DEF_METRIC_VAL;
376 	} else {
377 		errno = 0;
378 		metric = (uint_t)strtol(pval, &endp, 10);
379 		if (errno != 0 || *endp != '\0')
380 			return (IPADM_INVALID_ARG);
381 	}
382 
383 	bzero(&lifr, sizeof (lifr));
384 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
385 	lifr.lifr_metric = metric;
386 
387 	s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
388 
389 	if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0)
390 		return (ipadm_errno2status(errno));
391 
392 	return (IPADM_SUCCESS);
393 }
394 
395 /* ARGSUSED */
396 static ipadm_status_t
397 i_ipadm_set_usesrc(ipadm_handle_t iph, const void *arg,
398     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
399 {
400 	struct lifreq	lifr;
401 	const char	*ifname = arg;
402 	int		s;
403 	uint_t		ifindex = 0;
404 
405 	/* if we are resetting, set the value to its default value */
406 	if (flags & IPADM_OPT_DEFAULT)
407 		pval = IPADM_NONESTR;
408 
409 	/*
410 	 * cannot specify logical interface name. We can also filter out other
411 	 * bogus interface names here itself through i_ipadm_validate_ifname().
412 	 */
413 	if (strcmp(pval, IPADM_NONESTR) != 0 &&
414 	    !i_ipadm_validate_ifname(iph, pval))
415 		return (IPADM_INVALID_ARG);
416 
417 	bzero(&lifr, sizeof (lifr));
418 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
419 
420 	s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
421 
422 	if (strcmp(pval, IPADM_NONESTR) != 0) {
423 		if ((ifindex = if_nametoindex(pval)) == 0)
424 			return (ipadm_errno2status(errno));
425 		lifr.lifr_index = ifindex;
426 	} else {
427 		if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
428 			return (ipadm_errno2status(errno));
429 		lifr.lifr_index = 0;
430 	}
431 	if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) < 0)
432 		return (ipadm_errno2status(errno));
433 
434 	return (IPADM_SUCCESS);
435 }
436 
437 static struct hostmodel_strval {
438 	char *esm_str;
439 	ip_hostmodel_t esm_val;
440 } esm_arr[] = {
441 	{"weak", IP_WEAK_ES},
442 	{"src-priority", IP_SRC_PRI_ES},
443 	{"strong", IP_STRONG_ES},
444 	{"custom", IP_MAXVAL_ES}
445 };
446 
447 static ip_hostmodel_t
448 i_ipadm_hostmodel_str2val(const char *pval)
449 {
450 	int i;
451 
452 	for (i = 0; i < A_CNT(esm_arr); i++) {
453 		if (esm_arr[i].esm_str != NULL &&
454 		    strcmp(pval, esm_arr[i].esm_str) == 0) {
455 			return (esm_arr[i].esm_val);
456 		}
457 	}
458 	return (IP_MAXVAL_ES);
459 }
460 
461 static char *
462 i_ipadm_hostmodel_val2str(ip_hostmodel_t pval)
463 {
464 	int i;
465 
466 	for (i = 0; i < A_CNT(esm_arr); i++) {
467 		if (esm_arr[i].esm_val == pval)
468 			return (esm_arr[i].esm_str);
469 	}
470 	return (NULL);
471 }
472 
473 /* ARGSUSED */
474 static ipadm_status_t
475 i_ipadm_set_hostmodel(ipadm_handle_t iph, const void *arg,
476     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
477 {
478 	ip_hostmodel_t hostmodel;
479 	char val[11]; /* covers uint32_max as a string */
480 
481 	if ((flags & IPADM_OPT_DEFAULT) == 0) {
482 		hostmodel = i_ipadm_hostmodel_str2val(pval);
483 		if (hostmodel == IP_MAXVAL_ES)
484 			return (IPADM_INVALID_ARG);
485 		(void) snprintf(val, sizeof (val), "%d", hostmodel);
486 		pval = val;
487 	}
488 	return (i_ipadm_set_prop(iph, NULL, pdp, pval, proto, flags));
489 }
490 
491 /* ARGSUSED */
492 static ipadm_status_t
493 i_ipadm_get_hostmodel(ipadm_handle_t iph, const void *arg,
494     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
495     uint_t valtype)
496 {
497 	ip_hostmodel_t hostmodel;
498 	char *cp;
499 	size_t nbytes;
500 	ipadm_status_t status;
501 
502 	switch (valtype) {
503 	case MOD_PROP_PERM:
504 		nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
505 		break;
506 	case MOD_PROP_DEFAULT:
507 		nbytes = snprintf(buf, *bufsize, "weak");
508 		break;
509 	case MOD_PROP_ACTIVE:
510 		status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
511 		    valtype);
512 		if (status != IPADM_SUCCESS)
513 			return (status);
514 		bcopy(buf, &hostmodel, sizeof (hostmodel));
515 		cp = i_ipadm_hostmodel_val2str(hostmodel);
516 		nbytes = snprintf(buf, *bufsize, "%s",
517 		    (cp != NULL ? cp : "?"));
518 		break;
519 	case MOD_PROP_POSSIBLE:
520 		nbytes = snprintf(buf, *bufsize, "strong,src-priority,weak");
521 		break;
522 	default:
523 		return (IPADM_INVALID_ARG);
524 	}
525 	if (nbytes >= *bufsize) {
526 		/* insufficient buffer space */
527 		*bufsize = nbytes + 1;
528 		return (IPADM_NO_BUFS);
529 	}
530 	return (IPADM_SUCCESS);
531 }
532 
533 /* ARGSUSED */
534 static ipadm_status_t
535 i_ipadm_set_ifprop_flags(ipadm_handle_t iph, const void *arg,
536     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
537 {
538 	ipadm_status_t	status = IPADM_SUCCESS;
539 	const char	*ifname = arg;
540 	uint64_t	on_flags = 0, off_flags = 0;
541 	boolean_t	on = B_FALSE;
542 	sa_family_t	af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
543 
544 	/* if we are resetting, set the value to its default value */
545 	if (flags & IPADM_OPT_DEFAULT) {
546 		if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
547 		    strcmp(pdp->ipd_name, "arp") == 0 ||
548 		    strcmp(pdp->ipd_name, "nud") == 0) {
549 			pval = IPADM_ONSTR;
550 		} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
551 			pval = IPADM_OFFSTR;
552 		} else {
553 			return (IPADM_PROP_UNKNOWN);
554 		}
555 	}
556 
557 	if (strcmp(pval, IPADM_ONSTR) == 0)
558 		on = B_TRUE;
559 	else if (strcmp(pval, IPADM_OFFSTR) == 0)
560 		on = B_FALSE;
561 	else
562 		return (IPADM_INVALID_ARG);
563 
564 	if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
565 		if (on)
566 			off_flags = IFF_NORTEXCH;
567 		else
568 			on_flags = IFF_NORTEXCH;
569 	} else if (strcmp(pdp->ipd_name, "arp") == 0) {
570 		if (on)
571 			off_flags = IFF_NOARP;
572 		else
573 			on_flags = IFF_NOARP;
574 	} else if (strcmp(pdp->ipd_name, "nud") == 0) {
575 		if (on)
576 			off_flags = IFF_NONUD;
577 		else
578 			on_flags = IFF_NONUD;
579 	} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
580 		if (on)
581 			on_flags = IFF_ROUTER;
582 		else
583 			off_flags = IFF_ROUTER;
584 	}
585 
586 	if (on_flags || off_flags)  {
587 		status = i_ipadm_set_flags(iph, ifname, af, on_flags,
588 		    off_flags);
589 	}
590 	return (status);
591 }
592 
593 /* ARGSUSED */
594 static ipadm_status_t
595 i_ipadm_set_eprivport(ipadm_handle_t iph, const void *arg,
596     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
597 {
598 	nvlist_t	*portsnvl = NULL;
599 	nvpair_t	*nvp;
600 	ipadm_status_t	status = IPADM_SUCCESS;
601 	int		err;
602 	uint_t		count = 0;
603 
604 	if (flags & IPADM_OPT_DEFAULT) {
605 		assert(pval == NULL);
606 		return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
607 	}
608 
609 	if ((err = ipadm_str2nvlist(pval, &portsnvl, IPADM_NORVAL)) != 0)
610 		return (ipadm_errno2status(err));
611 
612 	/* count the number of ports */
613 	for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
614 	    nvp = nvlist_next_nvpair(portsnvl, nvp)) {
615 		++count;
616 	}
617 
618 	if (iph->iph_flags & IPH_INIT) {
619 		flags |= IPADM_OPT_APPEND;
620 	} else if (count > 1) {
621 		/*
622 		 * We allow only one port to be added, removed or
623 		 * assigned at a time.
624 		 *
625 		 * However on reboot, while initializing protocol
626 		 * properties, extra_priv_ports might have multiple
627 		 * values. Only in that case we allow setting multiple
628 		 * values.
629 		 */
630 		nvlist_free(portsnvl);
631 		return (IPADM_INVALID_ARG);
632 	}
633 
634 	for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
635 	    nvp = nvlist_next_nvpair(portsnvl, nvp)) {
636 		status = i_ipadm_set_prop(iph, arg, pdp, nvpair_name(nvp),
637 		    proto, flags);
638 		if (status != IPADM_SUCCESS)
639 			break;
640 	}
641 	nvlist_free(portsnvl);
642 	return (status);
643 }
644 
645 /* ARGSUSED */
646 static ipadm_status_t
647 i_ipadm_set_forwarding(ipadm_handle_t iph, const void *arg,
648     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
649 {
650 	const char	*ifname = arg;
651 	ipadm_status_t	status;
652 
653 	/*
654 	 * if interface name is provided, then set forwarding using the
655 	 * IFF_ROUTER flag
656 	 */
657 	if (ifname != NULL) {
658 		status = i_ipadm_set_ifprop_flags(iph, ifname, pdp, pval,
659 		    proto, flags);
660 	} else {
661 		char	*val = NULL;
662 
663 		/*
664 		 * if the caller is IPH_LEGACY, `pval' already contains
665 		 * numeric values.
666 		 */
667 		if (!(flags & IPADM_OPT_DEFAULT) &&
668 		    !(iph->iph_flags & IPH_LEGACY)) {
669 
670 			if (strcmp(pval, IPADM_ONSTR) == 0)
671 				val = "1";
672 			else if (strcmp(pval, IPADM_OFFSTR) == 0)
673 				val = "0";
674 			else
675 				return (IPADM_INVALID_ARG);
676 			pval = val;
677 		}
678 
679 		status = i_ipadm_set_prop(iph, ifname, pdp, pval, proto, flags);
680 	}
681 
682 	return (status);
683 }
684 
685 /* ARGSUSED */
686 static ipadm_status_t
687 i_ipadm_set_ecnsack(ipadm_handle_t iph, const void *arg,
688     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
689 {
690 	uint_t		i;
691 	char		val[MAXPROPVALLEN];
692 
693 	/* if IPH_LEGACY is set, `pval' already contains numeric values */
694 	if (!(flags & IPADM_OPT_DEFAULT) && !(iph->iph_flags & IPH_LEGACY)) {
695 		for (i = 0; ecn_sack_vals[i] != NULL; i++) {
696 			if (strcmp(pval, ecn_sack_vals[i]) == 0)
697 				break;
698 		}
699 		if (ecn_sack_vals[i] == NULL)
700 			return (IPADM_INVALID_ARG);
701 		(void) snprintf(val, MAXPROPVALLEN, "%d", i);
702 		pval = val;
703 	}
704 
705 	return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
706 }
707 
708 /* ARGSUSED */
709 ipadm_status_t
710 i_ipadm_get_ecnsack(ipadm_handle_t iph, const void *arg,
711     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
712     uint_t valtype)
713 {
714 	ipadm_status_t	status = IPADM_SUCCESS;
715 	uint_t		i, nbytes = 0;
716 
717 	switch (valtype) {
718 	case MOD_PROP_POSSIBLE:
719 		for (i = 0; ecn_sack_vals[i] != NULL; i++) {
720 			if (i == 0)
721 				nbytes += snprintf(buf + nbytes,
722 				    *bufsize - nbytes, "%s", ecn_sack_vals[i]);
723 			else
724 				nbytes += snprintf(buf + nbytes,
725 				    *bufsize - nbytes, ",%s", ecn_sack_vals[i]);
726 			if (nbytes >= *bufsize)
727 				break;
728 		}
729 		break;
730 	case MOD_PROP_PERM:
731 	case MOD_PROP_DEFAULT:
732 	case MOD_PROP_ACTIVE:
733 		status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
734 		    valtype);
735 
736 		/*
737 		 * If IPH_LEGACY is set, do not convert the value returned
738 		 * from kernel,
739 		 */
740 		if (iph->iph_flags & IPH_LEGACY)
741 			break;
742 
743 		/*
744 		 * For current and default value, convert the value returned
745 		 * from kernel to more discrete representation.
746 		 */
747 		if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
748 		    valtype == MOD_PROP_DEFAULT)) {
749 			i = atoi(buf);
750 			assert(i < 3);
751 			nbytes = snprintf(buf, *bufsize, "%s",
752 			    ecn_sack_vals[i]);
753 		}
754 		break;
755 	default:
756 		return (IPADM_INVALID_ARG);
757 	}
758 	if (nbytes >= *bufsize) {
759 		/* insufficient buffer space */
760 		*bufsize = nbytes + 1;
761 		return (IPADM_NO_BUFS);
762 	}
763 
764 	return (status);
765 }
766 
767 /* ARGSUSED */
768 static ipadm_status_t
769 i_ipadm_get_forwarding(ipadm_handle_t iph, const void *arg,
770     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
771     uint_t valtype)
772 {
773 	const char	*ifname = arg;
774 	ipadm_status_t	status = IPADM_SUCCESS;
775 
776 	/*
777 	 * if interface name is provided, then get forwarding status using
778 	 * SIOCGLIFFLAGS
779 	 */
780 	if (ifname != NULL) {
781 		status = i_ipadm_get_ifprop_flags(iph, ifname, pdp,
782 		    buf, bufsize, pdp->ipd_proto, valtype);
783 	} else {
784 		status = i_ipadm_get_prop(iph, ifname, pdp, buf,
785 		    bufsize, proto, valtype);
786 		/*
787 		 * If IPH_LEGACY is set, do not convert the value returned
788 		 * from kernel,
789 		 */
790 		if (iph->iph_flags & IPH_LEGACY)
791 			goto ret;
792 		if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
793 		    valtype == MOD_PROP_DEFAULT)) {
794 			uint_t	val = atoi(buf);
795 
796 			(void) snprintf(buf, *bufsize,
797 			    (val == 1 ? IPADM_ONSTR : IPADM_OFFSTR));
798 		}
799 	}
800 
801 ret:
802 	return (status);
803 }
804 
805 /* ARGSUSED */
806 static ipadm_status_t
807 i_ipadm_get_mtu(ipadm_handle_t iph, const void *arg,
808     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
809     uint_t valtype)
810 {
811 	struct lifreq	lifr;
812 	const char	*ifname = arg;
813 	size_t		nbytes;
814 	int		s;
815 
816 	switch (valtype) {
817 	case MOD_PROP_PERM:
818 		nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
819 		break;
820 	case MOD_PROP_DEFAULT:
821 	case MOD_PROP_POSSIBLE:
822 		return (i_ipadm_get_prop(iph, arg, pdp, buf, bufsize,
823 		    proto, valtype));
824 	case MOD_PROP_ACTIVE:
825 		bzero(&lifr, sizeof (lifr));
826 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
827 		s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
828 
829 		if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) < 0)
830 			return (ipadm_errno2status(errno));
831 		nbytes = snprintf(buf, *bufsize, "%u", lifr.lifr_mtu);
832 		break;
833 	default:
834 		return (IPADM_INVALID_ARG);
835 	}
836 	if (nbytes >= *bufsize) {
837 		/* insufficient buffer space */
838 		*bufsize = nbytes + 1;
839 		return (IPADM_NO_BUFS);
840 	}
841 	return (IPADM_SUCCESS);
842 }
843 
844 /* ARGSUSED */
845 static ipadm_status_t
846 i_ipadm_get_metric(ipadm_handle_t iph, const void *arg,
847     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
848     uint_t valtype)
849 {
850 	struct lifreq	lifr;
851 	const char	*ifname = arg;
852 	size_t		nbytes;
853 	int		s, val;
854 
855 	switch (valtype) {
856 	case MOD_PROP_PERM:
857 		val = MOD_PROP_PERM_RW;
858 		break;
859 	case MOD_PROP_DEFAULT:
860 		val = DEF_METRIC_VAL;
861 		break;
862 	case MOD_PROP_ACTIVE:
863 		bzero(&lifr, sizeof (lifr));
864 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
865 
866 		s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
867 		if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0)
868 			return (ipadm_errno2status(errno));
869 		val = lifr.lifr_metric;
870 		break;
871 	default:
872 		return (IPADM_INVALID_ARG);
873 	}
874 	nbytes = snprintf(buf, *bufsize, "%d", val);
875 	if (nbytes >= *bufsize) {
876 		/* insufficient buffer space */
877 		*bufsize = nbytes + 1;
878 		return (IPADM_NO_BUFS);
879 	}
880 
881 	return (IPADM_SUCCESS);
882 }
883 
884 /* ARGSUSED */
885 static ipadm_status_t
886 i_ipadm_get_usesrc(ipadm_handle_t iph, const void *arg,
887     ipadm_prop_desc_t *ipd, char *buf, uint_t *bufsize, uint_t proto,
888     uint_t valtype)
889 {
890 	struct lifreq	lifr;
891 	const char	*ifname = arg;
892 	int		s;
893 	char 		if_name[IF_NAMESIZE];
894 	size_t		nbytes;
895 
896 	switch (valtype) {
897 	case MOD_PROP_PERM:
898 		nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
899 		break;
900 	case MOD_PROP_DEFAULT:
901 		nbytes = snprintf(buf, *bufsize, "%s", IPADM_NONESTR);
902 		break;
903 	case MOD_PROP_ACTIVE:
904 		bzero(&lifr, sizeof (lifr));
905 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
906 
907 		s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
908 		if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
909 			return (ipadm_errno2status(errno));
910 		if (lifr.lifr_index == 0) {
911 			/* no src address was set, so print 'none' */
912 			(void) strlcpy(if_name, IPADM_NONESTR,
913 			    sizeof (if_name));
914 		} else if (if_indextoname(lifr.lifr_index, if_name) == NULL) {
915 			return (ipadm_errno2status(errno));
916 		}
917 		nbytes = snprintf(buf, *bufsize, "%s", if_name);
918 		break;
919 	default:
920 		return (IPADM_INVALID_ARG);
921 	}
922 	if (nbytes >= *bufsize) {
923 		/* insufficient buffer space */
924 		*bufsize = nbytes + 1;
925 		return (IPADM_NO_BUFS);
926 	}
927 	return (IPADM_SUCCESS);
928 }
929 
930 /* ARGSUSED */
931 static ipadm_status_t
932 i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg,
933     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
934     uint_t valtype)
935 {
936 	uint64_t 	intf_flags;
937 	char 		*val;
938 	size_t		nbytes;
939 	const char	*ifname = arg;
940 	sa_family_t	af;
941 	ipadm_status_t	status = IPADM_SUCCESS;
942 
943 	switch (valtype) {
944 	case MOD_PROP_PERM:
945 		nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
946 		break;
947 	case MOD_PROP_DEFAULT:
948 		if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
949 		    strcmp(pdp->ipd_name, "arp") == 0 ||
950 		    strcmp(pdp->ipd_name, "nud") == 0) {
951 			val = IPADM_ONSTR;
952 		} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
953 			val = IPADM_OFFSTR;
954 		} else {
955 			return (IPADM_PROP_UNKNOWN);
956 		}
957 		nbytes = snprintf(buf, *bufsize, "%s", val);
958 		break;
959 	case MOD_PROP_ACTIVE:
960 		af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
961 		status = i_ipadm_get_flags(iph, ifname, af, &intf_flags);
962 		if (status != IPADM_SUCCESS)
963 			return (status);
964 
965 		val = IPADM_OFFSTR;
966 		if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
967 			if (!(intf_flags & IFF_NORTEXCH))
968 				val = IPADM_ONSTR;
969 		} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
970 			if (intf_flags & IFF_ROUTER)
971 				val = IPADM_ONSTR;
972 		} else if (strcmp(pdp->ipd_name, "arp") == 0) {
973 			if (!(intf_flags & IFF_NOARP))
974 				val = IPADM_ONSTR;
975 		} else if (strcmp(pdp->ipd_name, "nud") == 0) {
976 			if (!(intf_flags & IFF_NONUD))
977 				val = IPADM_ONSTR;
978 		}
979 		nbytes = snprintf(buf, *bufsize, "%s", val);
980 		break;
981 	default:
982 		return (IPADM_INVALID_ARG);
983 	}
984 	if (nbytes >= *bufsize) {
985 		/* insufficient buffer space */
986 		*bufsize = nbytes + 1;
987 		status = IPADM_NO_BUFS;
988 	}
989 
990 	return (status);
991 }
992 
993 static void
994 i_ipadm_perm2str(char *buf, uint_t *bufsize)
995 {
996 	uint_t perm = atoi(buf);
997 
998 	(void) snprintf(buf, *bufsize, "%c%c",
999 	    ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
1000 	    ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
1001 }
1002 
1003 /* ARGSUSED */
1004 static ipadm_status_t
1005 i_ipadm_get_prop(ipadm_handle_t iph, const void *arg,
1006     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
1007     uint_t valtype)
1008 {
1009 	ipadm_status_t	status = IPADM_SUCCESS;
1010 	const char	*ifname = arg;
1011 	mod_ioc_prop_t	*mip;
1012 	char 		*pname = pdp->ipd_name;
1013 	uint_t		iocsize;
1014 
1015 	/* allocate sufficient ioctl buffer to retrieve value */
1016 	iocsize = sizeof (mod_ioc_prop_t) + *bufsize - 1;
1017 	if ((mip = calloc(1, iocsize)) == NULL)
1018 		return (IPADM_NO_BUFS);
1019 
1020 	mip->mpr_version = MOD_PROP_VERSION;
1021 	mip->mpr_flags = valtype;
1022 	mip->mpr_proto = proto;
1023 	if (ifname != NULL) {
1024 		(void) strlcpy(mip->mpr_ifname, ifname,
1025 		    sizeof (mip->mpr_ifname));
1026 	}
1027 	(void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
1028 	mip->mpr_valsize = *bufsize;
1029 
1030 	if (i_ipadm_strioctl(iph->iph_sock, SIOCGETPROP, (char *)mip,
1031 	    iocsize) < 0) {
1032 		if (errno == ENOENT)
1033 			status = IPADM_PROP_UNKNOWN;
1034 		else
1035 			status = ipadm_errno2status(errno);
1036 	} else {
1037 		bcopy(mip->mpr_val, buf, *bufsize);
1038 	}
1039 
1040 	free(mip);
1041 	return (status);
1042 }
1043 
1044 /*
1045  * populates the ipmgmt_prop_arg_t based on the class of property.
1046  */
1047 static void
1048 i_ipadm_populate_proparg(ipmgmt_prop_arg_t *pargp, ipadm_prop_desc_t *pdp,
1049     const char *pval, const void *object)
1050 {
1051 	const struct ipadm_addrobj_s *ipaddr;
1052 	uint_t		class = pdp->ipd_class;
1053 	uint_t		proto = pdp->ipd_proto;
1054 
1055 	(void) strlcpy(pargp->ia_pname, pdp->ipd_name,
1056 	    sizeof (pargp->ia_pname));
1057 	if (pval != NULL)
1058 		(void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
1059 
1060 	switch (class) {
1061 	case IPADMPROP_CLASS_MODULE:
1062 		(void) strlcpy(pargp->ia_module, object,
1063 		    sizeof (pargp->ia_module));
1064 		break;
1065 	case IPADMPROP_CLASS_MODIF:
1066 		/* check if object is protostr or an ifname */
1067 		if (ipadm_str2proto(object) != MOD_PROTO_NONE) {
1068 			(void) strlcpy(pargp->ia_module, object,
1069 			    sizeof (pargp->ia_module));
1070 			break;
1071 		}
1072 		/* it's an interface property, fall through */
1073 		/* FALLTHRU */
1074 	case IPADMPROP_CLASS_IF:
1075 		(void) strlcpy(pargp->ia_ifname, object,
1076 		    sizeof (pargp->ia_ifname));
1077 		(void) strlcpy(pargp->ia_module, ipadm_proto2str(proto),
1078 		    sizeof (pargp->ia_module));
1079 		break;
1080 	case IPADMPROP_CLASS_ADDR:
1081 		ipaddr = object;
1082 		(void) strlcpy(pargp->ia_ifname, ipaddr->ipadm_ifname,
1083 		    sizeof (pargp->ia_ifname));
1084 		(void) strlcpy(pargp->ia_aobjname, ipaddr->ipadm_aobjname,
1085 		    sizeof (pargp->ia_aobjname));
1086 		break;
1087 	}
1088 }
1089 
1090 /*
1091  * Common function to retrieve property value for a given interface `ifname' or
1092  * for a given protocol `proto'. The property name is in `pname'.
1093  *
1094  * `valtype' determines the type of value that will be retrieved.
1095  * 	IPADM_OPT_ACTIVE -	current value of the property (active config)
1096  *	IPADM_OPT_PERSIST -	value of the property from persistent store
1097  *	IPADM_OPT_DEFAULT -	default hard coded value (boot-time value)
1098  *	IPADM_OPT_PERM -	read/write permissions for the value
1099  *	IPADM_OPT_POSSIBLE -	range of values
1100  */
1101 static ipadm_status_t
1102 i_ipadm_getprop_common(ipadm_handle_t iph, const char *ifname,
1103     const char *pname, char *buf, uint_t *bufsize, uint_t proto,
1104     uint_t valtype)
1105 {
1106 	ipadm_status_t		status = IPADM_SUCCESS;
1107 	ipadm_prop_desc_t	*pdp, *pdtbl;
1108 	char			priv_propname[MAXPROPNAMELEN];
1109 	boolean_t		matched_name = B_FALSE;
1110 	boolean_t		is_if = (ifname != NULL);
1111 
1112 	pdtbl = i_ipadm_get_propdesc_table(proto);
1113 
1114 	/*
1115 	 * We already checked for supported protocol,
1116 	 * pdtbl better not be NULL.
1117 	 */
1118 	assert(pdtbl != NULL);
1119 
1120 	for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1121 		if (strcmp(pname, pdp->ipd_name) == 0) {
1122 			matched_name = B_TRUE;
1123 			if (proto == pdp->ipd_proto)
1124 				break;
1125 		}
1126 	}
1127 
1128 	if (pdp->ipd_name != NULL) {
1129 		/*
1130 		 * check whether the property can be
1131 		 * applied on an interface
1132 		 */
1133 		if (is_if && !(pdp->ipd_class & IPADMPROP_CLASS_IF))
1134 			return (IPADM_INVALID_ARG);
1135 		/*
1136 		 * check whether the property can be
1137 		 * applied on a module
1138 		 */
1139 		if (!is_if && !(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
1140 			return (IPADM_INVALID_ARG);
1141 
1142 	} else {
1143 		/*
1144 		 * if we matched name, but failed protocol check,
1145 		 * then return error
1146 		 */
1147 		if (matched_name)
1148 			return (IPADM_INVALID_ARG);
1149 
1150 		/* there are no private interface properties */
1151 		if (is_if)
1152 			return (IPADM_PROP_UNKNOWN);
1153 
1154 		/* private protocol properties, pass it to kernel directly */
1155 		pdp = &ipadm_privprop;
1156 		(void) strlcpy(priv_propname, pname, sizeof (priv_propname));
1157 		pdp->ipd_name = priv_propname;
1158 	}
1159 
1160 	switch (valtype) {
1161 	case IPADM_OPT_PERM:
1162 		status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1163 		    MOD_PROP_PERM);
1164 		if (status == IPADM_SUCCESS)
1165 			i_ipadm_perm2str(buf, bufsize);
1166 		break;
1167 	case IPADM_OPT_ACTIVE:
1168 		status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1169 		    MOD_PROP_ACTIVE);
1170 		break;
1171 	case IPADM_OPT_DEFAULT:
1172 		status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1173 		    MOD_PROP_DEFAULT);
1174 		break;
1175 	case IPADM_OPT_POSSIBLE:
1176 		if (pdp->ipd_get_range != NULL) {
1177 			status = pdp->ipd_get_range(iph, ifname, pdp, buf,
1178 			    bufsize, proto, MOD_PROP_POSSIBLE);
1179 			break;
1180 		}
1181 		buf[0] = '\0';
1182 		break;
1183 	case IPADM_OPT_PERSIST:
1184 		/* retrieve from database */
1185 		if (is_if)
1186 			status = i_ipadm_get_persist_propval(iph, pdp, buf,
1187 			    bufsize, ifname);
1188 		else
1189 			status = i_ipadm_get_persist_propval(iph, pdp, buf,
1190 			    bufsize, ipadm_proto2str(proto));
1191 		break;
1192 	default:
1193 		status = IPADM_INVALID_ARG;
1194 		break;
1195 	}
1196 	return (status);
1197 }
1198 
1199 /*
1200  * Get protocol property of the specified protocol.
1201  */
1202 ipadm_status_t
1203 ipadm_get_prop(ipadm_handle_t iph, const char *pname, char *buf,
1204     uint_t *bufsize, uint_t proto, uint_t valtype)
1205 {
1206 	/*
1207 	 * validate the arguments of the function.
1208 	 */
1209 	if (iph == NULL || pname == NULL || buf == NULL ||
1210 	    bufsize == NULL || *bufsize == 0) {
1211 		return (IPADM_INVALID_ARG);
1212 	}
1213 	/*
1214 	 * Do we support this proto, if not return error.
1215 	 */
1216 	if (ipadm_proto2str(proto) == NULL)
1217 		return (IPADM_NOTSUP);
1218 
1219 	return (i_ipadm_getprop_common(iph, NULL, pname, buf, bufsize,
1220 	    proto, valtype));
1221 }
1222 
1223 /*
1224  * Get interface property of the specified interface.
1225  */
1226 ipadm_status_t
1227 ipadm_get_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
1228     char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
1229 {
1230 	/* validate the arguments of the function. */
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 	if (ipadm_proto2str(proto) == NULL)
1238 		return (IPADM_NOTSUP);
1239 
1240 	/*
1241 	 * check if interface name is provided for interface property and
1242 	 * is valid.
1243 	 */
1244 	if (!i_ipadm_validate_ifname(iph, ifname))
1245 		return (IPADM_INVALID_ARG);
1246 
1247 	return (i_ipadm_getprop_common(iph, ifname, pname, buf, bufsize,
1248 	    proto, valtype));
1249 }
1250 
1251 /*
1252  * Allocates sufficient ioctl buffers and copies property name and the
1253  * value, among other things. If the flag IPADM_OPT_DEFAULT is set, then
1254  * `pval' will be NULL and it instructs the kernel to reset the current
1255  * value to property's default value.
1256  */
1257 static ipadm_status_t
1258 i_ipadm_set_prop(ipadm_handle_t iph, const void *arg,
1259     ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
1260 {
1261 	ipadm_status_t	status = IPADM_SUCCESS;
1262 	const char	*ifname = arg;
1263 	mod_ioc_prop_t 	*mip;
1264 	char 		*pname = pdp->ipd_name;
1265 	uint_t 		valsize, iocsize;
1266 	uint_t		iocflags = 0;
1267 
1268 	if (flags & IPADM_OPT_DEFAULT) {
1269 		iocflags |= MOD_PROP_DEFAULT;
1270 	} else if (flags & IPADM_OPT_ACTIVE) {
1271 		iocflags |= MOD_PROP_ACTIVE;
1272 		if (flags & IPADM_OPT_APPEND)
1273 			iocflags |= MOD_PROP_APPEND;
1274 		else if (flags & IPADM_OPT_REMOVE)
1275 			iocflags |= MOD_PROP_REMOVE;
1276 	}
1277 
1278 	if (pval != NULL) {
1279 		valsize = strlen(pval);
1280 		iocsize = sizeof (mod_ioc_prop_t) + valsize - 1;
1281 	} else {
1282 		valsize = 0;
1283 		iocsize = sizeof (mod_ioc_prop_t);
1284 	}
1285 
1286 	if ((mip = calloc(1, iocsize)) == NULL)
1287 		return (IPADM_NO_BUFS);
1288 
1289 	mip->mpr_version = MOD_PROP_VERSION;
1290 	mip->mpr_flags = iocflags;
1291 	mip->mpr_proto = proto;
1292 	if (ifname != NULL) {
1293 		(void) strlcpy(mip->mpr_ifname, ifname,
1294 		    sizeof (mip->mpr_ifname));
1295 	}
1296 
1297 	(void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
1298 	mip->mpr_valsize = valsize;
1299 	if (pval != NULL)
1300 		bcopy(pval, mip->mpr_val, valsize);
1301 
1302 	if (i_ipadm_strioctl(iph->iph_sock, SIOCSETPROP, (char *)mip,
1303 	    iocsize) < 0) {
1304 		if (errno == ENOENT)
1305 			status = IPADM_PROP_UNKNOWN;
1306 		else
1307 			status = ipadm_errno2status(errno);
1308 	}
1309 	free(mip);
1310 	return (status);
1311 }
1312 
1313 /*
1314  * Common function for modifying both protocol/interface property.
1315  *
1316  * If:
1317  *   IPADM_OPT_PERSIST is set then the value is persisted.
1318  *   IPADM_OPT_DEFAULT is set then the default value for the property will
1319  *		       be applied.
1320  */
1321 static ipadm_status_t
1322 i_ipadm_setprop_common(ipadm_handle_t iph, const char *ifname,
1323     const char *pname, const char *buf, uint_t proto, uint_t pflags)
1324 {
1325 	ipadm_status_t		status = IPADM_SUCCESS;
1326 	boolean_t 		persist = (pflags & IPADM_OPT_PERSIST);
1327 	boolean_t		reset = (pflags & IPADM_OPT_DEFAULT);
1328 	ipadm_prop_desc_t	*pdp, *pdtbl;
1329 	boolean_t		is_if = (ifname != NULL);
1330 	char			priv_propname[MAXPROPNAMELEN];
1331 	boolean_t		matched_name = B_FALSE;
1332 
1333 	/* Check that property value is within the allowed size */
1334 	if (!reset && strnlen(buf, MAXPROPVALLEN) >= MAXPROPVALLEN)
1335 		return (IPADM_INVALID_ARG);
1336 
1337 	pdtbl = i_ipadm_get_propdesc_table(proto);
1338 	/*
1339 	 * We already checked for supported protocol,
1340 	 * pdtbl better not be NULL.
1341 	 */
1342 	assert(pdtbl != NULL);
1343 
1344 	/* Walk through the property table to match the given property name */
1345 	for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1346 		/*
1347 		 * we find the entry which matches <pname, proto> tuple
1348 		 */
1349 		if (strcmp(pname, pdp->ipd_name) == 0) {
1350 			matched_name = B_TRUE;
1351 			if (pdp->ipd_proto == proto)
1352 				break;
1353 		}
1354 	}
1355 
1356 	if (pdp->ipd_name != NULL) {
1357 		/* do some sanity checks */
1358 		if (is_if) {
1359 			if (!(pdp->ipd_class & IPADMPROP_CLASS_IF))
1360 				return (IPADM_INVALID_ARG);
1361 		} else {
1362 			if (!(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
1363 				return (IPADM_INVALID_ARG);
1364 		}
1365 		/*
1366 		 * if the property is not multi-valued and IPADM_OPT_APPEND or
1367 		 * IPADM_OPT_REMOVE is specified, return IPADM_INVALID_ARG.
1368 		 */
1369 		if (!(pdp->ipd_flags & IPADMPROP_MULVAL) && (pflags &
1370 		    (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1371 			return (IPADM_INVALID_ARG);
1372 		}
1373 	} else {
1374 		/*
1375 		 * if we matched name, but failed protocol check,
1376 		 * then return error.
1377 		 */
1378 		if (matched_name)
1379 			return (IPADM_BAD_PROTOCOL);
1380 
1381 		/* Possibly a private property, pass it to kernel directly */
1382 
1383 		/* there are no private interface properties */
1384 		if (is_if)
1385 			return (IPADM_PROP_UNKNOWN);
1386 
1387 		pdp = &ipadm_privprop;
1388 		(void) strlcpy(priv_propname, pname, sizeof (priv_propname));
1389 		pdp->ipd_name = priv_propname;
1390 	}
1391 
1392 	status = pdp->ipd_set(iph, ifname, pdp, buf, proto, pflags);
1393 	if (status != IPADM_SUCCESS)
1394 		return (status);
1395 
1396 	if (persist) {
1397 		if (is_if)
1398 			status = i_ipadm_persist_propval(iph, pdp, buf, ifname,
1399 			    pflags);
1400 		else
1401 			status = i_ipadm_persist_propval(iph, pdp, buf,
1402 			    ipadm_proto2str(proto), pflags);
1403 	}
1404 	return (status);
1405 }
1406 
1407 /*
1408  * Sets the property value of the specified interface
1409  */
1410 ipadm_status_t
1411 ipadm_set_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
1412     const char *buf, uint_t proto, uint_t pflags)
1413 {
1414 	boolean_t	reset = (pflags & IPADM_OPT_DEFAULT);
1415 	ipadm_status_t	status;
1416 
1417 	/* check for solaris.network.interface.config authorization */
1418 	if (!ipadm_check_auth())
1419 		return (IPADM_EAUTH);
1420 	/*
1421 	 * validate the arguments of the function.
1422 	 */
1423 	if (iph == NULL || pname == NULL || (!reset && buf == NULL) ||
1424 	    pflags == 0 || pflags == IPADM_OPT_PERSIST ||
1425 	    (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT))) {
1426 		return (IPADM_INVALID_ARG);
1427 	}
1428 
1429 	/*
1430 	 * Do we support this protocol, if not return error.
1431 	 */
1432 	if (ipadm_proto2str(proto) == NULL)
1433 		return (IPADM_NOTSUP);
1434 
1435 	/*
1436 	 * Validate the interface and check if a persistent
1437 	 * operation is performed on a temporary object.
1438 	 */
1439 	status = i_ipadm_validate_if(iph, ifname, proto, pflags);
1440 	if (status != IPADM_SUCCESS)
1441 		return (status);
1442 
1443 	return (i_ipadm_setprop_common(iph, ifname, pname, buf, proto,
1444 	    pflags));
1445 }
1446 
1447 /*
1448  * Sets the property value of the specified protocol.
1449  */
1450 ipadm_status_t
1451 ipadm_set_prop(ipadm_handle_t iph, const char *pname, const char *buf,
1452     uint_t proto, uint_t pflags)
1453 {
1454 	boolean_t	reset = (pflags & IPADM_OPT_DEFAULT);
1455 
1456 	/* check for solaris.network.interface.config authorization */
1457 	if (!ipadm_check_auth())
1458 		return (IPADM_EAUTH);
1459 	/*
1460 	 * validate the arguments of the function.
1461 	 */
1462 	if (iph == NULL || pname == NULL ||(!reset && buf == NULL) ||
1463 	    pflags == 0 || pflags == IPADM_OPT_PERSIST ||
1464 	    (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT|
1465 	    IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1466 		return (IPADM_INVALID_ARG);
1467 	}
1468 
1469 	/*
1470 	 * Do we support this proto, if not return error.
1471 	 */
1472 	if (ipadm_proto2str(proto) == NULL)
1473 		return (IPADM_NOTSUP);
1474 
1475 	return (i_ipadm_setprop_common(iph, NULL, pname, buf, proto,
1476 	    pflags));
1477 }
1478 
1479 /* helper function for ipadm_walk_proptbl */
1480 static void
1481 i_ipadm_walk_proptbl(ipadm_prop_desc_t *pdtbl, uint_t proto, uint_t class,
1482     ipadm_prop_wfunc_t *func, void *arg)
1483 {
1484 	ipadm_prop_desc_t	*pdp;
1485 
1486 	for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1487 		if (!(pdp->ipd_class & class))
1488 			continue;
1489 
1490 		if (proto != MOD_PROTO_NONE && !(pdp->ipd_proto & proto))
1491 			continue;
1492 
1493 		/*
1494 		 * we found a class specific match, call the
1495 		 * user callback function.
1496 		 */
1497 		if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
1498 			break;
1499 	}
1500 }
1501 
1502 /*
1503  * Walks through all the properties, for a given protocol and property class
1504  * (protocol or interface).
1505  *
1506  * Further if proto == MOD_PROTO_NONE, then it walks through all the supported
1507  * protocol property tables.
1508  */
1509 ipadm_status_t
1510 ipadm_walk_proptbl(uint_t proto, uint_t class, ipadm_prop_wfunc_t *func,
1511     void *arg)
1512 {
1513 	ipadm_prop_desc_t	*pdtbl;
1514 	ipadm_status_t		status = IPADM_SUCCESS;
1515 	int			i;
1516 	int			count = A_CNT(protocols);
1517 
1518 	if (func == NULL)
1519 		return (IPADM_INVALID_ARG);
1520 
1521 	switch (class) {
1522 	case IPADMPROP_CLASS_ADDR:
1523 		pdtbl = ipadm_addrprop_table;
1524 		break;
1525 	case IPADMPROP_CLASS_IF:
1526 	case IPADMPROP_CLASS_MODULE:
1527 		pdtbl = i_ipadm_get_propdesc_table(proto);
1528 		if (pdtbl == NULL && proto != MOD_PROTO_NONE)
1529 			return (IPADM_INVALID_ARG);
1530 		break;
1531 	default:
1532 		return (IPADM_INVALID_ARG);
1533 	}
1534 
1535 	if (pdtbl != NULL) {
1536 		/*
1537 		 * proto will be MOD_PROTO_NONE in the case of
1538 		 * IPADMPROP_CLASS_ADDR.
1539 		 */
1540 		i_ipadm_walk_proptbl(pdtbl, proto, class, func, arg);
1541 	} else {
1542 		/* Walk thru all the protocol tables, we support */
1543 		for (i = 0; i < count; i++) {
1544 			pdtbl = i_ipadm_get_propdesc_table(protocols[i]);
1545 			i_ipadm_walk_proptbl(pdtbl, protocols[i], class, func,
1546 			    arg);
1547 		}
1548 	}
1549 	return (status);
1550 }
1551 
1552 /*
1553  * Given a property name, walks through all the instances of a property name.
1554  * Some properties have two instances one for v4 interfaces and another for v6
1555  * interfaces. For example: MTU. MTU can have different values for v4 and v6.
1556  * Therefore there are two properties for 'MTU'.
1557  *
1558  * This function invokes `func' for every instance of property `pname'
1559  */
1560 ipadm_status_t
1561 ipadm_walk_prop(const char *pname, uint_t proto, uint_t class,
1562     ipadm_prop_wfunc_t *func, void *arg)
1563 {
1564 	ipadm_prop_desc_t	*pdtbl, *pdp;
1565 	ipadm_status_t		status = IPADM_SUCCESS;
1566 	boolean_t		matched = B_FALSE;
1567 
1568 	if (pname == NULL || func == NULL)
1569 		return (IPADM_INVALID_ARG);
1570 
1571 	switch (class) {
1572 	case IPADMPROP_CLASS_ADDR:
1573 		pdtbl = ipadm_addrprop_table;
1574 		break;
1575 	case IPADMPROP_CLASS_IF:
1576 	case IPADMPROP_CLASS_MODULE:
1577 		pdtbl = i_ipadm_get_propdesc_table(proto);
1578 		break;
1579 	default:
1580 		return (IPADM_INVALID_ARG);
1581 	}
1582 
1583 	if (pdtbl == NULL)
1584 		return (IPADM_INVALID_ARG);
1585 
1586 	for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1587 		if (strcmp(pname, pdp->ipd_name) != 0)
1588 			continue;
1589 		if (!(pdp->ipd_proto & proto))
1590 			continue;
1591 		matched = B_TRUE;
1592 		/* we found a match, call the callback function */
1593 		if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
1594 			break;
1595 	}
1596 	if (!matched)
1597 		status = IPADM_PROP_UNKNOWN;
1598 	return (status);
1599 }
1600 
1601 /* ARGSUSED */
1602 ipadm_status_t
1603 i_ipadm_get_onoff(ipadm_handle_t iph, const void *arg, ipadm_prop_desc_t *dp,
1604     char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
1605 {
1606 	(void) snprintf(buf, *bufsize, "%s,%s", IPADM_ONSTR, IPADM_OFFSTR);
1607 	return (IPADM_SUCCESS);
1608 }
1609 
1610 /*
1611  * Makes a door call to ipmgmtd to retrieve the persisted property value
1612  */
1613 ipadm_status_t
1614 i_ipadm_get_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
1615     char *gbuf, uint_t *gbufsize, const void *object)
1616 {
1617 	ipmgmt_prop_arg_t	parg;
1618 	ipmgmt_getprop_rval_t	rval, *rvalp;
1619 	size_t			nbytes;
1620 	int			err = 0;
1621 
1622 	bzero(&parg, sizeof (parg));
1623 	parg.ia_cmd = IPMGMT_CMD_GETPROP;
1624 	i_ipadm_populate_proparg(&parg, pdp, NULL, object);
1625 
1626 	rvalp = &rval;
1627 	err = ipadm_door_call(iph, &parg, sizeof (parg), (void **)&rvalp,
1628 	    sizeof (rval), B_FALSE);
1629 	if (err == 0) {
1630 		/* assert that rvalp was not reallocated */
1631 		assert(rvalp == &rval);
1632 
1633 		/* `ir_pval' contains the property value */
1634 		nbytes = snprintf(gbuf, *gbufsize, "%s", rvalp->ir_pval);
1635 		if (nbytes >= *gbufsize) {
1636 			/* insufficient buffer space */
1637 			*gbufsize = nbytes + 1;
1638 			err = ENOBUFS;
1639 		}
1640 	}
1641 	return (ipadm_errno2status(err));
1642 }
1643 
1644 /*
1645  * Persists the property value for a given property in the data store
1646  */
1647 ipadm_status_t
1648 i_ipadm_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
1649     const char *pval, const void *object, uint_t flags)
1650 {
1651 	ipmgmt_prop_arg_t	parg;
1652 	int			err = 0;
1653 
1654 	bzero(&parg, sizeof (parg));
1655 	i_ipadm_populate_proparg(&parg, pdp, pval, object);
1656 
1657 	/*
1658 	 * Check if value to be persisted need to be appended or removed. This
1659 	 * is required for multi-valued property.
1660 	 */
1661 	if (flags & IPADM_OPT_APPEND)
1662 		parg.ia_flags |= IPMGMT_APPEND;
1663 	if (flags & IPADM_OPT_REMOVE)
1664 		parg.ia_flags |= IPMGMT_REMOVE;
1665 
1666 	if (flags & (IPADM_OPT_DEFAULT|IPADM_OPT_REMOVE))
1667 		parg.ia_cmd = IPMGMT_CMD_RESETPROP;
1668 	else
1669 		parg.ia_cmd = IPMGMT_CMD_SETPROP;
1670 
1671 	err = ipadm_door_call(iph, &parg, sizeof (parg), NULL, 0, B_FALSE);
1672 
1673 	/*
1674 	 * its fine if there were no entry in the DB to delete. The user
1675 	 * might be changing property value, which was not changed
1676 	 * persistently.
1677 	 */
1678 	if (err == ENOENT)
1679 		err = 0;
1680 	return (ipadm_errno2status(err));
1681 }
1682 
1683 /*
1684  * Called during boot.
1685  *
1686  * Walk through the DB and apply all the global module properties. We plow
1687  * through the DB even if we fail to apply property.
1688  */
1689 /* ARGSUSED */
1690 boolean_t
1691 ipadm_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
1692     int *errp)
1693 {
1694 	ipadm_handle_t	iph = cbarg;
1695 	nvpair_t	*nvp, *pnvp;
1696 	char		*strval = NULL, *name, *mod = NULL;
1697 	uint_t		proto;
1698 
1699 	/*
1700 	 * We could have used nvl_exists() directly, however we need several
1701 	 * calls to it and each call traverses the list. Since this codepath
1702 	 * is exercised during boot, let's traverse the list ourselves and do
1703 	 * the necessary checks.
1704 	 */
1705 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1706 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1707 		name = nvpair_name(nvp);
1708 		if (IPADM_PRIV_NVP(name)) {
1709 			if (strcmp(name, IPADM_NVP_IFNAME) == 0 ||
1710 			    strcmp(name, IPADM_NVP_AOBJNAME) == 0)
1711 				return (B_TRUE);
1712 			else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 &&
1713 			    nvpair_value_string(nvp, &mod) != 0)
1714 				return (B_TRUE);
1715 		} else {
1716 			/* possible a property */
1717 			pnvp = nvp;
1718 		}
1719 	}
1720 
1721 	/* if we are here than we found a global property */
1722 	assert(mod != NULL);
1723 	assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
1724 
1725 	proto = ipadm_str2proto(mod);
1726 	if (nvpair_value_string(pnvp, &strval) == 0) {
1727 		(void) ipadm_set_prop(iph, name, strval, proto,
1728 		    IPADM_OPT_ACTIVE);
1729 	}
1730 
1731 	return (B_TRUE);
1732 }
1733 
1734 /* initialize global module properties */
1735 ipadm_status_t
1736 ipadm_init_prop()
1737 {
1738 	ipadm_handle_t	iph = NULL;
1739 	ipadm_status_t	status;
1740 	int		err;
1741 
1742 	/* check for solaris.network.interface.config authorization */
1743 	if (!ipadm_check_auth())
1744 		return (IPADM_EAUTH);
1745 
1746 	if ((status = ipadm_open(&iph, IPH_INIT)) != IPADM_SUCCESS)
1747 		return (status);
1748 
1749 	err = ipadm_rw_db(ipadm_db_init, iph, IPADM_DB_FILE, IPADM_FILE_MODE,
1750 	    IPADM_DB_READ);
1751 
1752 	ipadm_close(iph);
1753 	return (ipadm_errno2status(err));
1754 }
1755 
1756 /*
1757  * This is called from ipadm_set_ifprop() to validate the set operation.
1758  * It does the following steps:
1759  * 1. Validates the interface name.
1760  * 2. Fails if it is an IPMP meta-interface or an underlying interface.
1761  * 3. In case of a persistent operation, verifies that the
1762  *	interface is persistent.
1763  */
1764 static ipadm_status_t
1765 i_ipadm_validate_if(ipadm_handle_t iph, const char *ifname,
1766     uint_t proto, uint_t flags)
1767 {
1768 	sa_family_t	af, other_af;
1769 	ipadm_status_t	status;
1770 	boolean_t	p_exists;
1771 	boolean_t	af_exists, other_af_exists, a_exists;
1772 
1773 	/* Check if the interface name is valid. */
1774 	if (!i_ipadm_validate_ifname(iph, ifname))
1775 		return (IPADM_INVALID_ARG);
1776 
1777 	af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
1778 	/*
1779 	 * Setting properties on an IPMP meta-interface or underlying
1780 	 * interface is not supported.
1781 	 */
1782 	if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
1783 		return (IPADM_NOTSUP);
1784 
1785 	/* Check if interface exists in the persistent configuration. */
1786 	status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1787 	if (status != IPADM_SUCCESS)
1788 		return (status);
1789 
1790 	/* Check if interface exists in the active configuration. */
1791 	af_exists = ipadm_if_enabled(iph, ifname, af);
1792 	other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1793 	other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
1794 	a_exists = (af_exists || other_af_exists);
1795 	if (!a_exists && p_exists)
1796 		return (IPADM_OP_DISABLE_OBJ);
1797 	if (!af_exists)
1798 		return (IPADM_ENXIO);
1799 
1800 	/*
1801 	 * If a persistent operation is requested, check if the underlying
1802 	 * IP interface is persistent.
1803 	 */
1804 	if ((flags & IPADM_OPT_PERSIST) && !p_exists)
1805 		return (IPADM_TEMPORARY_OBJ);
1806 	return (IPADM_SUCCESS);
1807 }
1808