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