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