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