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