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