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