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