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