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