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 ipadm_prop_desc_t ipadm_privprop = 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 boolean_t is_if = (ifname != NULL); 1188 int err = 0; 1189 1190 pdp = i_ipadm_get_prop_desc(pname, proto, &err); 1191 if (err == EPROTO) 1192 return (IPADM_BAD_PROTOCOL); 1193 /* there are no private interface properties */ 1194 if (is_if && err == ENOENT) 1195 return (IPADM_PROP_UNKNOWN); 1196 1197 if (pdp != NULL) { 1198 /* 1199 * check whether the property can be 1200 * applied on an interface 1201 */ 1202 if (is_if && !(pdp->ipd_class & IPADMPROP_CLASS_IF)) 1203 return (IPADM_INVALID_ARG); 1204 /* 1205 * check whether the property can be 1206 * applied on a module 1207 */ 1208 if (!is_if && !(pdp->ipd_class & IPADMPROP_CLASS_MODULE)) 1209 return (IPADM_INVALID_ARG); 1210 1211 } else { 1212 /* private protocol properties, pass it to kernel directly */ 1213 pdp = &ipadm_privprop; 1214 (void) strlcpy(priv_propname, pname, sizeof (priv_propname)); 1215 pdp->ipd_name = priv_propname; 1216 } 1217 1218 switch (valtype) { 1219 case IPADM_OPT_PERM: 1220 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto, 1221 MOD_PROP_PERM); 1222 if (status == IPADM_SUCCESS) 1223 i_ipadm_perm2str(buf, bufsize); 1224 break; 1225 case IPADM_OPT_ACTIVE: 1226 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto, 1227 MOD_PROP_ACTIVE); 1228 break; 1229 case IPADM_OPT_DEFAULT: 1230 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto, 1231 MOD_PROP_DEFAULT); 1232 break; 1233 case IPADM_OPT_POSSIBLE: 1234 if (pdp->ipd_get_range != NULL) { 1235 status = pdp->ipd_get_range(iph, ifname, pdp, buf, 1236 bufsize, proto, MOD_PROP_POSSIBLE); 1237 break; 1238 } 1239 buf[0] = '\0'; 1240 break; 1241 case IPADM_OPT_PERSIST: 1242 /* retrieve from database */ 1243 if (is_if) 1244 status = i_ipadm_get_persist_propval(iph, pdp, buf, 1245 bufsize, ifname); 1246 else 1247 status = i_ipadm_get_persist_propval(iph, pdp, buf, 1248 bufsize, ipadm_proto2str(proto)); 1249 break; 1250 default: 1251 status = IPADM_INVALID_ARG; 1252 break; 1253 } 1254 return (status); 1255 } 1256 1257 /* 1258 * Get protocol property of the specified protocol. 1259 */ 1260 ipadm_status_t 1261 ipadm_get_prop(ipadm_handle_t iph, const char *pname, char *buf, 1262 uint_t *bufsize, uint_t proto, uint_t valtype) 1263 { 1264 /* 1265 * validate the arguments of the function. 1266 */ 1267 if (iph == NULL || pname == NULL || buf == NULL || 1268 bufsize == NULL || *bufsize == 0) { 1269 return (IPADM_INVALID_ARG); 1270 } 1271 /* 1272 * Do we support this proto, if not return error. 1273 */ 1274 if (ipadm_proto2str(proto) == NULL) 1275 return (IPADM_NOTSUP); 1276 1277 return (i_ipadm_getprop_common(iph, NULL, pname, buf, bufsize, 1278 proto, valtype)); 1279 } 1280 1281 /* 1282 * Get interface property of the specified interface. 1283 */ 1284 ipadm_status_t 1285 ipadm_get_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname, 1286 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype) 1287 { 1288 /* validate the arguments of the function. */ 1289 if (iph == NULL || pname == NULL || buf == NULL || 1290 bufsize == NULL || *bufsize == 0) { 1291 return (IPADM_INVALID_ARG); 1292 } 1293 1294 /* Do we support this proto, if not return error. */ 1295 if (ipadm_proto2str(proto) == NULL) 1296 return (IPADM_NOTSUP); 1297 1298 /* 1299 * check if interface name is provided for interface property and 1300 * is valid. 1301 */ 1302 if (!i_ipadm_validate_ifname(iph, ifname)) 1303 return (IPADM_INVALID_ARG); 1304 1305 return (i_ipadm_getprop_common(iph, ifname, pname, buf, bufsize, 1306 proto, valtype)); 1307 } 1308 1309 /* 1310 * Allocates sufficient ioctl buffers and copies property name and the 1311 * value, among other things. If the flag IPADM_OPT_DEFAULT is set, then 1312 * `pval' will be NULL and it instructs the kernel to reset the current 1313 * value to property's default value. 1314 */ 1315 static ipadm_status_t 1316 i_ipadm_set_prop(ipadm_handle_t iph, const void *arg, 1317 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 1318 { 1319 ipadm_status_t status = IPADM_SUCCESS; 1320 const char *ifname = arg; 1321 mod_ioc_prop_t *mip; 1322 char *pname = pdp->ipd_name; 1323 uint_t valsize, iocsize; 1324 uint_t iocflags = 0; 1325 1326 if (flags & IPADM_OPT_DEFAULT) { 1327 iocflags |= MOD_PROP_DEFAULT; 1328 } else if (flags & IPADM_OPT_ACTIVE) { 1329 iocflags |= MOD_PROP_ACTIVE; 1330 if (flags & IPADM_OPT_APPEND) 1331 iocflags |= MOD_PROP_APPEND; 1332 else if (flags & IPADM_OPT_REMOVE) 1333 iocflags |= MOD_PROP_REMOVE; 1334 } 1335 1336 if (pval != NULL) { 1337 valsize = strlen(pval); 1338 iocsize = sizeof (mod_ioc_prop_t) + valsize - 1; 1339 } else { 1340 valsize = 0; 1341 iocsize = sizeof (mod_ioc_prop_t); 1342 } 1343 1344 if ((mip = calloc(1, iocsize)) == NULL) 1345 return (IPADM_NO_BUFS); 1346 1347 mip->mpr_version = MOD_PROP_VERSION; 1348 mip->mpr_flags = iocflags; 1349 mip->mpr_proto = proto; 1350 if (ifname != NULL) { 1351 (void) strlcpy(mip->mpr_ifname, ifname, 1352 sizeof (mip->mpr_ifname)); 1353 } 1354 1355 (void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name)); 1356 mip->mpr_valsize = valsize; 1357 if (pval != NULL) 1358 bcopy(pval, mip->mpr_val, valsize); 1359 1360 if (i_ipadm_strioctl(iph->iph_sock, SIOCSETPROP, (char *)mip, 1361 iocsize) < 0) { 1362 if (errno == ENOENT) 1363 status = IPADM_PROP_UNKNOWN; 1364 else 1365 status = ipadm_errno2status(errno); 1366 } 1367 free(mip); 1368 return (status); 1369 } 1370 1371 /* 1372 * Common function for modifying both protocol/interface property. 1373 * 1374 * If: 1375 * IPADM_OPT_PERSIST is set then the value is persisted. 1376 * IPADM_OPT_DEFAULT is set then the default value for the property will 1377 * be applied. 1378 */ 1379 static ipadm_status_t 1380 i_ipadm_setprop_common(ipadm_handle_t iph, const char *ifname, 1381 const char *pname, const char *buf, uint_t proto, uint_t pflags) 1382 { 1383 ipadm_status_t status = IPADM_SUCCESS; 1384 boolean_t persist = (pflags & IPADM_OPT_PERSIST); 1385 boolean_t reset = (pflags & IPADM_OPT_DEFAULT); 1386 ipadm_prop_desc_t *pdp; 1387 boolean_t is_if = (ifname != NULL); 1388 char priv_propname[MAXPROPNAMELEN]; 1389 int err = 0; 1390 1391 /* Check that property value is within the allowed size */ 1392 if (!reset && strnlen(buf, MAXPROPVALLEN) >= MAXPROPVALLEN) 1393 return (IPADM_INVALID_ARG); 1394 1395 pdp = i_ipadm_get_prop_desc(pname, proto, &err); 1396 if (err == EPROTO) 1397 return (IPADM_BAD_PROTOCOL); 1398 /* there are no private interface properties */ 1399 if (is_if && err == ENOENT) 1400 return (IPADM_PROP_UNKNOWN); 1401 1402 if (pdp != NULL) { 1403 /* do some sanity checks */ 1404 if (is_if) { 1405 if (!(pdp->ipd_class & IPADMPROP_CLASS_IF)) 1406 return (IPADM_INVALID_ARG); 1407 } else { 1408 if (!(pdp->ipd_class & IPADMPROP_CLASS_MODULE)) 1409 return (IPADM_INVALID_ARG); 1410 } 1411 /* 1412 * if the property is not multi-valued and IPADM_OPT_APPEND or 1413 * IPADM_OPT_REMOVE is specified, return IPADM_INVALID_ARG. 1414 */ 1415 if (!(pdp->ipd_flags & IPADMPROP_MULVAL) && (pflags & 1416 (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) { 1417 return (IPADM_INVALID_ARG); 1418 } 1419 } else { 1420 /* private protocol property, pass it to kernel directly */ 1421 pdp = &ipadm_privprop; 1422 (void) strlcpy(priv_propname, pname, sizeof (priv_propname)); 1423 pdp->ipd_name = priv_propname; 1424 } 1425 1426 status = pdp->ipd_set(iph, ifname, pdp, buf, proto, pflags); 1427 if (status != IPADM_SUCCESS) 1428 return (status); 1429 1430 if (persist) { 1431 if (is_if) 1432 status = i_ipadm_persist_propval(iph, pdp, buf, ifname, 1433 pflags); 1434 else 1435 status = i_ipadm_persist_propval(iph, pdp, buf, 1436 ipadm_proto2str(proto), pflags); 1437 } 1438 return (status); 1439 } 1440 1441 /* 1442 * Sets the property value of the specified interface 1443 */ 1444 ipadm_status_t 1445 ipadm_set_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname, 1446 const char *buf, uint_t proto, uint_t pflags) 1447 { 1448 boolean_t reset = (pflags & IPADM_OPT_DEFAULT); 1449 ipadm_status_t status; 1450 1451 /* check for solaris.network.interface.config authorization */ 1452 if (!ipadm_check_auth()) 1453 return (IPADM_EAUTH); 1454 /* 1455 * validate the arguments of the function. 1456 */ 1457 if (iph == NULL || pname == NULL || (!reset && buf == NULL) || 1458 pflags == 0 || pflags == IPADM_OPT_PERSIST || 1459 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT))) { 1460 return (IPADM_INVALID_ARG); 1461 } 1462 1463 /* 1464 * Do we support this protocol, if not return error. 1465 */ 1466 if (ipadm_proto2str(proto) == NULL) 1467 return (IPADM_NOTSUP); 1468 1469 /* 1470 * Validate the interface and check if a persistent 1471 * operation is performed on a temporary object. 1472 */ 1473 status = i_ipadm_validate_if(iph, ifname, proto, pflags); 1474 if (status != IPADM_SUCCESS) 1475 return (status); 1476 1477 return (i_ipadm_setprop_common(iph, ifname, pname, buf, proto, 1478 pflags)); 1479 } 1480 1481 /* 1482 * Sets the property value of the specified protocol. 1483 */ 1484 ipadm_status_t 1485 ipadm_set_prop(ipadm_handle_t iph, const char *pname, const char *buf, 1486 uint_t proto, uint_t pflags) 1487 { 1488 boolean_t reset = (pflags & IPADM_OPT_DEFAULT); 1489 1490 /* check for solaris.network.interface.config authorization */ 1491 if (!ipadm_check_auth()) 1492 return (IPADM_EAUTH); 1493 /* 1494 * validate the arguments of the function. 1495 */ 1496 if (iph == NULL || pname == NULL ||(!reset && buf == NULL) || 1497 pflags == 0 || pflags == IPADM_OPT_PERSIST || 1498 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT| 1499 IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) { 1500 return (IPADM_INVALID_ARG); 1501 } 1502 1503 /* 1504 * Do we support this proto, if not return error. 1505 */ 1506 if (ipadm_proto2str(proto) == NULL) 1507 return (IPADM_NOTSUP); 1508 1509 return (i_ipadm_setprop_common(iph, NULL, pname, buf, proto, 1510 pflags)); 1511 } 1512 1513 /* helper function for ipadm_walk_proptbl */ 1514 static void 1515 i_ipadm_walk_proptbl(ipadm_prop_desc_t *pdtbl, uint_t proto, uint_t class, 1516 ipadm_prop_wfunc_t *func, void *arg) 1517 { 1518 ipadm_prop_desc_t *pdp; 1519 1520 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) { 1521 if (!(pdp->ipd_class & class)) 1522 continue; 1523 1524 if (proto != MOD_PROTO_NONE && !(pdp->ipd_proto & proto)) 1525 continue; 1526 1527 /* 1528 * we found a class specific match, call the 1529 * user callback function. 1530 */ 1531 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE) 1532 break; 1533 } 1534 } 1535 1536 /* 1537 * Walks through all the properties, for a given protocol and property class 1538 * (protocol or interface). 1539 * 1540 * Further if proto == MOD_PROTO_NONE, then it walks through all the supported 1541 * protocol property tables. 1542 */ 1543 ipadm_status_t 1544 ipadm_walk_proptbl(uint_t proto, uint_t class, ipadm_prop_wfunc_t *func, 1545 void *arg) 1546 { 1547 ipadm_prop_desc_t *pdtbl; 1548 ipadm_status_t status = IPADM_SUCCESS; 1549 int i; 1550 int count = A_CNT(protocols); 1551 1552 if (func == NULL) 1553 return (IPADM_INVALID_ARG); 1554 1555 switch (class) { 1556 case IPADMPROP_CLASS_ADDR: 1557 pdtbl = ipadm_addrprop_table; 1558 break; 1559 case IPADMPROP_CLASS_IF: 1560 case IPADMPROP_CLASS_MODULE: 1561 pdtbl = i_ipadm_get_propdesc_table(proto); 1562 if (pdtbl == NULL && proto != MOD_PROTO_NONE) 1563 return (IPADM_INVALID_ARG); 1564 break; 1565 default: 1566 return (IPADM_INVALID_ARG); 1567 } 1568 1569 if (pdtbl != NULL) { 1570 /* 1571 * proto will be MOD_PROTO_NONE in the case of 1572 * IPADMPROP_CLASS_ADDR. 1573 */ 1574 i_ipadm_walk_proptbl(pdtbl, proto, class, func, arg); 1575 } else { 1576 /* Walk thru all the protocol tables, we support */ 1577 for (i = 0; i < count; i++) { 1578 pdtbl = i_ipadm_get_propdesc_table(protocols[i]); 1579 i_ipadm_walk_proptbl(pdtbl, protocols[i], class, func, 1580 arg); 1581 } 1582 } 1583 return (status); 1584 } 1585 1586 /* 1587 * Given a property name, walks through all the instances of a property name. 1588 * Some properties have two instances one for v4 interfaces and another for v6 1589 * interfaces. For example: MTU. MTU can have different values for v4 and v6. 1590 * Therefore there are two properties for 'MTU'. 1591 * 1592 * This function invokes `func' for every instance of property `pname' 1593 */ 1594 ipadm_status_t 1595 ipadm_walk_prop(const char *pname, uint_t proto, uint_t class, 1596 ipadm_prop_wfunc_t *func, void *arg) 1597 { 1598 ipadm_prop_desc_t *pdtbl, *pdp; 1599 ipadm_status_t status = IPADM_SUCCESS; 1600 boolean_t matched = B_FALSE; 1601 1602 if (pname == NULL || func == NULL) 1603 return (IPADM_INVALID_ARG); 1604 1605 switch (class) { 1606 case IPADMPROP_CLASS_ADDR: 1607 pdtbl = ipadm_addrprop_table; 1608 break; 1609 case IPADMPROP_CLASS_IF: 1610 case IPADMPROP_CLASS_MODULE: 1611 pdtbl = i_ipadm_get_propdesc_table(proto); 1612 break; 1613 default: 1614 return (IPADM_INVALID_ARG); 1615 } 1616 1617 if (pdtbl == NULL) 1618 return (IPADM_INVALID_ARG); 1619 1620 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) { 1621 if (strcmp(pname, pdp->ipd_name) != 0) 1622 continue; 1623 if (!(pdp->ipd_proto & proto)) 1624 continue; 1625 matched = B_TRUE; 1626 /* we found a match, call the callback function */ 1627 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE) 1628 break; 1629 } 1630 if (!matched) 1631 status = IPADM_PROP_UNKNOWN; 1632 return (status); 1633 } 1634 1635 /* ARGSUSED */ 1636 ipadm_status_t 1637 i_ipadm_get_onoff(ipadm_handle_t iph, const void *arg, ipadm_prop_desc_t *dp, 1638 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype) 1639 { 1640 (void) snprintf(buf, *bufsize, "%s,%s", IPADM_ONSTR, IPADM_OFFSTR); 1641 return (IPADM_SUCCESS); 1642 } 1643 1644 /* 1645 * Makes a door call to ipmgmtd to retrieve the persisted property value 1646 */ 1647 ipadm_status_t 1648 i_ipadm_get_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp, 1649 char *gbuf, uint_t *gbufsize, const void *object) 1650 { 1651 ipmgmt_prop_arg_t parg; 1652 ipmgmt_getprop_rval_t rval, *rvalp; 1653 size_t nbytes; 1654 int err = 0; 1655 1656 bzero(&parg, sizeof (parg)); 1657 parg.ia_cmd = IPMGMT_CMD_GETPROP; 1658 i_ipadm_populate_proparg(&parg, pdp, NULL, object); 1659 1660 rvalp = &rval; 1661 err = ipadm_door_call(iph, &parg, sizeof (parg), (void **)&rvalp, 1662 sizeof (rval), B_FALSE); 1663 if (err == 0) { 1664 /* assert that rvalp was not reallocated */ 1665 assert(rvalp == &rval); 1666 1667 /* `ir_pval' contains the property value */ 1668 nbytes = snprintf(gbuf, *gbufsize, "%s", rvalp->ir_pval); 1669 if (nbytes >= *gbufsize) { 1670 /* insufficient buffer space */ 1671 *gbufsize = nbytes + 1; 1672 err = ENOBUFS; 1673 } 1674 } 1675 return (ipadm_errno2status(err)); 1676 } 1677 1678 /* 1679 * Persists the property value for a given property in the data store 1680 */ 1681 ipadm_status_t 1682 i_ipadm_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp, 1683 const char *pval, const void *object, uint_t flags) 1684 { 1685 ipmgmt_prop_arg_t parg; 1686 int err = 0; 1687 1688 bzero(&parg, sizeof (parg)); 1689 i_ipadm_populate_proparg(&parg, pdp, pval, object); 1690 /* 1691 * Check if value to be persisted need to be appended or removed. This 1692 * is required for multi-valued property. 1693 */ 1694 if (flags & IPADM_OPT_APPEND) 1695 parg.ia_flags |= IPMGMT_APPEND; 1696 if (flags & IPADM_OPT_REMOVE) 1697 parg.ia_flags |= IPMGMT_REMOVE; 1698 1699 if (flags & (IPADM_OPT_DEFAULT|IPADM_OPT_REMOVE)) 1700 parg.ia_cmd = IPMGMT_CMD_RESETPROP; 1701 else 1702 parg.ia_cmd = IPMGMT_CMD_SETPROP; 1703 1704 err = ipadm_door_call(iph, &parg, sizeof (parg), NULL, 0, B_FALSE); 1705 1706 /* 1707 * its fine if there were no entry in the DB to delete. The user 1708 * might be changing property value, which was not changed 1709 * persistently. 1710 */ 1711 if (err == ENOENT) 1712 err = 0; 1713 return (ipadm_errno2status(err)); 1714 } 1715 1716 /* 1717 * This is called from ipadm_set_ifprop() to validate the set operation. 1718 * It does the following steps: 1719 * 1. Validates the interface name. 1720 * 2. In case of a persistent operation, verifies that the 1721 * interface is persistent. 1722 */ 1723 static ipadm_status_t 1724 i_ipadm_validate_if(ipadm_handle_t iph, const char *ifname, 1725 uint_t proto, uint_t flags) 1726 { 1727 sa_family_t af, other_af; 1728 ipadm_status_t status; 1729 boolean_t p_exists; 1730 boolean_t af_exists, other_af_exists, a_exists; 1731 1732 /* Check if the interface name is valid. */ 1733 if (!i_ipadm_validate_ifname(iph, ifname)) 1734 return (IPADM_INVALID_ARG); 1735 1736 af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET); 1737 1738 /* Check if interface exists in the persistent configuration. */ 1739 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists); 1740 if (status != IPADM_SUCCESS) 1741 return (status); 1742 1743 /* Check if interface exists in the active configuration. */ 1744 af_exists = ipadm_if_enabled(iph, ifname, af); 1745 other_af = (af == AF_INET ? AF_INET6 : AF_INET); 1746 other_af_exists = ipadm_if_enabled(iph, ifname, other_af); 1747 a_exists = (af_exists || other_af_exists); 1748 if (!a_exists && p_exists) 1749 return (IPADM_OP_DISABLE_OBJ); 1750 if (!af_exists) 1751 return (IPADM_ENXIO); 1752 1753 /* 1754 * If a persistent operation is requested, check if the underlying 1755 * IP interface is persistent. 1756 */ 1757 if ((flags & IPADM_OPT_PERSIST) && !p_exists) 1758 return (IPADM_TEMPORARY_OBJ); 1759 return (IPADM_SUCCESS); 1760 } 1761 1762 /* 1763 * Private protocol properties namespace scheme: 1764 * 1765 * PSARC 2010/080 identified the private protocol property names to be the 1766 * leading protocol names. For e.g. tcp_strong_iss, ip_strict_src_multihoming, 1767 * et al,. However to be consistent with private data-link property names, 1768 * which starts with '_', private protocol property names will start with '_'. 1769 * For e.g. _strong_iss, _strict_src_multihoming, et al,. 1770 */ 1771 1772 /* maps new private protocol property name to the old private property name */ 1773 typedef struct ipadm_oname2nname_map { 1774 char *iom_oname; 1775 char *iom_nname; 1776 uint_t iom_proto; 1777 } ipadm_oname2nname_map_t; 1778 1779 /* 1780 * IP is a special case. It isn't straight forward to derive the legacy name 1781 * from the new name and vice versa. No set standard was followed in naming 1782 * the properties and hence we need a table to capture the mapping. 1783 */ 1784 static ipadm_oname2nname_map_t name_map[] = { 1785 { "arp_probe_delay", "_arp_probe_delay", 1786 MOD_PROTO_IP }, 1787 { "arp_fastprobe_delay", "_arp_fastprobe_delay", 1788 MOD_PROTO_IP }, 1789 { "arp_probe_interval", "_arp_probe_interval", 1790 MOD_PROTO_IP }, 1791 { "arp_fastprobe_interval", "_arp_fastprobe_interval", 1792 MOD_PROTO_IP }, 1793 { "arp_probe_count", "_arp_probe_count", 1794 MOD_PROTO_IP }, 1795 { "arp_fastprobe_count", "_arp_fastprobe_count", 1796 MOD_PROTO_IP }, 1797 { "arp_defend_interval", "_arp_defend_interval", 1798 MOD_PROTO_IP }, 1799 { "arp_defend_rate", "_arp_defend_rate", 1800 MOD_PROTO_IP }, 1801 { "arp_defend_period", "_arp_defend_period", 1802 MOD_PROTO_IP }, 1803 { "ndp_defend_interval", "_ndp_defend_interval", 1804 MOD_PROTO_IP }, 1805 { "ndp_defend_rate", "_ndp_defend_rate", 1806 MOD_PROTO_IP }, 1807 { "ndp_defend_period", "_ndp_defend_period", 1808 MOD_PROTO_IP }, 1809 { "igmp_max_version", "_igmp_max_version", 1810 MOD_PROTO_IP }, 1811 { "mld_max_version", "_mld_max_version", 1812 MOD_PROTO_IP }, 1813 { "ipsec_override_persocket_policy", "_ipsec_override_persocket_policy", 1814 MOD_PROTO_IP }, 1815 { "ipsec_policy_log_interval", "_ipsec_policy_log_interval", 1816 MOD_PROTO_IP }, 1817 { "icmp_accept_clear_messages", "_icmp_accept_clear_messages", 1818 MOD_PROTO_IP }, 1819 { "igmp_accept_clear_messages", "_igmp_accept_clear_messages", 1820 MOD_PROTO_IP }, 1821 { "pim_accept_clear_messages", "_pim_accept_clear_messages", 1822 MOD_PROTO_IP }, 1823 { "ip_respond_to_echo_multicast", "_respond_to_echo_multicast", 1824 MOD_PROTO_IPV4 }, 1825 { "ip_send_redirects", "_send_redirects", 1826 MOD_PROTO_IPV4 }, 1827 { "ip_forward_src_routed", "_forward_src_routed", 1828 MOD_PROTO_IPV4 }, 1829 { "ip_icmp_return_data_bytes", "_icmp_return_data_bytes", 1830 MOD_PROTO_IPV4 }, 1831 { "ip_ignore_redirect", "_ignore_redirect", 1832 MOD_PROTO_IPV4 }, 1833 { "ip_strict_dst_multihoming", "_strict_dst_multihoming", 1834 MOD_PROTO_IPV4 }, 1835 { "ip_reasm_timeout", "_reasm_timeout", 1836 MOD_PROTO_IPV4 }, 1837 { "ip_strict_src_multihoming", "_strict_src_multihoming", 1838 MOD_PROTO_IPV4 }, 1839 { "ipv4_dad_announce_interval", "_dad_announce_interval", 1840 MOD_PROTO_IPV4 }, 1841 { "ipv4_icmp_return_pmtu", "_icmp_return_pmtu", 1842 MOD_PROTO_IPV4 }, 1843 { "ipv6_dad_announce_interval", "_dad_announce_interval", 1844 MOD_PROTO_IPV6 }, 1845 { "ipv6_icmp_return_pmtu", "_icmp_return_pmtu", 1846 MOD_PROTO_IPV6 }, 1847 { NULL, NULL, MOD_PROTO_NONE } 1848 }; 1849 1850 /* 1851 * Following API returns a new property name in `nname' for the given legacy 1852 * property name in `oname'. 1853 */ 1854 int 1855 ipadm_legacy2new_propname(const char *oname, char *nname, uint_t nnamelen, 1856 uint_t *proto) 1857 { 1858 const char *str; 1859 ipadm_oname2nname_map_t *ionmp; 1860 1861 /* if it's a public property, there is nothing to return */ 1862 if (i_ipadm_get_prop_desc(oname, *proto, NULL) != NULL) 1863 return (-1); 1864 1865 /* 1866 * we didn't find the `oname' in the table, check if the property 1867 * name begins with a leading protocol. 1868 */ 1869 str = oname; 1870 switch (*proto) { 1871 case MOD_PROTO_TCP: 1872 if (strstr(oname, "tcp_") == oname) 1873 str += strlen("tcp"); 1874 break; 1875 case MOD_PROTO_SCTP: 1876 if (strstr(oname, "sctp_") == oname) 1877 str += strlen("sctp"); 1878 break; 1879 case MOD_PROTO_UDP: 1880 if (strstr(oname, "udp_") == oname) 1881 str += strlen("udp"); 1882 break; 1883 case MOD_PROTO_RAWIP: 1884 if (strstr(oname, "icmp_") == oname) 1885 str += strlen("icmp"); 1886 break; 1887 case MOD_PROTO_IP: 1888 case MOD_PROTO_IPV4: 1889 case MOD_PROTO_IPV6: 1890 if (strstr(oname, "ip6_") == oname) { 1891 *proto = MOD_PROTO_IPV6; 1892 str += strlen("ip6"); 1893 } else { 1894 for (ionmp = name_map; ionmp->iom_oname != NULL; 1895 ionmp++) { 1896 if (strcmp(oname, ionmp->iom_oname) == 0) { 1897 str = ionmp->iom_nname; 1898 *proto = ionmp->iom_proto; 1899 break; 1900 } 1901 } 1902 if (ionmp->iom_oname != NULL) 1903 break; 1904 1905 if (strstr(oname, "ip_") == oname) { 1906 *proto = MOD_PROTO_IP; 1907 str += strlen("ip"); 1908 } 1909 } 1910 break; 1911 default: 1912 return (-1); 1913 } 1914 (void) snprintf(nname, nnamelen, "%s", str); 1915 return (0); 1916 } 1917 1918 /* 1919 * Following API is required for ndd.c alone. To maintain backward 1920 * compatibility with ndd output, we need to print the legacy name 1921 * for the new name. 1922 */ 1923 int 1924 ipadm_new2legacy_propname(const char *oname, char *nname, 1925 uint_t nnamelen, uint_t proto) 1926 { 1927 char *prefix; 1928 ipadm_oname2nname_map_t *ionmp; 1929 1930 /* if it's a public property, there is nothing to prepend */ 1931 if (i_ipadm_get_prop_desc(oname, proto, NULL) != NULL) 1932 return (-1); 1933 1934 switch (proto) { 1935 case MOD_PROTO_TCP: 1936 prefix = "tcp"; 1937 break; 1938 case MOD_PROTO_SCTP: 1939 prefix = "sctp"; 1940 break; 1941 case MOD_PROTO_UDP: 1942 prefix = "udp"; 1943 break; 1944 case MOD_PROTO_RAWIP: 1945 prefix = "icmp"; 1946 break; 1947 case MOD_PROTO_IP: 1948 case MOD_PROTO_IPV4: 1949 case MOD_PROTO_IPV6: 1950 /* handle special case for IP */ 1951 for (ionmp = name_map; ionmp->iom_oname != NULL; ionmp++) { 1952 if (strcmp(oname, ionmp->iom_nname) == 0 && 1953 ionmp->iom_proto == proto) { 1954 (void) strlcpy(nname, ionmp->iom_oname, 1955 nnamelen); 1956 return (0); 1957 } 1958 } 1959 if (proto == MOD_PROTO_IPV6) 1960 prefix = "ip6"; 1961 else 1962 prefix = "ip"; 1963 break; 1964 default: 1965 return (-1); 1966 } 1967 (void) snprintf(nname, nnamelen, "%s%s", prefix, oname); 1968 return (0); 1969 } 1970