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 * 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 * 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 * 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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