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