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