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