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