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 by Delphix. All rights reserved.
24 * Copyright (c) 2014 Nexenta Systems, Inc. All rights reserved
25 */
26
27 /*
28 * This file contains routines that are used to modify/retrieve protocol or
29 * interface property values. It also holds all the supported properties for
30 * both IP interface and protocols in `ipadm_prop_desc_t'. Following protocols
31 * are supported: IP, IPv4, IPv6, TCP, SCTP, UDP and ICMP.
32 *
33 * This file also contains walkers, which walks through the property table and
34 * calls the callback function, of the form `ipadm_prop_wfunc_t' , for every
35 * property in the table.
36 */
37
38 #include <unistd.h>
39 #include <errno.h>
40 #include <ctype.h>
41 #include <fcntl.h>
42 #include <strings.h>
43 #include <stdlib.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <sys/sockio.h>
47 #include <assert.h>
48 #include <libdllink.h>
49 #include <zone.h>
50 #include "libipadm_impl.h"
51 #include <inet/tunables.h>
52
53 #define IPADM_NONESTR "none"
54 #define DEF_METRIC_VAL 0 /* default metric value */
55
56 #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0]))
57
58 static ipadm_status_t i_ipadm_validate_if(ipadm_handle_t, const char *,
59 uint_t, uint_t);
60
61 /*
62 * Callback functions to retrieve property values from the kernel. These
63 * functions, when required, translate the values from the kernel to a format
64 * suitable for printing. For example: boolean values will be translated
65 * to on/off. They also retrieve DEFAULT, PERM and POSSIBLE values for
66 * a given property.
67 */
68 static ipadm_pd_getf_t i_ipadm_get_prop, i_ipadm_get_ifprop_flags,
69 i_ipadm_get_mtu, i_ipadm_get_metric,
70 i_ipadm_get_usesrc, i_ipadm_get_forwarding,
71 i_ipadm_get_ecnsack, i_ipadm_get_hostmodel;
72
73 /*
74 * Callback function to set property values. These functions translate the
75 * values to a format suitable for kernel consumption, allocates the necessary
76 * ioctl buffers and then invokes ioctl().
77 */
78 static ipadm_pd_setf_t i_ipadm_set_prop, i_ipadm_set_mtu,
79 i_ipadm_set_ifprop_flags,
80 i_ipadm_set_metric, i_ipadm_set_usesrc,
81 i_ipadm_set_forwarding, i_ipadm_set_eprivport,
82 i_ipadm_set_ecnsack, i_ipadm_set_hostmodel;
83
84 /* array of protocols we support */
85 static int protocols[] = { MOD_PROTO_IP, MOD_PROTO_RAWIP,
86 MOD_PROTO_TCP, MOD_PROTO_UDP,
87 MOD_PROTO_SCTP };
88
89 /*
90 * Supported IP protocol properties.
91 */
92 static ipadm_prop_desc_t ipadm_ip_prop_table[] = {
93 { "arp", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
94 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
95 i_ipadm_get_ifprop_flags },
96
97 { "forwarding", NULL, IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV4, 0,
98 i_ipadm_set_forwarding, i_ipadm_get_onoff,
99 i_ipadm_get_forwarding },
100
101 { "metric", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
102 i_ipadm_set_metric, NULL, i_ipadm_get_metric },
103
104 { "mtu", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
105 i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
106
107 { "exchange_routes", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
108 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
109 i_ipadm_get_ifprop_flags },
110
111 { "usesrc", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
112 i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
113
114 { "ttl", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4, 0,
115 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
116
117 { "forwarding", NULL, IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV6, 0,
118 i_ipadm_set_forwarding, i_ipadm_get_onoff,
119 i_ipadm_get_forwarding },
120
121 { "hoplimit", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6, 0,
122 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
123
124 { "metric", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
125 i_ipadm_set_metric, NULL, i_ipadm_get_metric },
126
127 { "mtu", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
128 i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
129
130 { "nud", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
131 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
132 i_ipadm_get_ifprop_flags },
133
134 { "exchange_routes", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
135 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
136 i_ipadm_get_ifprop_flags },
137
138 { "usesrc", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
139 i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
140
141 { "hostmodel", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6, 0,
142 i_ipadm_set_hostmodel, i_ipadm_get_hostmodel,
143 i_ipadm_get_hostmodel },
144
145 { "hostmodel", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4, 0,
146 i_ipadm_set_hostmodel, i_ipadm_get_hostmodel,
147 i_ipadm_get_hostmodel },
148
149 { "standby", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IP, 0,
150 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
151 i_ipadm_get_ifprop_flags },
152
153
154 { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
155 };
156
157 /* possible values for TCP properties `ecn' and `sack' */
158 static const char *ecn_sack_vals[] = {"never", "passive", "active", NULL};
159
160 /* Supported TCP protocol properties */
161 static ipadm_prop_desc_t ipadm_tcp_prop_table[] = {
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 strcmp(pdp->ipd_name, "standby") == 0) {
606 pval = IPADM_OFFSTR;
607 } else {
608 return (IPADM_PROP_UNKNOWN);
609 }
610 }
611
612 if (strcmp(pval, IPADM_ONSTR) == 0)
613 on = B_TRUE;
614 else if (strcmp(pval, IPADM_OFFSTR) == 0)
615 on = B_FALSE;
616 else
617 return (IPADM_INVALID_ARG);
618
619 if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
620 if (on)
621 off_flags = IFF_NORTEXCH;
622 else
623 on_flags = IFF_NORTEXCH;
624 } else if (strcmp(pdp->ipd_name, "arp") == 0) {
625 if (on)
626 off_flags = IFF_NOARP;
627 else
628 on_flags = IFF_NOARP;
629 } else if (strcmp(pdp->ipd_name, "nud") == 0) {
630 if (on)
631 off_flags = IFF_NONUD;
632 else
633 on_flags = IFF_NONUD;
634 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
635 if (on)
636 on_flags = IFF_ROUTER;
637 else
638 off_flags = IFF_ROUTER;
639 } else if (strcmp(pdp->ipd_name, "standby") == 0) {
640 if (on)
641 on_flags = IFF_STANDBY;
642 else
643 off_flags = IFF_STANDBY;
644 }
645
646 if (on_flags || off_flags) {
647 status = i_ipadm_set_flags(iph, ifname, af, on_flags,
648 off_flags);
649 }
650 return (status);
651 }
652
653 /* ARGSUSED */
654 static ipadm_status_t
655 i_ipadm_set_eprivport(ipadm_handle_t iph, const void *arg,
656 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
657 {
658 nvlist_t *portsnvl = NULL;
659 nvpair_t *nvp;
660 ipadm_status_t status = IPADM_SUCCESS;
661 int err;
662 uint_t count = 0;
663
664 if (flags & IPADM_OPT_DEFAULT) {
665 assert(pval == NULL);
666 return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
667 }
668
669 if ((err = ipadm_str2nvlist(pval, &portsnvl, IPADM_NORVAL)) != 0)
670 return (ipadm_errno2status(err));
671
672 /* count the number of ports */
673 for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
674 nvp = nvlist_next_nvpair(portsnvl, nvp)) {
675 ++count;
676 }
677
678 if (iph->iph_flags & IPH_INIT) {
679 flags |= IPADM_OPT_APPEND;
680 } else if (count > 1) {
681 /*
682 * We allow only one port to be added, removed or
683 * assigned at a time.
684 *
685 * However on reboot, while initializing protocol
686 * properties, extra_priv_ports might have multiple
687 * values. Only in that case we allow setting multiple
688 * values.
689 */
690 nvlist_free(portsnvl);
691 return (IPADM_INVALID_ARG);
692 }
693
694 for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
695 nvp = nvlist_next_nvpair(portsnvl, nvp)) {
696 status = i_ipadm_set_prop(iph, arg, pdp, nvpair_name(nvp),
697 proto, flags);
698 if (status != IPADM_SUCCESS)
699 break;
700 }
701 nvlist_free(portsnvl);
702 return (status);
703 }
704
705 /* ARGSUSED */
706 static ipadm_status_t
707 i_ipadm_set_forwarding(ipadm_handle_t iph, const void *arg,
708 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
709 {
710 const char *ifname = arg;
711 ipadm_status_t status;
712
713 /*
714 * if interface name is provided, then set forwarding using the
715 * IFF_ROUTER flag
716 */
717 if (ifname != NULL) {
718 status = i_ipadm_set_ifprop_flags(iph, ifname, pdp, pval,
719 proto, flags);
720 } else {
721 char *val = NULL;
722
723 /*
724 * if the caller is IPH_LEGACY, `pval' already contains
725 * numeric values.
726 */
727 if (!(flags & IPADM_OPT_DEFAULT) &&
728 !(iph->iph_flags & IPH_LEGACY)) {
729
730 if (strcmp(pval, IPADM_ONSTR) == 0)
731 val = "1";
732 else if (strcmp(pval, IPADM_OFFSTR) == 0)
733 val = "0";
734 else
735 return (IPADM_INVALID_ARG);
736 pval = val;
737 }
738
739 status = i_ipadm_set_prop(iph, ifname, pdp, pval, proto, flags);
740 }
741
742 return (status);
743 }
744
745 /* ARGSUSED */
746 static ipadm_status_t
747 i_ipadm_set_ecnsack(ipadm_handle_t iph, const void *arg,
748 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
749 {
750 uint_t i;
751 char val[MAXPROPVALLEN];
752
753 /* if IPH_LEGACY is set, `pval' already contains numeric values */
754 if (!(flags & IPADM_OPT_DEFAULT) && !(iph->iph_flags & IPH_LEGACY)) {
755 for (i = 0; ecn_sack_vals[i] != NULL; i++) {
756 if (strcmp(pval, ecn_sack_vals[i]) == 0)
757 break;
758 }
759 if (ecn_sack_vals[i] == NULL)
760 return (IPADM_INVALID_ARG);
761 (void) snprintf(val, MAXPROPVALLEN, "%d", i);
762 pval = val;
763 }
764
765 return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
766 }
767
768 /* ARGSUSED */
769 ipadm_status_t
770 i_ipadm_get_ecnsack(ipadm_handle_t iph, const void *arg,
771 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
772 uint_t valtype)
773 {
774 ipadm_status_t status = IPADM_SUCCESS;
775 uint_t i, nbytes = 0;
776
777 switch (valtype) {
778 case MOD_PROP_POSSIBLE:
779 for (i = 0; ecn_sack_vals[i] != NULL; i++) {
780 if (i == 0)
781 nbytes += snprintf(buf + nbytes,
782 *bufsize - nbytes, "%s", ecn_sack_vals[i]);
783 else
784 nbytes += snprintf(buf + nbytes,
785 *bufsize - nbytes, ",%s", ecn_sack_vals[i]);
786 if (nbytes >= *bufsize)
787 break;
788 }
789 break;
790 case MOD_PROP_PERM:
791 case MOD_PROP_DEFAULT:
792 case MOD_PROP_ACTIVE:
793 status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
794 valtype);
795
796 /*
797 * If IPH_LEGACY is set, do not convert the value returned
798 * from kernel,
799 */
800 if (iph->iph_flags & IPH_LEGACY)
801 break;
802
803 /*
804 * For current and default value, convert the value returned
805 * from kernel to more discrete representation.
806 */
807 if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
808 valtype == MOD_PROP_DEFAULT)) {
809 i = atoi(buf);
810 assert(i < 3);
811 nbytes = snprintf(buf, *bufsize, "%s",
812 ecn_sack_vals[i]);
813 }
814 break;
815 default:
816 return (IPADM_INVALID_ARG);
817 }
818 if (nbytes >= *bufsize) {
819 /* insufficient buffer space */
820 *bufsize = nbytes + 1;
821 return (IPADM_NO_BUFS);
822 }
823
824 return (status);
825 }
826
827 /* ARGSUSED */
828 static ipadm_status_t
829 i_ipadm_get_forwarding(ipadm_handle_t iph, const void *arg,
830 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
831 uint_t valtype)
832 {
833 const char *ifname = arg;
834 ipadm_status_t status = IPADM_SUCCESS;
835
836 /*
837 * if interface name is provided, then get forwarding status using
838 * SIOCGLIFFLAGS
839 */
840 if (ifname != NULL) {
841 status = i_ipadm_get_ifprop_flags(iph, ifname, pdp,
842 buf, bufsize, pdp->ipd_proto, valtype);
843 } else {
844 status = i_ipadm_get_prop(iph, ifname, pdp, buf,
845 bufsize, proto, valtype);
846 /*
847 * If IPH_LEGACY is set, do not convert the value returned
848 * from kernel,
849 */
850 if (iph->iph_flags & IPH_LEGACY)
851 goto ret;
852 if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
853 valtype == MOD_PROP_DEFAULT)) {
854 uint_t val = atoi(buf);
855
856 (void) snprintf(buf, *bufsize,
857 (val == 1 ? IPADM_ONSTR : IPADM_OFFSTR));
858 }
859 }
860
861 ret:
862 return (status);
863 }
864
865 /* ARGSUSED */
866 static ipadm_status_t
867 i_ipadm_get_mtu(ipadm_handle_t iph, const void *arg,
868 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
869 uint_t valtype)
870 {
871 struct lifreq lifr;
872 const char *ifname = arg;
873 size_t nbytes;
874 int s;
875
876 switch (valtype) {
877 case MOD_PROP_PERM:
878 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
879 break;
880 case MOD_PROP_DEFAULT:
881 case MOD_PROP_POSSIBLE:
882 return (i_ipadm_get_prop(iph, arg, pdp, buf, bufsize,
883 proto, valtype));
884 case MOD_PROP_ACTIVE:
885 bzero(&lifr, sizeof (lifr));
886 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
887 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
888
889 if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) < 0)
890 return (ipadm_errno2status(errno));
891 nbytes = snprintf(buf, *bufsize, "%u", lifr.lifr_mtu);
892 break;
893 default:
894 return (IPADM_INVALID_ARG);
895 }
896 if (nbytes >= *bufsize) {
897 /* insufficient buffer space */
898 *bufsize = nbytes + 1;
899 return (IPADM_NO_BUFS);
900 }
901 return (IPADM_SUCCESS);
902 }
903
904 /* ARGSUSED */
905 static ipadm_status_t
906 i_ipadm_get_metric(ipadm_handle_t iph, const void *arg,
907 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
908 uint_t valtype)
909 {
910 struct lifreq lifr;
911 const char *ifname = arg;
912 size_t nbytes;
913 int s, val;
914
915 switch (valtype) {
916 case MOD_PROP_PERM:
917 val = MOD_PROP_PERM_RW;
918 break;
919 case MOD_PROP_DEFAULT:
920 val = DEF_METRIC_VAL;
921 break;
922 case MOD_PROP_ACTIVE:
923 bzero(&lifr, sizeof (lifr));
924 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
925
926 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
927 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0)
928 return (ipadm_errno2status(errno));
929 val = lifr.lifr_metric;
930 break;
931 default:
932 return (IPADM_INVALID_ARG);
933 }
934 nbytes = snprintf(buf, *bufsize, "%d", val);
935 if (nbytes >= *bufsize) {
936 /* insufficient buffer space */
937 *bufsize = nbytes + 1;
938 return (IPADM_NO_BUFS);
939 }
940
941 return (IPADM_SUCCESS);
942 }
943
944 /* ARGSUSED */
945 static ipadm_status_t
946 i_ipadm_get_usesrc(ipadm_handle_t iph, const void *arg,
947 ipadm_prop_desc_t *ipd, char *buf, uint_t *bufsize, uint_t proto,
948 uint_t valtype)
949 {
950 struct lifreq lifr;
951 const char *ifname = arg;
952 int s;
953 char if_name[IF_NAMESIZE];
954 size_t nbytes;
955
956 switch (valtype) {
957 case MOD_PROP_PERM:
958 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
959 break;
960 case MOD_PROP_DEFAULT:
961 nbytes = snprintf(buf, *bufsize, "%s", IPADM_NONESTR);
962 break;
963 case MOD_PROP_ACTIVE:
964 bzero(&lifr, sizeof (lifr));
965 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
966
967 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
968 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
969 return (ipadm_errno2status(errno));
970 if (lifr.lifr_index == 0) {
971 /* no src address was set, so print 'none' */
972 (void) strlcpy(if_name, IPADM_NONESTR,
973 sizeof (if_name));
974 } else if (if_indextoname(lifr.lifr_index, if_name) == NULL) {
975 return (ipadm_errno2status(errno));
976 }
977 nbytes = snprintf(buf, *bufsize, "%s", if_name);
978 break;
979 default:
980 return (IPADM_INVALID_ARG);
981 }
982 if (nbytes >= *bufsize) {
983 /* insufficient buffer space */
984 *bufsize = nbytes + 1;
985 return (IPADM_NO_BUFS);
986 }
987 return (IPADM_SUCCESS);
988 }
989
990 /* ARGSUSED */
991 static ipadm_status_t
992 i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg,
993 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
994 uint_t valtype)
995 {
996 uint64_t intf_flags;
997 char *val;
998 size_t nbytes;
999 const char *ifname = arg;
1000 sa_family_t af;
1001 ipadm_status_t status = IPADM_SUCCESS;
1002
1003 switch (valtype) {
1004 case MOD_PROP_PERM:
1005 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
1006 break;
1007 case MOD_PROP_DEFAULT:
1008 if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
1009 strcmp(pdp->ipd_name, "arp") == 0 ||
1010 strcmp(pdp->ipd_name, "nud") == 0) {
1011 val = IPADM_ONSTR;
1012 } else if (strcmp(pdp->ipd_name, "forwarding") == 0 ||
1013 strcmp(pdp->ipd_name, "standby") == 0) {
1014 val = IPADM_OFFSTR;
1015 } else {
1016 return (IPADM_PROP_UNKNOWN);
1017 }
1018 nbytes = snprintf(buf, *bufsize, "%s", val);
1019 break;
1020 case MOD_PROP_ACTIVE:
1021 af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
1022 status = i_ipadm_get_flags(iph, ifname, af, &intf_flags);
1023 if (status != IPADM_SUCCESS)
1024 return (status);
1025
1026 val = IPADM_OFFSTR;
1027 if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
1028 if (!(intf_flags & IFF_NORTEXCH))
1029 val = IPADM_ONSTR;
1030 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
1031 if (intf_flags & IFF_ROUTER)
1032 val = IPADM_ONSTR;
1033 } else if (strcmp(pdp->ipd_name, "arp") == 0) {
1034 if (!(intf_flags & IFF_NOARP))
1035 val = IPADM_ONSTR;
1036 } else if (strcmp(pdp->ipd_name, "nud") == 0) {
1037 if (!(intf_flags & IFF_NONUD))
1038 val = IPADM_ONSTR;
1039 } else if (strcmp(pdp->ipd_name, "standby") == 0) {
1040 if (!(intf_flags & IFF_STANDBY))
1041 val = IPADM_ONSTR;
1042 }
1043 nbytes = snprintf(buf, *bufsize, "%s", val);
1044 break;
1045 default:
1046 return (IPADM_INVALID_ARG);
1047 }
1048 if (nbytes >= *bufsize) {
1049 /* insufficient buffer space */
1050 *bufsize = nbytes + 1;
1051 status = IPADM_NO_BUFS;
1052 }
1053
1054 return (status);
1055 }
1056
1057 static void
1058 i_ipadm_perm2str(char *buf, uint_t *bufsize)
1059 {
1060 uint_t perm = atoi(buf);
1061
1062 (void) snprintf(buf, *bufsize, "%c%c",
1063 ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
1064 ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
1065 }
1066
1067 /* ARGSUSED */
1068 static ipadm_status_t
1069 i_ipadm_get_prop(ipadm_handle_t iph, const void *arg,
1070 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
1071 uint_t valtype)
1072 {
1073 ipadm_status_t status = IPADM_SUCCESS;
1074 const char *ifname = arg;
1075 mod_ioc_prop_t *mip;
1076 char *pname = pdp->ipd_name;
1077 uint_t iocsize;
1078
1079 /* allocate sufficient ioctl buffer to retrieve value */
1080 iocsize = sizeof (mod_ioc_prop_t) + *bufsize - 1;
1081 if ((mip = calloc(1, iocsize)) == NULL)
1082 return (IPADM_NO_BUFS);
1083
1084 mip->mpr_version = MOD_PROP_VERSION;
1085 mip->mpr_flags = valtype;
1086 mip->mpr_proto = proto;
1087 if (ifname != NULL) {
1088 (void) strlcpy(mip->mpr_ifname, ifname,
1089 sizeof (mip->mpr_ifname));
1090 }
1091 (void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
1092 mip->mpr_valsize = *bufsize;
1093
1094 if (i_ipadm_strioctl(iph->iph_sock, SIOCGETPROP, (char *)mip,
1095 iocsize) < 0) {
1096 if (errno == ENOENT)
1097 status = IPADM_PROP_UNKNOWN;
1098 else
1099 status = ipadm_errno2status(errno);
1100 } else {
1101 bcopy(mip->mpr_val, buf, *bufsize);
1102 }
1103
1104 free(mip);
1105 return (status);
1106 }
1107
1108 /*
1109 * Populates the ipmgmt_prop_arg_t based on the class of property.
1110 *
1111 * For private protocol properties, while persisting information in ipadm
1112 * data store, to ensure there is no collision of namespace between ipadm
1113 * private nvpair names (which also starts with '_', see ipadm_ipmgmt.h)
1114 * and private protocol property names, we will prepend IPADM_PRIV_PROP_PREFIX
1115 * to property names.
1116 */
1117 static void
1118 i_ipadm_populate_proparg(ipmgmt_prop_arg_t *pargp, ipadm_prop_desc_t *pdp,
1119 const char *pval, const void *object)
1120 {
1121 const struct ipadm_addrobj_s *ipaddr;
1122 uint_t class = pdp->ipd_class;
1123 uint_t proto = pdp->ipd_proto;
1124
1125 (void) strlcpy(pargp->ia_pname, pdp->ipd_name,
1126 sizeof (pargp->ia_pname));
1127 if (pval != NULL)
1128 (void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
1129
1130 switch (class) {
1131 case IPADMPROP_CLASS_MODULE:
1132 /* if it's a private property then add the prefix. */
1133 if (pdp->ipd_name[0] == '_') {
1134 (void) snprintf(pargp->ia_pname,
1135 sizeof (pargp->ia_pname), "_%s", pdp->ipd_name);
1136 }
1137 (void) strlcpy(pargp->ia_module, object,
1138 sizeof (pargp->ia_module));
1139 break;
1140 case IPADMPROP_CLASS_MODIF:
1141 /* check if object is protostr or an ifname */
1142 if (ipadm_str2proto(object) != MOD_PROTO_NONE) {
1143 (void) strlcpy(pargp->ia_module, object,
1144 sizeof (pargp->ia_module));
1145 break;
1146 }
1147 /* it's an interface property, fall through */
1148 /* FALLTHRU */
1149 case IPADMPROP_CLASS_IF:
1150 (void) strlcpy(pargp->ia_ifname, object,
1151 sizeof (pargp->ia_ifname));
1152 (void) strlcpy(pargp->ia_module, ipadm_proto2str(proto),
1153 sizeof (pargp->ia_module));
1154 break;
1155 case IPADMPROP_CLASS_ADDR:
1156 ipaddr = object;
1157 (void) strlcpy(pargp->ia_ifname, ipaddr->ipadm_ifname,
1158 sizeof (pargp->ia_ifname));
1159 (void) strlcpy(pargp->ia_aobjname, ipaddr->ipadm_aobjname,
1160 sizeof (pargp->ia_aobjname));
1161 break;
1162 }
1163 }
1164
1165 /*
1166 * Common function to retrieve property value for a given interface `ifname' or
1167 * for a given protocol `proto'. The property name is in `pname'.
1168 *
1169 * `valtype' determines the type of value that will be retrieved.
1170 * IPADM_OPT_ACTIVE - current value of the property (active config)
1171 * IPADM_OPT_PERSIST - value of the property from persistent store
1172 * IPADM_OPT_DEFAULT - default hard coded value (boot-time value)
1173 * IPADM_OPT_PERM - read/write permissions for the value
1174 * IPADM_OPT_POSSIBLE - range of values
1175 */
1176 static ipadm_status_t
1177 i_ipadm_getprop_common(ipadm_handle_t iph, const char *ifname,
1178 const char *pname, char *buf, uint_t *bufsize, uint_t proto,
1179 uint_t valtype)
1180 {
1181 ipadm_status_t status = IPADM_SUCCESS;
1182 ipadm_prop_desc_t *pdp;
1183 char priv_propname[MAXPROPNAMELEN];
1184 boolean_t is_if = (ifname != NULL);
1185 int err = 0;
1186
1187 pdp = i_ipadm_get_prop_desc(pname, proto, &err);
1188 if (err == EPROTO)
1189 return (IPADM_BAD_PROTOCOL);
1190 /* there are no private interface properties */
1191 if (is_if && err == ENOENT)
1192 return (IPADM_PROP_UNKNOWN);
1193
1194 if (pdp != NULL) {
1195 /*
1196 * check whether the property can be
1197 * applied on an interface
1198 */
1199 if (is_if && !(pdp->ipd_class & IPADMPROP_CLASS_IF))
1200 return (IPADM_INVALID_ARG);
1201 /*
1202 * check whether the property can be
1203 * applied on a module
1204 */
1205 if (!is_if && !(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
1206 return (IPADM_INVALID_ARG);
1207
1208 } else {
1209 /* private protocol properties, pass it to kernel directly */
1210 pdp = &ipadm_privprop;
1211 (void) strlcpy(priv_propname, pname, sizeof (priv_propname));
1212 pdp->ipd_name = priv_propname;
1213 }
1214
1215 switch (valtype) {
1216 case IPADM_OPT_PERM:
1217 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1218 MOD_PROP_PERM);
1219 if (status == IPADM_SUCCESS)
1220 i_ipadm_perm2str(buf, bufsize);
1221 break;
1222 case IPADM_OPT_ACTIVE:
1223 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1224 MOD_PROP_ACTIVE);
1225 break;
1226 case IPADM_OPT_DEFAULT:
1227 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1228 MOD_PROP_DEFAULT);
1229 break;
1230 case IPADM_OPT_POSSIBLE:
1231 if (pdp->ipd_get_range != NULL) {
1232 status = pdp->ipd_get_range(iph, ifname, pdp, buf,
1233 bufsize, proto, MOD_PROP_POSSIBLE);
1234 break;
1235 }
1236 buf[0] = '\0';
1237 break;
1238 case IPADM_OPT_PERSIST:
1239 /* retrieve from database */
1240 if (is_if)
1241 status = i_ipadm_get_persist_propval(iph, pdp, buf,
1242 bufsize, ifname);
1243 else
1244 status = i_ipadm_get_persist_propval(iph, pdp, buf,
1245 bufsize, ipadm_proto2str(proto));
1246 break;
1247 default:
1248 status = IPADM_INVALID_ARG;
1249 break;
1250 }
1251 return (status);
1252 }
1253
1254 /*
1255 * Get protocol property of the specified protocol.
1256 */
1257 ipadm_status_t
1258 ipadm_get_prop(ipadm_handle_t iph, const char *pname, char *buf,
1259 uint_t *bufsize, uint_t proto, uint_t valtype)
1260 {
1261 /*
1262 * validate the arguments of the function.
1263 */
1264 if (iph == NULL || pname == NULL || buf == NULL ||
1265 bufsize == NULL || *bufsize == 0) {
1266 return (IPADM_INVALID_ARG);
1267 }
1268 /*
1269 * Do we support this proto, if not return error.
1270 */
1271 if (ipadm_proto2str(proto) == NULL)
1272 return (IPADM_NOTSUP);
1273
1274 return (i_ipadm_getprop_common(iph, NULL, pname, buf, bufsize,
1275 proto, valtype));
1276 }
1277
1278 /*
1279 * Get interface property of the specified interface.
1280 */
1281 ipadm_status_t
1282 ipadm_get_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
1283 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
1284 {
1285 /* validate the arguments of the function. */
1286 if (iph == NULL || pname == NULL || buf == NULL ||
1287 bufsize == NULL || *bufsize == 0) {
1288 return (IPADM_INVALID_ARG);
1289 }
1290
1291 /* Do we support this proto, if not return error. */
1292 if (ipadm_proto2str(proto) == NULL)
1293 return (IPADM_NOTSUP);
1294
1295 /*
1296 * check if interface name is provided for interface property and
1297 * is valid.
1298 */
1299 if (!i_ipadm_validate_ifname(iph, ifname))
1300 return (IPADM_INVALID_ARG);
1301
1302 return (i_ipadm_getprop_common(iph, ifname, pname, buf, bufsize,
1303 proto, valtype));
1304 }
1305
1306 /*
1307 * Allocates sufficient ioctl buffers and copies property name and the
1308 * value, among other things. If the flag IPADM_OPT_DEFAULT is set, then
1309 * `pval' will be NULL and it instructs the kernel to reset the current
1310 * value to property's default value.
1311 */
1312 static ipadm_status_t
1313 i_ipadm_set_prop(ipadm_handle_t iph, const void *arg,
1314 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
1315 {
1316 ipadm_status_t status = IPADM_SUCCESS;
1317 const char *ifname = arg;
1318 mod_ioc_prop_t *mip;
1319 char *pname = pdp->ipd_name;
1320 uint_t valsize, iocsize;
1321 uint_t iocflags = 0;
1322
1323 if (flags & IPADM_OPT_DEFAULT) {
1324 iocflags |= MOD_PROP_DEFAULT;
1325 } else if (flags & IPADM_OPT_ACTIVE) {
1326 iocflags |= MOD_PROP_ACTIVE;
1327 if (flags & IPADM_OPT_APPEND)
1328 iocflags |= MOD_PROP_APPEND;
1329 else if (flags & IPADM_OPT_REMOVE)
1330 iocflags |= MOD_PROP_REMOVE;
1331 }
1332
1333 if (pval != NULL) {
1334 valsize = strlen(pval);
1335 iocsize = sizeof (mod_ioc_prop_t) + valsize - 1;
1336 } else {
1337 valsize = 0;
1338 iocsize = sizeof (mod_ioc_prop_t);
1339 }
1340
1341 if ((mip = calloc(1, iocsize)) == NULL)
1342 return (IPADM_NO_BUFS);
1343
1344 mip->mpr_version = MOD_PROP_VERSION;
1345 mip->mpr_flags = iocflags;
1346 mip->mpr_proto = proto;
1347 if (ifname != NULL) {
1348 (void) strlcpy(mip->mpr_ifname, ifname,
1349 sizeof (mip->mpr_ifname));
1350 }
1351
1352 (void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
1353 mip->mpr_valsize = valsize;
1354 if (pval != NULL)
1355 bcopy(pval, mip->mpr_val, valsize);
1356
1357 if (i_ipadm_strioctl(iph->iph_sock, SIOCSETPROP, (char *)mip,
1358 iocsize) < 0) {
1359 if (errno == ENOENT)
1360 status = IPADM_PROP_UNKNOWN;
1361 else
1362 status = ipadm_errno2status(errno);
1363 }
1364 free(mip);
1365 return (status);
1366 }
1367
1368 /*
1369 * Common function for modifying both protocol/interface property.
1370 *
1371 * If:
1372 * IPADM_OPT_PERSIST is set then the value is persisted.
1373 * IPADM_OPT_DEFAULT is set then the default value for the property will
1374 * be applied.
1375 */
1376 static ipadm_status_t
1377 i_ipadm_setprop_common(ipadm_handle_t iph, const char *ifname,
1378 const char *pname, const char *buf, uint_t proto, uint_t pflags)
1379 {
1380 ipadm_status_t status = IPADM_SUCCESS;
1381 boolean_t persist = (pflags & IPADM_OPT_PERSIST);
1382 boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
1383 ipadm_prop_desc_t *pdp;
1384 boolean_t is_if = (ifname != NULL);
1385 char priv_propname[MAXPROPNAMELEN];
1386 int err = 0;
1387
1388 /* Check that property value is within the allowed size */
1389 if (!reset && strnlen(buf, MAXPROPVALLEN) >= MAXPROPVALLEN)
1390 return (IPADM_INVALID_ARG);
1391
1392 pdp = i_ipadm_get_prop_desc(pname, proto, &err);
1393 if (err == EPROTO)
1394 return (IPADM_BAD_PROTOCOL);
1395 /* there are no private interface properties */
1396 if (is_if && err == ENOENT)
1397 return (IPADM_PROP_UNKNOWN);
1398
1399 if (pdp != NULL) {
1400 /* do some sanity checks */
1401 if (is_if) {
1402 if (!(pdp->ipd_class & IPADMPROP_CLASS_IF))
1403 return (IPADM_INVALID_ARG);
1404 } else {
1405 if (!(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
1406 return (IPADM_INVALID_ARG);
1407 }
1408 /*
1409 * if the property is not multi-valued and IPADM_OPT_APPEND or
1410 * IPADM_OPT_REMOVE is specified, return IPADM_INVALID_ARG.
1411 */
1412 if (!(pdp->ipd_flags & IPADMPROP_MULVAL) && (pflags &
1413 (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1414 return (IPADM_INVALID_ARG);
1415 }
1416 } else {
1417 /* private protocol property, pass it to kernel directly */
1418 pdp = &ipadm_privprop;
1419 (void) strlcpy(priv_propname, pname, sizeof (priv_propname));
1420 pdp->ipd_name = priv_propname;
1421 }
1422
1423 status = pdp->ipd_set(iph, ifname, pdp, buf, proto, pflags);
1424 if (status != IPADM_SUCCESS)
1425 return (status);
1426
1427 if (persist) {
1428 if (is_if)
1429 status = i_ipadm_persist_propval(iph, pdp, buf, ifname,
1430 pflags);
1431 else
1432 status = i_ipadm_persist_propval(iph, pdp, buf,
1433 ipadm_proto2str(proto), pflags);
1434 }
1435 return (status);
1436 }
1437
1438 /*
1439 * Sets the property value of the specified interface
1440 */
1441 ipadm_status_t
1442 ipadm_set_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
1443 const char *buf, uint_t proto, uint_t pflags)
1444 {
1445 boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
1446 ipadm_status_t status;
1447
1448 /* check for solaris.network.interface.config authorization */
1449 if (!ipadm_check_auth())
1450 return (IPADM_EAUTH);
1451 /*
1452 * validate the arguments of the function.
1453 */
1454 if (iph == NULL || pname == NULL || (!reset && buf == NULL) ||
1455 pflags == 0 || pflags == IPADM_OPT_PERSIST ||
1456 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT))) {
1457 return (IPADM_INVALID_ARG);
1458 }
1459
1460 /*
1461 * Do we support this protocol, if not return error.
1462 */
1463 if (ipadm_proto2str(proto) == NULL)
1464 return (IPADM_NOTSUP);
1465
1466 /*
1467 * Validate the interface and check if a persistent
1468 * operation is performed on a temporary object.
1469 */
1470 status = i_ipadm_validate_if(iph, ifname, proto, pflags);
1471 if (status != IPADM_SUCCESS)
1472 return (status);
1473
1474 return (i_ipadm_setprop_common(iph, ifname, pname, buf, proto,
1475 pflags));
1476 }
1477
1478 /*
1479 * Sets the property value of the specified protocol.
1480 */
1481 ipadm_status_t
1482 ipadm_set_prop(ipadm_handle_t iph, const char *pname, const char *buf,
1483 uint_t proto, uint_t pflags)
1484 {
1485 boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
1486
1487 /* check for solaris.network.interface.config authorization */
1488 if (!ipadm_check_auth())
1489 return (IPADM_EAUTH);
1490 /*
1491 * validate the arguments of the function.
1492 */
1493 if (iph == NULL || pname == NULL ||(!reset && buf == NULL) ||
1494 pflags == 0 || pflags == IPADM_OPT_PERSIST ||
1495 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT|
1496 IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1497 return (IPADM_INVALID_ARG);
1498 }
1499
1500 /*
1501 * Do we support this proto, if not return error.
1502 */
1503 if (ipadm_proto2str(proto) == NULL)
1504 return (IPADM_NOTSUP);
1505
1506 return (i_ipadm_setprop_common(iph, NULL, pname, buf, proto,
1507 pflags));
1508 }
1509
1510 /* helper function for ipadm_walk_proptbl */
1511 static void
1512 i_ipadm_walk_proptbl(ipadm_prop_desc_t *pdtbl, uint_t proto, uint_t class,
1513 ipadm_prop_wfunc_t *func, void *arg)
1514 {
1515 ipadm_prop_desc_t *pdp;
1516
1517 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1518 if (!(pdp->ipd_class & class))
1519 continue;
1520
1521 if (proto != MOD_PROTO_NONE && !(pdp->ipd_proto & proto))
1522 continue;
1523
1524 /*
1525 * we found a class specific match, call the
1526 * user callback function.
1527 */
1528 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
1529 break;
1530 }
1531 }
1532
1533 /*
1534 * Walks through all the properties, for a given protocol and property class
1535 * (protocol or interface).
1536 *
1537 * Further if proto == MOD_PROTO_NONE, then it walks through all the supported
1538 * protocol property tables.
1539 */
1540 ipadm_status_t
1541 ipadm_walk_proptbl(uint_t proto, uint_t class, ipadm_prop_wfunc_t *func,
1542 void *arg)
1543 {
1544 ipadm_prop_desc_t *pdtbl;
1545 ipadm_status_t status = IPADM_SUCCESS;
1546 int i;
1547 int count = A_CNT(protocols);
1548
1549 if (func == NULL)
1550 return (IPADM_INVALID_ARG);
1551
1552 switch (class) {
1553 case IPADMPROP_CLASS_ADDR:
1554 pdtbl = ipadm_addrprop_table;
1555 break;
1556 case IPADMPROP_CLASS_IF:
1557 case IPADMPROP_CLASS_MODULE:
1558 pdtbl = i_ipadm_get_propdesc_table(proto);
1559 if (pdtbl == NULL && proto != MOD_PROTO_NONE)
1560 return (IPADM_INVALID_ARG);
1561 break;
1562 default:
1563 return (IPADM_INVALID_ARG);
1564 }
1565
1566 if (pdtbl != NULL) {
1567 /*
1568 * proto will be MOD_PROTO_NONE in the case of
1569 * IPADMPROP_CLASS_ADDR.
1570 */
1571 i_ipadm_walk_proptbl(pdtbl, proto, class, func, arg);
1572 } else {
1573 /* Walk thru all the protocol tables, we support */
1574 for (i = 0; i < count; i++) {
1575 pdtbl = i_ipadm_get_propdesc_table(protocols[i]);
1576 i_ipadm_walk_proptbl(pdtbl, protocols[i], class, func,
1577 arg);
1578 }
1579 }
1580 return (status);
1581 }
1582
1583 /*
1584 * Given a property name, walks through all the instances of a property name.
1585 * Some properties have two instances one for v4 interfaces and another for v6
1586 * interfaces. For example: MTU. MTU can have different values for v4 and v6.
1587 * Therefore there are two properties for 'MTU'.
1588 *
1589 * This function invokes `func' for every instance of property `pname'
1590 */
1591 ipadm_status_t
1592 ipadm_walk_prop(const char *pname, uint_t proto, uint_t class,
1593 ipadm_prop_wfunc_t *func, void *arg)
1594 {
1595 ipadm_prop_desc_t *pdtbl, *pdp;
1596 ipadm_status_t status = IPADM_SUCCESS;
1597 boolean_t matched = B_FALSE;
1598
1599 if (pname == NULL || func == NULL)
1600 return (IPADM_INVALID_ARG);
1601
1602 switch (class) {
1603 case IPADMPROP_CLASS_ADDR:
1604 pdtbl = ipadm_addrprop_table;
1605 break;
1606 case IPADMPROP_CLASS_IF:
1607 case IPADMPROP_CLASS_MODULE:
1608 pdtbl = i_ipadm_get_propdesc_table(proto);
1609 break;
1610 default:
1611 return (IPADM_INVALID_ARG);
1612 }
1613
1614 if (pdtbl == NULL)
1615 return (IPADM_INVALID_ARG);
1616
1617 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1618 if (strcmp(pname, pdp->ipd_name) != 0)
1619 continue;
1620 if (!(pdp->ipd_proto & proto))
1621 continue;
1622 matched = B_TRUE;
1623 /* we found a match, call the callback function */
1624 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
1625 break;
1626 }
1627 if (!matched)
1628 status = IPADM_PROP_UNKNOWN;
1629 return (status);
1630 }
1631
1632 /* ARGSUSED */
1633 ipadm_status_t
1634 i_ipadm_get_onoff(ipadm_handle_t iph, const void *arg, ipadm_prop_desc_t *dp,
1635 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
1636 {
1637 (void) snprintf(buf, *bufsize, "%s,%s", IPADM_ONSTR, IPADM_OFFSTR);
1638 return (IPADM_SUCCESS);
1639 }
1640
1641 /*
1642 * Makes a door call to ipmgmtd to retrieve the persisted property value
1643 */
1644 ipadm_status_t
1645 i_ipadm_get_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
1646 char *gbuf, uint_t *gbufsize, const void *object)
1647 {
1648 ipmgmt_prop_arg_t parg;
1649 ipmgmt_getprop_rval_t rval, *rvalp;
1650 size_t nbytes;
1651 int err = 0;
1652
1653 bzero(&parg, sizeof (parg));
1654 parg.ia_cmd = IPMGMT_CMD_GETPROP;
1655 i_ipadm_populate_proparg(&parg, pdp, NULL, object);
1656
1657 rvalp = &rval;
1658 err = ipadm_door_call(iph, &parg, sizeof (parg), (void **)&rvalp,
1659 sizeof (rval), B_FALSE);
1660 if (err == 0) {
1661 /* assert that rvalp was not reallocated */
1662 assert(rvalp == &rval);
1663
1664 /* `ir_pval' contains the property value */
1665 nbytes = snprintf(gbuf, *gbufsize, "%s", rvalp->ir_pval);
1666 if (nbytes >= *gbufsize) {
1667 /* insufficient buffer space */
1668 *gbufsize = nbytes + 1;
1669 err = ENOBUFS;
1670 }
1671 }
1672 return (ipadm_errno2status(err));
1673 }
1674
1675 /*
1676 * Persists the property value for a given property in the data store
1677 */
1678 ipadm_status_t
1679 i_ipadm_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
1680 const char *pval, const void *object, uint_t flags)
1681 {
1682 ipmgmt_prop_arg_t parg;
1683 int err = 0;
1684
1685 bzero(&parg, sizeof (parg));
1686 i_ipadm_populate_proparg(&parg, pdp, pval, object);
1687 /*
1688 * Check if value to be persisted need to be appended or removed. This
1689 * is required for multi-valued property.
1690 */
1691 if (flags & IPADM_OPT_APPEND)
1692 parg.ia_flags |= IPMGMT_APPEND;
1693 if (flags & IPADM_OPT_REMOVE)
1694 parg.ia_flags |= IPMGMT_REMOVE;
1695
1696 if (flags & (IPADM_OPT_DEFAULT|IPADM_OPT_REMOVE))
1697 parg.ia_cmd = IPMGMT_CMD_RESETPROP;
1698 else
1699 parg.ia_cmd = IPMGMT_CMD_SETPROP;
1700
1701 err = ipadm_door_call(iph, &parg, sizeof (parg), NULL, 0, B_FALSE);
1702
1703 /*
1704 * its fine if there were no entry in the DB to delete. The user
1705 * might be changing property value, which was not changed
1706 * persistently.
1707 */
1708 if (err == ENOENT)
1709 err = 0;
1710 return (ipadm_errno2status(err));
1711 }
1712
1713 /*
1714 * This is called from ipadm_set_ifprop() to validate the set operation.
1715 * It does the following steps:
1716 * 1. Validates the interface name.
1717 * 2. In case of a persistent operation, verifies that the
1718 * interface is persistent.
1719 */
1720 static ipadm_status_t
1721 i_ipadm_validate_if(ipadm_handle_t iph, const char *ifname,
1722 uint_t proto, uint_t flags)
1723 {
1724 sa_family_t af, other_af;
1725 ipadm_status_t status;
1726 boolean_t p_exists;
1727 boolean_t af_exists, other_af_exists, a_exists;
1728
1729 /* Check if the interface name is valid. */
1730 if (!i_ipadm_validate_ifname(iph, ifname))
1731 return (IPADM_INVALID_ARG);
1732
1733 af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
1734
1735 /* Check if interface exists in the persistent configuration. */
1736 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1737 if (status != IPADM_SUCCESS)
1738 return (status);
1739
1740 /* Check if interface exists in the active configuration. */
1741 af_exists = ipadm_if_enabled(iph, ifname, af);
1742 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1743 other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
1744 a_exists = (af_exists || other_af_exists);
1745 if (!a_exists && p_exists)
1746 return (IPADM_OP_DISABLE_OBJ);
1747 if (!af_exists)
1748 return (IPADM_ENXIO);
1749
1750 /*
1751 * If a persistent operation is requested, check if the underlying
1752 * IP interface is persistent.
1753 */
1754 if ((flags & IPADM_OPT_PERSIST) && !p_exists)
1755 return (IPADM_TEMPORARY_OBJ);
1756 return (IPADM_SUCCESS);
1757 }
1758
1759 /*
1760 * Private protocol properties namespace scheme:
1761 *
1762 * PSARC 2010/080 identified the private protocol property names to be the
1763 * leading protocol names. For e.g. tcp_strong_iss, ip_strict_src_multihoming,
1764 * et al,. However to be consistent with private data-link property names,
1765 * which starts with '_', private protocol property names will start with '_'.
1766 * For e.g. _strong_iss, _strict_src_multihoming, et al,.
1767 */
1768
1769 /* maps new private protocol property name to the old private property name */
1770 typedef struct ipadm_oname2nname_map {
1771 char *iom_oname;
1772 char *iom_nname;
1773 uint_t iom_proto;
1774 } ipadm_oname2nname_map_t;
1775
1776 /*
1777 * IP is a special case. It isn't straight forward to derive the legacy name
1778 * from the new name and vice versa. No set standard was followed in naming
1779 * the properties and hence we need a table to capture the mapping.
1780 */
1781 static ipadm_oname2nname_map_t name_map[] = {
1782 { "arp_probe_delay", "_arp_probe_delay",
1783 MOD_PROTO_IP },
1784 { "arp_fastprobe_delay", "_arp_fastprobe_delay",
1785 MOD_PROTO_IP },
1786 { "arp_probe_interval", "_arp_probe_interval",
1787 MOD_PROTO_IP },
1788 { "arp_fastprobe_interval", "_arp_fastprobe_interval",
1789 MOD_PROTO_IP },
1790 { "arp_probe_count", "_arp_probe_count",
1791 MOD_PROTO_IP },
1792 { "arp_fastprobe_count", "_arp_fastprobe_count",
1793 MOD_PROTO_IP },
1794 { "arp_defend_interval", "_arp_defend_interval",
1795 MOD_PROTO_IP },
1796 { "arp_defend_rate", "_arp_defend_rate",
1797 MOD_PROTO_IP },
1798 { "arp_defend_period", "_arp_defend_period",
1799 MOD_PROTO_IP },
1800 { "ndp_defend_interval", "_ndp_defend_interval",
1801 MOD_PROTO_IP },
1802 { "ndp_defend_rate", "_ndp_defend_rate",
1803 MOD_PROTO_IP },
1804 { "ndp_defend_period", "_ndp_defend_period",
1805 MOD_PROTO_IP },
1806 { "igmp_max_version", "_igmp_max_version",
1807 MOD_PROTO_IP },
1808 { "mld_max_version", "_mld_max_version",
1809 MOD_PROTO_IP },
1810 { "ipsec_override_persocket_policy", "_ipsec_override_persocket_policy",
1811 MOD_PROTO_IP },
1812 { "ipsec_policy_log_interval", "_ipsec_policy_log_interval",
1813 MOD_PROTO_IP },
1814 { "icmp_accept_clear_messages", "_icmp_accept_clear_messages",
1815 MOD_PROTO_IP },
1816 { "igmp_accept_clear_messages", "_igmp_accept_clear_messages",
1817 MOD_PROTO_IP },
1818 { "pim_accept_clear_messages", "_pim_accept_clear_messages",
1819 MOD_PROTO_IP },
1820 { "ip_respond_to_echo_multicast", "_respond_to_echo_multicast",
1821 MOD_PROTO_IPV4 },
1822 { "ip_send_redirects", "_send_redirects",
1823 MOD_PROTO_IPV4 },
1824 { "ip_forward_src_routed", "_forward_src_routed",
1825 MOD_PROTO_IPV4 },
1826 { "ip_icmp_return_data_bytes", "_icmp_return_data_bytes",
1827 MOD_PROTO_IPV4 },
1828 { "ip_ignore_redirect", "_ignore_redirect",
1829 MOD_PROTO_IPV4 },
1830 { "ip_strict_dst_multihoming", "_strict_dst_multihoming",
1831 MOD_PROTO_IPV4 },
1832 { "ip_reasm_timeout", "_reasm_timeout",
1833 MOD_PROTO_IPV4 },
1834 { "ip_strict_src_multihoming", "_strict_src_multihoming",
1835 MOD_PROTO_IPV4 },
1836 { "ipv4_dad_announce_interval", "_dad_announce_interval",
1837 MOD_PROTO_IPV4 },
1838 { "ipv4_icmp_return_pmtu", "_icmp_return_pmtu",
1839 MOD_PROTO_IPV4 },
1840 { "ipv6_dad_announce_interval", "_dad_announce_interval",
1841 MOD_PROTO_IPV6 },
1842 { "ipv6_icmp_return_pmtu", "_icmp_return_pmtu",
1843 MOD_PROTO_IPV6 },
1844 { NULL, NULL, MOD_PROTO_NONE }
1845 };
1846
1847 /*
1848 * Following API returns a new property name in `nname' for the given legacy
1849 * property name in `oname'.
1850 */
1851 int
1852 ipadm_legacy2new_propname(const char *oname, char *nname, uint_t nnamelen,
1853 uint_t *proto)
1854 {
1855 const char *str;
1856 ipadm_oname2nname_map_t *ionmp;
1857
1858 /* if it's a public property, there is nothing to return */
1859 if (i_ipadm_get_prop_desc(oname, *proto, NULL) != NULL)
1860 return (-1);
1861
1862 /*
1863 * we didn't find the `oname' in the table, check if the property
1864 * name begins with a leading protocol.
1865 */
1866 str = oname;
1867 switch (*proto) {
1868 case MOD_PROTO_TCP:
1869 if (strstr(oname, "tcp_") == oname)
1870 str += strlen("tcp");
1871 break;
1872 case MOD_PROTO_SCTP:
1873 if (strstr(oname, "sctp_") == oname)
1874 str += strlen("sctp");
1875 break;
1876 case MOD_PROTO_UDP:
1877 if (strstr(oname, "udp_") == oname)
1878 str += strlen("udp");
1879 break;
1880 case MOD_PROTO_RAWIP:
1881 if (strstr(oname, "icmp_") == oname)
1882 str += strlen("icmp");
1883 break;
1884 case MOD_PROTO_IP:
1885 case MOD_PROTO_IPV4:
1886 case MOD_PROTO_IPV6:
1887 if (strstr(oname, "ip6_") == oname) {
1888 *proto = MOD_PROTO_IPV6;
1889 str += strlen("ip6");
1890 } else {
1891 for (ionmp = name_map; ionmp->iom_oname != NULL;
1892 ionmp++) {
1893 if (strcmp(oname, ionmp->iom_oname) == 0) {
1894 str = ionmp->iom_nname;
1895 *proto = ionmp->iom_proto;
1896 break;
1897 }
1898 }
1899 if (ionmp->iom_oname != NULL)
1900 break;
1901
1902 if (strstr(oname, "ip_") == oname) {
1903 *proto = MOD_PROTO_IP;
1904 str += strlen("ip");
1905 }
1906 }
1907 break;
1908 default:
1909 return (-1);
1910 }
1911 (void) snprintf(nname, nnamelen, "%s", str);
1912 return (0);
1913 }
1914
1915 /*
1916 * Following API is required for ndd.c alone. To maintain backward
1917 * compatibility with ndd output, we need to print the legacy name
1918 * for the new name.
1919 */
1920 int
1921 ipadm_new2legacy_propname(const char *oname, char *nname,
1922 uint_t nnamelen, uint_t proto)
1923 {
1924 char *prefix;
1925 ipadm_oname2nname_map_t *ionmp;
1926
1927 /* if it's a public property, there is nothing to prepend */
1928 if (i_ipadm_get_prop_desc(oname, proto, NULL) != NULL)
1929 return (-1);
1930
1931 switch (proto) {
1932 case MOD_PROTO_TCP:
1933 prefix = "tcp";
1934 break;
1935 case MOD_PROTO_SCTP:
1936 prefix = "sctp";
1937 break;
1938 case MOD_PROTO_UDP:
1939 prefix = "udp";
1940 break;
1941 case MOD_PROTO_RAWIP:
1942 prefix = "icmp";
1943 break;
1944 case MOD_PROTO_IP:
1945 case MOD_PROTO_IPV4:
1946 case MOD_PROTO_IPV6:
1947 /* handle special case for IP */
1948 for (ionmp = name_map; ionmp->iom_oname != NULL; ionmp++) {
1949 if (strcmp(oname, ionmp->iom_nname) == 0 &&
1950 ionmp->iom_proto == proto) {
1951 (void) strlcpy(nname, ionmp->iom_oname,
1952 nnamelen);
1953 return (0);
1954 }
1955 }
1956 if (proto == MOD_PROTO_IPV6)
1957 prefix = "ip6";
1958 else
1959 prefix = "ip";
1960 break;
1961 default:
1962 return (-1);
1963 }
1964 (void) snprintf(nname, nnamelen, "%s%s", prefix, oname);
1965 return (0);
1966 }