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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This file contains routines that are used to modify/retrieve protocol or 28 * interface property values. It also holds all the supported properties for 29 * both IP interface and protocols in `ipadm_prop_desc_t'. Following protocols 30 * are supported: IP, IPv4, IPv6, TCP, SCTP, UDP and ICMP. 31 * 32 * This file also contains walkers, which walks through the property table and 33 * calls the callback function, of the form `ipadm_prop_wfunc_t' , for every 34 * property in the table. 35 */ 36 37 #include <unistd.h> 38 #include <errno.h> 39 #include <ctype.h> 40 #include <fcntl.h> 41 #include <strings.h> 42 #include <stdlib.h> 43 #include <netinet/in.h> 44 #include <arpa/inet.h> 45 #include <sys/sockio.h> 46 #include <assert.h> 47 #include <libdllink.h> 48 #include <zone.h> 49 #include "libipadm_impl.h" 50 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; 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; 81 82 /* array of protocols we support */ 83 static int protocols[] = { MOD_PROTO_IP, MOD_PROTO_RAWIP, 84 MOD_PROTO_TCP, MOD_PROTO_UDP, 85 MOD_PROTO_SCTP }; 86 87 /* 88 * Supported IP protocol properties. 89 */ 90 static ipadm_prop_desc_t ipadm_ip_prop_table[] = { 91 { "arp", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 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, 96 i_ipadm_set_forwarding, i_ipadm_get_onoff, 97 i_ipadm_get_forwarding }, 98 99 { "metric", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 100 i_ipadm_set_metric, NULL, i_ipadm_get_metric }, 101 102 { "mtu", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 103 i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu }, 104 105 { "exchange_routes", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 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, 110 i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc }, 111 112 { "ttl", IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4, 113 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 114 115 { "forwarding", IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV6, 116 i_ipadm_set_forwarding, i_ipadm_get_onoff, 117 i_ipadm_get_forwarding }, 118 119 { "hoplimit", IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6, 120 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 121 122 { "metric", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 123 i_ipadm_set_metric, NULL, i_ipadm_get_metric }, 124 125 { "mtu", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 126 i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu }, 127 128 { "nud", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 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, 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, 137 i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc }, 138 139 { NULL, 0, 0, NULL, NULL, NULL } 140 }; 141 142 /* possible values for TCP properties `ecn' and `sack' */ 143 static const char *ecn_sack_vals[] = {"never", "passive", "active", NULL}; 144 145 /* Supported TCP protocol properties */ 146 static ipadm_prop_desc_t ipadm_tcp_prop_table[] = { 147 { "ecn", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 148 i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack }, 149 150 { "extra_priv_ports", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 151 i_ipadm_set_eprivport, i_ipadm_get_prop, i_ipadm_get_prop }, 152 153 { "largest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 154 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 155 156 { "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 157 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 158 159 { "sack", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 160 i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack }, 161 162 { "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 163 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 164 165 { "smallest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 166 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 167 168 { "smallest_nonpriv_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 169 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 170 171 { NULL, 0, 0, NULL, NULL, NULL } 172 }; 173 174 /* Supported UDP protocol properties */ 175 static ipadm_prop_desc_t ipadm_udp_prop_table[] = { 176 { "extra_priv_ports", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 177 i_ipadm_set_eprivport, i_ipadm_get_prop, i_ipadm_get_prop }, 178 179 { "largest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 180 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 181 182 { "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 183 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 184 185 { "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 186 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 187 188 { "smallest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 189 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 190 191 { "smallest_nonpriv_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 192 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 193 194 { NULL, 0, 0, NULL, NULL, NULL } 195 }; 196 197 /* Supported SCTP protocol properties */ 198 static ipadm_prop_desc_t ipadm_sctp_prop_table[] = { 199 { "extra_priv_ports", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 200 i_ipadm_set_eprivport, i_ipadm_get_prop, i_ipadm_get_prop }, 201 202 { "largest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 203 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 204 205 { "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 206 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 207 208 { "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 209 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 210 211 { "smallest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 212 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 213 214 { "smallest_nonpriv_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 215 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 216 217 { NULL, 0, 0, NULL, NULL, NULL } 218 }; 219 220 /* Supported ICMP protocol properties */ 221 static ipadm_prop_desc_t ipadm_icmp_prop_table[] = { 222 { "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 223 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 224 225 { "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 226 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }, 227 228 { NULL, 0, 0, NULL, NULL, NULL } 229 }; 230 231 /* 232 * A dummy private property structure, used while handling private 233 * protocol properties (properties not yet supported by libipadm). 234 */ 235 static ipadm_prop_desc_t ipadm_privprop =\ 236 { NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_NONE, 237 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop }; 238 239 /* 240 * Returns the property description table, for the given protocol 241 */ 242 static ipadm_prop_desc_t * 243 i_ipadm_get_propdesc_table(uint_t proto) 244 { 245 switch (proto) { 246 case MOD_PROTO_IP: 247 case MOD_PROTO_IPV4: 248 case MOD_PROTO_IPV6: 249 return (ipadm_ip_prop_table); 250 case MOD_PROTO_RAWIP: 251 return (ipadm_icmp_prop_table); 252 case MOD_PROTO_TCP: 253 return (ipadm_tcp_prop_table); 254 case MOD_PROTO_UDP: 255 return (ipadm_udp_prop_table); 256 case MOD_PROTO_SCTP: 257 return (ipadm_sctp_prop_table); 258 } 259 260 return (NULL); 261 } 262 263 char * 264 ipadm_proto2str(uint_t proto) 265 { 266 switch (proto) { 267 case MOD_PROTO_IP: 268 return ("ip"); 269 case MOD_PROTO_IPV4: 270 return ("ipv4"); 271 case MOD_PROTO_IPV6: 272 return ("ipv6"); 273 case MOD_PROTO_RAWIP: 274 return ("icmp"); 275 case MOD_PROTO_TCP: 276 return ("tcp"); 277 case MOD_PROTO_UDP: 278 return ("udp"); 279 case MOD_PROTO_SCTP: 280 return ("sctp"); 281 } 282 283 return (NULL); 284 } 285 286 uint_t 287 ipadm_str2proto(const char *protostr) 288 { 289 if (protostr == NULL) 290 return (MOD_PROTO_NONE); 291 if (strcmp(protostr, "tcp") == 0) 292 return (MOD_PROTO_TCP); 293 else if (strcmp(protostr, "udp") == 0) 294 return (MOD_PROTO_UDP); 295 else if (strcmp(protostr, "ip") == 0) 296 return (MOD_PROTO_IP); 297 else if (strcmp(protostr, "ipv4") == 0) 298 return (MOD_PROTO_IPV4); 299 else if (strcmp(protostr, "ipv6") == 0) 300 return (MOD_PROTO_IPV6); 301 else if (strcmp(protostr, "icmp") == 0) 302 return (MOD_PROTO_RAWIP); 303 else if (strcmp(protostr, "sctp") == 0) 304 return (MOD_PROTO_SCTP); 305 else if (strcmp(protostr, "arp") == 0) 306 return (MOD_PROTO_IP); 307 308 return (MOD_PROTO_NONE); 309 } 310 311 /* ARGSUSED */ 312 static ipadm_status_t 313 i_ipadm_set_mtu(ipadm_handle_t iph, const void *arg, 314 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 315 { 316 struct lifreq lifr; 317 char *endp; 318 uint_t mtu; 319 int s; 320 const char *ifname = arg; 321 char val[MAXPROPVALLEN]; 322 323 /* to reset MTU first retrieve the default MTU and then set it */ 324 if (flags & IPADM_OPT_DEFAULT) { 325 ipadm_status_t status; 326 uint_t size = MAXPROPVALLEN; 327 328 status = i_ipadm_get_prop(iph, arg, pdp, val, &size, 329 proto, MOD_PROP_DEFAULT); 330 if (status != IPADM_SUCCESS) 331 return (status); 332 pval = val; 333 } 334 335 errno = 0; 336 mtu = (uint_t)strtol(pval, &endp, 10); 337 if (errno != 0 || *endp != '\0') 338 return (IPADM_INVALID_ARG); 339 340 bzero(&lifr, sizeof (lifr)); 341 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 342 lifr.lifr_mtu = mtu; 343 344 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock); 345 if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0) 346 return (ipadm_errno2status(errno)); 347 348 return (IPADM_SUCCESS); 349 } 350 351 /* ARGSUSED */ 352 static ipadm_status_t 353 i_ipadm_set_metric(ipadm_handle_t iph, const void *arg, 354 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 355 { 356 struct lifreq lifr; 357 char *endp; 358 int metric; 359 const char *ifname = arg; 360 int s; 361 362 /* if we are resetting, set the value to its default value */ 363 if (flags & IPADM_OPT_DEFAULT) { 364 metric = DEF_METRIC_VAL; 365 } else { 366 errno = 0; 367 metric = (uint_t)strtol(pval, &endp, 10); 368 if (errno != 0 || *endp != '\0') 369 return (IPADM_INVALID_ARG); 370 } 371 372 bzero(&lifr, sizeof (lifr)); 373 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 374 lifr.lifr_metric = metric; 375 376 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock); 377 378 if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0) 379 return (ipadm_errno2status(errno)); 380 381 return (IPADM_SUCCESS); 382 } 383 384 /* ARGSUSED */ 385 static ipadm_status_t 386 i_ipadm_set_usesrc(ipadm_handle_t iph, const void *arg, 387 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 388 { 389 struct lifreq lifr; 390 const char *ifname = arg; 391 int s; 392 uint_t ifindex = 0; 393 394 /* if we are resetting, set the value to its default value */ 395 if (flags & IPADM_OPT_DEFAULT) 396 pval = IPADM_NONESTR; 397 398 /* 399 * cannot specify logical interface name. We can also filter out other 400 * bogus interface names here itself through i_ipadm_validate_ifname(). 401 */ 402 if (strcmp(pval, IPADM_NONESTR) != 0 && 403 !i_ipadm_validate_ifname(iph, pval)) 404 return (IPADM_INVALID_ARG); 405 406 bzero(&lifr, sizeof (lifr)); 407 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 408 409 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock); 410 411 if (strcmp(pval, IPADM_NONESTR) != 0) { 412 if ((ifindex = if_nametoindex(pval)) == 0) 413 return (ipadm_errno2status(errno)); 414 lifr.lifr_index = ifindex; 415 } else { 416 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0) 417 return (ipadm_errno2status(errno)); 418 lifr.lifr_index = 0; 419 } 420 if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) < 0) 421 return (ipadm_errno2status(errno)); 422 423 return (IPADM_SUCCESS); 424 } 425 426 /* ARGSUSED */ 427 static ipadm_status_t 428 i_ipadm_set_ifprop_flags(ipadm_handle_t iph, const void *arg, 429 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 430 { 431 ipadm_status_t status = IPADM_SUCCESS; 432 const char *ifname = arg; 433 uint64_t on_flags = 0, off_flags = 0; 434 boolean_t on = B_FALSE; 435 sa_family_t af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET); 436 437 /* if we are resetting, set the value to its default value */ 438 if (flags & IPADM_OPT_DEFAULT) { 439 if (strcmp(pdp->ipd_name, "exchange_routes") == 0 || 440 strcmp(pdp->ipd_name, "arp") == 0 || 441 strcmp(pdp->ipd_name, "nud") == 0) { 442 pval = IPADM_ONSTR; 443 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) { 444 pval = IPADM_OFFSTR; 445 } else { 446 return (IPADM_PROP_UNKNOWN); 447 } 448 } 449 450 if (strcmp(pval, IPADM_ONSTR) == 0) 451 on = B_TRUE; 452 else if (strcmp(pval, IPADM_OFFSTR) == 0) 453 on = B_FALSE; 454 else 455 return (IPADM_INVALID_ARG); 456 457 if (strcmp(pdp->ipd_name, "exchange_routes") == 0) { 458 if (on) 459 off_flags = IFF_NORTEXCH; 460 else 461 on_flags = IFF_NORTEXCH; 462 } else if (strcmp(pdp->ipd_name, "arp") == 0) { 463 if (on) 464 off_flags = IFF_NOARP; 465 else 466 on_flags = IFF_NOARP; 467 } else if (strcmp(pdp->ipd_name, "nud") == 0) { 468 if (on) 469 off_flags = IFF_NONUD; 470 else 471 on_flags = IFF_NONUD; 472 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) { 473 if (on) 474 on_flags = IFF_ROUTER; 475 else 476 off_flags = IFF_ROUTER; 477 } 478 479 if (on_flags || off_flags) { 480 status = i_ipadm_set_flags(iph, ifname, af, on_flags, 481 off_flags); 482 } 483 return (status); 484 } 485 486 /* ARGSUSED */ 487 static ipadm_status_t 488 i_ipadm_set_eprivport(ipadm_handle_t iph, const void *arg, 489 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 490 { 491 nvlist_t *portsnvl = NULL; 492 nvpair_t *nvp; 493 ipadm_status_t status = IPADM_SUCCESS; 494 int err; 495 char *port; 496 uint_t count = 0; 497 498 if (flags & IPADM_OPT_DEFAULT) { 499 assert(pval == NULL); 500 return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags)); 501 } 502 503 if ((err = ipadm_str2nvlist(pval, &portsnvl, IPADM_NORVAL)) != 0) 504 return (ipadm_errno2status(err)); 505 506 /* count the number of ports */ 507 for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL; 508 nvp = nvlist_next_nvpair(portsnvl, nvp)) { 509 ++count; 510 } 511 512 /* We allow only one port to be added or removed, at a time */ 513 if (count > 1 && (flags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) 514 return (IPADM_INVALID_ARG); 515 516 /* 517 * However on reboot, while initializing protocol properties, 518 * extra_priv_ports might have multiple values. Only in that case 519 * we allow setting multiple properties. 520 */ 521 if (count > 1 && !(iph->iph_flags & IPH_INIT)) 522 return (IPADM_INVALID_ARG); 523 524 count = 0; 525 for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL; 526 nvp = nvlist_next_nvpair(portsnvl, nvp)) { 527 port = nvpair_name(nvp); 528 if (count == 0) { 529 status = i_ipadm_set_prop(iph, arg, pdp, port, proto, 530 flags); 531 } else { 532 assert(iph->iph_flags & IPH_INIT); 533 status = i_ipadm_set_prop(iph, arg, pdp, port, proto, 534 IPADM_OPT_APPEND); 535 } 536 ++count; 537 if (status != IPADM_SUCCESS) 538 break; 539 } 540 ret: 541 nvlist_free(portsnvl); 542 return (status); 543 } 544 545 /* ARGSUSED */ 546 static ipadm_status_t 547 i_ipadm_set_forwarding(ipadm_handle_t iph, const void *arg, 548 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 549 { 550 const char *ifname = arg; 551 ipadm_status_t status; 552 553 /* 554 * if interface name is provided, then set forwarding using the 555 * IFF_ROUTER flag 556 */ 557 if (ifname != NULL) { 558 status = i_ipadm_set_ifprop_flags(iph, ifname, pdp, pval, 559 proto, flags); 560 } else { 561 char *val = NULL; 562 563 /* 564 * if the caller is IPH_LEGACY, `pval' already contains 565 * numeric values. 566 */ 567 if (!(flags & IPADM_OPT_DEFAULT) && 568 !(iph->iph_flags & IPH_LEGACY)) { 569 570 if (strcmp(pval, IPADM_ONSTR) == 0) 571 val = "1"; 572 else if (strcmp(pval, IPADM_OFFSTR) == 0) 573 val = "0"; 574 else 575 return (IPADM_INVALID_ARG); 576 pval = val; 577 } 578 579 status = i_ipadm_set_prop(iph, ifname, pdp, pval, proto, flags); 580 } 581 582 return (status); 583 } 584 585 /* ARGSUSED */ 586 static ipadm_status_t 587 i_ipadm_set_ecnsack(ipadm_handle_t iph, const void *arg, 588 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 589 { 590 uint_t i; 591 char val[MAXPROPVALLEN]; 592 593 /* if IPH_LEGACY is set, `pval' already contains numeric values */ 594 if (!(flags & IPADM_OPT_DEFAULT) && !(iph->iph_flags & IPH_LEGACY)) { 595 for (i = 0; ecn_sack_vals[i] != NULL; i++) { 596 if (strcmp(pval, ecn_sack_vals[i]) == 0) 597 break; 598 } 599 if (ecn_sack_vals[i] == NULL) 600 return (IPADM_INVALID_ARG); 601 (void) snprintf(val, MAXPROPVALLEN, "%d", i); 602 pval = val; 603 } 604 605 return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags)); 606 } 607 608 /* ARGSUSED */ 609 ipadm_status_t 610 i_ipadm_get_ecnsack(ipadm_handle_t iph, const void *arg, 611 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 612 uint_t valtype) 613 { 614 ipadm_status_t status = IPADM_SUCCESS; 615 uint_t i, nbytes = 0; 616 617 switch (valtype) { 618 case MOD_PROP_POSSIBLE: 619 for (i = 0; ecn_sack_vals[i] != NULL; i++) { 620 if (i == 0) 621 nbytes += snprintf(buf + nbytes, 622 *bufsize - nbytes, "%s", ecn_sack_vals[i]); 623 else 624 nbytes += snprintf(buf + nbytes, 625 *bufsize - nbytes, ",%s", ecn_sack_vals[i]); 626 if (nbytes >= *bufsize) 627 break; 628 } 629 break; 630 case MOD_PROP_PERM: 631 case MOD_PROP_DEFAULT: 632 case MOD_PROP_ACTIVE: 633 status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto, 634 valtype); 635 636 /* 637 * If IPH_LEGACY is set, do not convert the value returned 638 * from kernel, 639 */ 640 if (iph->iph_flags & IPH_LEGACY) 641 break; 642 643 /* 644 * For current and default value, convert the value returned 645 * from kernel to more discrete representation. 646 */ 647 if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE || 648 valtype == MOD_PROP_DEFAULT)) { 649 i = atoi(buf); 650 assert(i < 3); 651 nbytes = snprintf(buf, *bufsize, "%s", 652 ecn_sack_vals[i]); 653 } 654 break; 655 default: 656 return (IPADM_INVALID_ARG); 657 } 658 if (nbytes >= *bufsize) { 659 /* insufficient buffer space */ 660 *bufsize = nbytes + 1; 661 return (IPADM_NO_BUFS); 662 } 663 664 return (status); 665 } 666 667 /* ARGSUSED */ 668 static ipadm_status_t 669 i_ipadm_get_forwarding(ipadm_handle_t iph, const void *arg, 670 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 671 uint_t valtype) 672 { 673 const char *ifname = arg; 674 ipadm_status_t status = IPADM_SUCCESS; 675 676 /* 677 * if interface name is provided, then get forwarding status using 678 * SIOCGLIFFLAGS 679 */ 680 if (ifname != NULL) { 681 status = i_ipadm_get_ifprop_flags(iph, ifname, pdp, 682 buf, bufsize, pdp->ipd_proto, valtype); 683 } else { 684 status = i_ipadm_get_prop(iph, ifname, pdp, buf, 685 bufsize, proto, valtype); 686 /* 687 * If IPH_LEGACY is set, do not convert the value returned 688 * from kernel, 689 */ 690 if (iph->iph_flags & IPH_LEGACY) 691 goto ret; 692 if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE || 693 valtype == MOD_PROP_DEFAULT)) { 694 uint_t val = atoi(buf); 695 696 (void) snprintf(buf, *bufsize, 697 (val == 1 ? IPADM_ONSTR : IPADM_OFFSTR)); 698 } 699 } 700 701 ret: 702 return (status); 703 } 704 705 /* ARGSUSED */ 706 static ipadm_status_t 707 i_ipadm_get_mtu(ipadm_handle_t iph, const void *arg, 708 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 709 uint_t valtype) 710 { 711 struct lifreq lifr; 712 const char *ifname = arg; 713 size_t nbytes; 714 int s; 715 716 switch (valtype) { 717 case MOD_PROP_PERM: 718 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW); 719 break; 720 case MOD_PROP_DEFAULT: 721 case MOD_PROP_POSSIBLE: 722 return (i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, 723 proto, valtype)); 724 case MOD_PROP_ACTIVE: 725 bzero(&lifr, sizeof (lifr)); 726 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 727 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock); 728 729 if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) < 0) 730 return (ipadm_errno2status(errno)); 731 nbytes = snprintf(buf, *bufsize, "%u", lifr.lifr_mtu); 732 break; 733 default: 734 return (IPADM_INVALID_ARG); 735 } 736 if (nbytes >= *bufsize) { 737 /* insufficient buffer space */ 738 *bufsize = nbytes + 1; 739 return (IPADM_NO_BUFS); 740 } 741 return (IPADM_SUCCESS); 742 } 743 744 /* ARGSUSED */ 745 static ipadm_status_t 746 i_ipadm_get_metric(ipadm_handle_t iph, const void *arg, 747 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 748 uint_t valtype) 749 { 750 struct lifreq lifr; 751 const char *ifname = arg; 752 size_t nbytes; 753 int s, val; 754 755 switch (valtype) { 756 case MOD_PROP_PERM: 757 val = MOD_PROP_PERM_RW; 758 break; 759 case MOD_PROP_DEFAULT: 760 val = DEF_METRIC_VAL; 761 break; 762 case MOD_PROP_ACTIVE: 763 bzero(&lifr, sizeof (lifr)); 764 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 765 766 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock); 767 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) 768 return (ipadm_errno2status(errno)); 769 val = lifr.lifr_metric; 770 break; 771 default: 772 return (IPADM_INVALID_ARG); 773 } 774 nbytes = snprintf(buf, *bufsize, "%d", val); 775 if (nbytes >= *bufsize) { 776 /* insufficient buffer space */ 777 *bufsize = nbytes + 1; 778 return (IPADM_NO_BUFS); 779 } 780 781 return (IPADM_SUCCESS); 782 } 783 784 /* ARGSUSED */ 785 static ipadm_status_t 786 i_ipadm_get_usesrc(ipadm_handle_t iph, const void *arg, 787 ipadm_prop_desc_t *ipd, char *buf, uint_t *bufsize, uint_t proto, 788 uint_t valtype) 789 { 790 struct lifreq lifr; 791 const char *ifname = arg; 792 int s; 793 char if_name[IF_NAMESIZE]; 794 size_t nbytes; 795 796 switch (valtype) { 797 case MOD_PROP_PERM: 798 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW); 799 break; 800 case MOD_PROP_DEFAULT: 801 nbytes = snprintf(buf, *bufsize, "%s", IPADM_NONESTR); 802 break; 803 case MOD_PROP_ACTIVE: 804 bzero(&lifr, sizeof (lifr)); 805 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 806 807 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock); 808 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0) 809 return (ipadm_errno2status(errno)); 810 if (lifr.lifr_index == 0) { 811 /* no src address was set, so print 'none' */ 812 (void) strlcpy(if_name, IPADM_NONESTR, 813 sizeof (if_name)); 814 } else if (if_indextoname(lifr.lifr_index, if_name) == NULL) { 815 return (ipadm_errno2status(errno)); 816 } 817 nbytes = snprintf(buf, *bufsize, "%s", if_name); 818 break; 819 default: 820 return (IPADM_INVALID_ARG); 821 } 822 if (nbytes >= *bufsize) { 823 /* insufficient buffer space */ 824 *bufsize = nbytes + 1; 825 return (IPADM_NO_BUFS); 826 } 827 return (IPADM_SUCCESS); 828 } 829 830 /* ARGSUSED */ 831 static ipadm_status_t 832 i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg, 833 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 834 uint_t valtype) 835 { 836 uint64_t intf_flags; 837 char *val; 838 size_t nbytes; 839 const char *ifname = arg; 840 sa_family_t af; 841 ipadm_status_t status = IPADM_SUCCESS; 842 843 switch (valtype) { 844 case MOD_PROP_PERM: 845 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW); 846 break; 847 case MOD_PROP_DEFAULT: 848 if (strcmp(pdp->ipd_name, "exchange_routes") == 0 || 849 strcmp(pdp->ipd_name, "arp") == 0 || 850 strcmp(pdp->ipd_name, "nud") == 0) { 851 val = IPADM_ONSTR; 852 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) { 853 val = IPADM_OFFSTR; 854 } else { 855 return (IPADM_PROP_UNKNOWN); 856 } 857 nbytes = snprintf(buf, *bufsize, "%s", val); 858 break; 859 case MOD_PROP_ACTIVE: 860 af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET); 861 status = i_ipadm_get_flags(iph, ifname, af, &intf_flags); 862 if (status != IPADM_SUCCESS) 863 return (status); 864 865 val = IPADM_OFFSTR; 866 if (strcmp(pdp->ipd_name, "exchange_routes") == 0) { 867 if (!(intf_flags & IFF_NORTEXCH)) 868 val = IPADM_ONSTR; 869 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) { 870 if (intf_flags & IFF_ROUTER) 871 val = IPADM_ONSTR; 872 } else if (strcmp(pdp->ipd_name, "arp") == 0) { 873 if (!(intf_flags & IFF_NOARP)) 874 val = IPADM_ONSTR; 875 } else if (strcmp(pdp->ipd_name, "nud") == 0) { 876 if (!(intf_flags & IFF_NONUD)) 877 val = IPADM_ONSTR; 878 } 879 nbytes = snprintf(buf, *bufsize, "%s", val); 880 break; 881 default: 882 return (IPADM_INVALID_ARG); 883 } 884 if (nbytes >= *bufsize) { 885 /* insufficient buffer space */ 886 *bufsize = nbytes + 1; 887 status = IPADM_NO_BUFS; 888 } 889 890 return (status); 891 } 892 893 static void 894 i_ipadm_perm2str(char *buf, uint_t *bufsize) 895 { 896 uint_t perm = atoi(buf); 897 898 (void) snprintf(buf, *bufsize, "%c%c", 899 ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-', 900 ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-'); 901 } 902 903 /* ARGSUSED */ 904 static ipadm_status_t 905 i_ipadm_get_prop(ipadm_handle_t iph, const void *arg, 906 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 907 uint_t valtype) 908 { 909 ipadm_status_t status = IPADM_SUCCESS; 910 const char *ifname = arg; 911 mod_ioc_prop_t *mip; 912 char *pname = pdp->ipd_name; 913 uint_t iocsize; 914 915 /* allocate sufficient ioctl buffer to retrieve value */ 916 iocsize = sizeof (mod_ioc_prop_t) + *bufsize - 1; 917 if ((mip = calloc(1, iocsize)) == NULL) 918 return (IPADM_NO_BUFS); 919 920 mip->mpr_version = MOD_PROP_VERSION; 921 mip->mpr_flags = valtype; 922 mip->mpr_proto = proto; 923 if (ifname != NULL) { 924 (void) strlcpy(mip->mpr_ifname, ifname, 925 sizeof (mip->mpr_ifname)); 926 } 927 (void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name)); 928 mip->mpr_valsize = *bufsize; 929 930 if (i_ipadm_strioctl(iph->iph_sock, SIOCGETPROP, (char *)mip, 931 iocsize) < 0) { 932 if (errno == ENOENT) 933 status = IPADM_PROP_UNKNOWN; 934 else 935 status = ipadm_errno2status(errno); 936 } else { 937 bcopy(mip->mpr_val, buf, *bufsize); 938 } 939 940 free(mip); 941 return (status); 942 } 943 944 /* 945 * populates the ipmgmt_prop_arg_t based on the class of property. 946 */ 947 static void 948 i_ipadm_populate_proparg(ipmgmt_prop_arg_t *pargp, ipadm_prop_desc_t *pdp, 949 const char *pval, const void *object) 950 { 951 const struct ipadm_addrobj_s *ipaddr; 952 uint_t class = pdp->ipd_class; 953 uint_t proto = pdp->ipd_proto; 954 955 (void) strlcpy(pargp->ia_pname, pdp->ipd_name, 956 sizeof (pargp->ia_pname)); 957 if (pval != NULL) 958 (void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval)); 959 960 switch (class) { 961 case IPADMPROP_CLASS_MODULE: 962 (void) strlcpy(pargp->ia_module, object, 963 sizeof (pargp->ia_module)); 964 break; 965 case IPADMPROP_CLASS_MODIF: 966 /* check if object is protostr or an ifname */ 967 if (ipadm_str2proto(object) != MOD_PROTO_NONE) { 968 (void) strlcpy(pargp->ia_module, object, 969 sizeof (pargp->ia_module)); 970 break; 971 } 972 /* it's an interface property, fall through */ 973 /* FALLTHRU */ 974 case IPADMPROP_CLASS_IF: 975 (void) strlcpy(pargp->ia_ifname, object, 976 sizeof (pargp->ia_ifname)); 977 (void) strlcpy(pargp->ia_module, ipadm_proto2str(proto), 978 sizeof (pargp->ia_module)); 979 break; 980 case IPADMPROP_CLASS_ADDR: 981 ipaddr = object; 982 (void) strlcpy(pargp->ia_ifname, ipaddr->ipadm_ifname, 983 sizeof (pargp->ia_ifname)); 984 (void) strlcpy(pargp->ia_aobjname, ipaddr->ipadm_aobjname, 985 sizeof (pargp->ia_aobjname)); 986 break; 987 } 988 } 989 990 /* 991 * Common function to retrieve property value for a given interface `ifname' or 992 * for a given protocol `proto'. The property name is in `pname'. 993 * 994 * `valtype' determines the type of value that will be retrieved. 995 * IPADM_OPT_ACTIVE - current value of the property (active config) 996 * IPADM_OPT_PERSIST - value of the property from persistent store 997 * IPADM_OPT_DEFAULT - default hard coded value (boot-time value) 998 * IPADM_OPT_PERM - read/write permissions for the value 999 * IPADM_OPT_POSSIBLE - range of values 1000 */ 1001 static ipadm_status_t 1002 i_ipadm_getprop_common(ipadm_handle_t iph, const char *ifname, 1003 const char *pname, char *buf, uint_t *bufsize, uint_t proto, 1004 uint_t valtype) 1005 { 1006 ipadm_status_t status = IPADM_SUCCESS; 1007 ipadm_prop_desc_t *pdp, *pdtbl; 1008 char priv_propname[MAXPROPNAMELEN]; 1009 boolean_t matched_name = B_FALSE; 1010 boolean_t is_if = (ifname != NULL); 1011 1012 pdtbl = i_ipadm_get_propdesc_table(proto); 1013 1014 /* 1015 * We already checked for supported protocol, 1016 * pdtbl better not be NULL. 1017 */ 1018 assert(pdtbl != NULL); 1019 1020 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) { 1021 if (strcmp(pname, pdp->ipd_name) == 0) { 1022 matched_name = B_TRUE; 1023 if (proto == pdp->ipd_proto) 1024 break; 1025 } 1026 } 1027 1028 if (pdp->ipd_name != NULL) { 1029 /* 1030 * check whether the property can be 1031 * applied on an interface 1032 */ 1033 if (is_if && !(pdp->ipd_class & IPADMPROP_CLASS_IF)) 1034 return (IPADM_INVALID_ARG); 1035 /* 1036 * check whether the property can be 1037 * applied on a module 1038 */ 1039 if (!is_if && !(pdp->ipd_class & IPADMPROP_CLASS_MODULE)) 1040 return (IPADM_INVALID_ARG); 1041 1042 } else { 1043 /* 1044 * if we matched name, but failed protocol check, 1045 * then return error 1046 */ 1047 if (matched_name) 1048 return (IPADM_INVALID_ARG); 1049 1050 /* there are no private interface properties */ 1051 if (is_if) 1052 return (IPADM_PROP_UNKNOWN); 1053 1054 /* private protocol properties, pass it to kernel directly */ 1055 pdp = &ipadm_privprop; 1056 (void) strlcpy(priv_propname, pname, sizeof (priv_propname)); 1057 pdp->ipd_name = priv_propname; 1058 } 1059 1060 switch (valtype) { 1061 case IPADM_OPT_PERM: 1062 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto, 1063 MOD_PROP_PERM); 1064 if (status == IPADM_SUCCESS) 1065 i_ipadm_perm2str(buf, bufsize); 1066 break; 1067 case IPADM_OPT_ACTIVE: 1068 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto, 1069 MOD_PROP_ACTIVE); 1070 break; 1071 case IPADM_OPT_DEFAULT: 1072 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto, 1073 MOD_PROP_DEFAULT); 1074 break; 1075 case IPADM_OPT_POSSIBLE: 1076 if (pdp->ipd_get_range != NULL) { 1077 status = pdp->ipd_get_range(iph, ifname, pdp, buf, 1078 bufsize, proto, MOD_PROP_POSSIBLE); 1079 break; 1080 } 1081 buf[0] = '\0'; 1082 break; 1083 case IPADM_OPT_PERSIST: 1084 /* retrieve from database */ 1085 if (is_if) 1086 status = i_ipadm_get_persist_propval(iph, pdp, buf, 1087 bufsize, ifname); 1088 else 1089 status = i_ipadm_get_persist_propval(iph, pdp, buf, 1090 bufsize, ipadm_proto2str(proto)); 1091 break; 1092 default: 1093 status = IPADM_INVALID_ARG; 1094 break; 1095 } 1096 return (status); 1097 } 1098 1099 /* 1100 * Get protocol property of the specified protocol. 1101 */ 1102 ipadm_status_t 1103 ipadm_get_prop(ipadm_handle_t iph, const char *pname, char *buf, 1104 uint_t *bufsize, uint_t proto, uint_t valtype) 1105 { 1106 /* 1107 * validate the arguments of the function. 1108 */ 1109 if (iph == NULL || pname == NULL || buf == NULL || 1110 bufsize == NULL || *bufsize == 0) { 1111 return (IPADM_INVALID_ARG); 1112 } 1113 /* 1114 * Do we support this proto, if not return error. 1115 */ 1116 if (ipadm_proto2str(proto) == NULL) 1117 return (IPADM_NOTSUP); 1118 1119 return (i_ipadm_getprop_common(iph, NULL, pname, buf, bufsize, 1120 proto, valtype)); 1121 } 1122 1123 /* 1124 * Get interface property of the specified interface. 1125 */ 1126 ipadm_status_t 1127 ipadm_get_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname, 1128 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype) 1129 { 1130 /* validate the arguments of the function. */ 1131 if (iph == NULL || pname == NULL || buf == NULL || 1132 bufsize == NULL || *bufsize == 0) { 1133 return (IPADM_INVALID_ARG); 1134 } 1135 1136 /* Do we support this proto, if not return error. */ 1137 if (ipadm_proto2str(proto) == NULL) 1138 return (IPADM_NOTSUP); 1139 1140 /* 1141 * check if interface name is provided for interface property and 1142 * is valid. 1143 */ 1144 if (!i_ipadm_validate_ifname(iph, ifname)) 1145 return (IPADM_INVALID_ARG); 1146 1147 return (i_ipadm_getprop_common(iph, ifname, pname, buf, bufsize, 1148 proto, valtype)); 1149 } 1150 1151 /* 1152 * Allocates sufficient ioctl buffers and copies property name and the 1153 * value, among other things. If the flag IPADM_OPT_DEFAULT is set, then 1154 * `pval' will be NULL and it instructs the kernel to reset the current 1155 * value to property's default value. 1156 */ 1157 static ipadm_status_t 1158 i_ipadm_set_prop(ipadm_handle_t iph, const void *arg, 1159 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 1160 { 1161 ipadm_status_t status = IPADM_SUCCESS; 1162 const char *ifname = arg; 1163 mod_ioc_prop_t *mip; 1164 char *pname = pdp->ipd_name; 1165 uint_t valsize, iocsize; 1166 uint_t iocflags = 0; 1167 1168 if (flags & IPADM_OPT_DEFAULT) { 1169 iocflags |= MOD_PROP_DEFAULT; 1170 } else if (flags & IPADM_OPT_ACTIVE) { 1171 iocflags |= MOD_PROP_ACTIVE; 1172 if (flags & IPADM_OPT_APPEND) 1173 iocflags |= MOD_PROP_APPEND; 1174 else if (flags & IPADM_OPT_REMOVE) 1175 iocflags |= MOD_PROP_REMOVE; 1176 } 1177 1178 if (pval != NULL) { 1179 valsize = strlen(pval); 1180 iocsize = sizeof (mod_ioc_prop_t) + valsize - 1; 1181 } else { 1182 valsize = 0; 1183 iocsize = sizeof (mod_ioc_prop_t); 1184 } 1185 1186 if ((mip = calloc(1, iocsize)) == NULL) 1187 return (IPADM_NO_BUFS); 1188 1189 mip->mpr_version = MOD_PROP_VERSION; 1190 mip->mpr_flags = iocflags; 1191 mip->mpr_proto = proto; 1192 if (ifname != NULL) { 1193 (void) strlcpy(mip->mpr_ifname, ifname, 1194 sizeof (mip->mpr_ifname)); 1195 } 1196 1197 (void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name)); 1198 mip->mpr_valsize = valsize; 1199 if (pval != NULL) 1200 bcopy(pval, mip->mpr_val, valsize); 1201 1202 if (i_ipadm_strioctl(iph->iph_sock, SIOCSETPROP, (char *)mip, 1203 iocsize) < 0) { 1204 if (errno == ENOENT) 1205 status = IPADM_PROP_UNKNOWN; 1206 else 1207 status = ipadm_errno2status(errno); 1208 } 1209 free(mip); 1210 return (status); 1211 } 1212 1213 /* 1214 * Common function for modifying both protocol/interface property. 1215 * 1216 * If: 1217 * IPADM_OPT_PERSIST is set then the value is persisted. 1218 * IPADM_OPT_DEFAULT is set then the default value for the property will 1219 * be applied. 1220 */ 1221 static ipadm_status_t 1222 i_ipadm_setprop_common(ipadm_handle_t iph, const char *ifname, 1223 const char *pname, const char *buf, uint_t proto, uint_t pflags) 1224 { 1225 ipadm_status_t status = IPADM_SUCCESS; 1226 boolean_t persist = (pflags & IPADM_OPT_PERSIST); 1227 boolean_t reset = (pflags & IPADM_OPT_DEFAULT); 1228 ipadm_prop_desc_t *pdp, *pdtbl; 1229 boolean_t is_if = (ifname != NULL); 1230 char priv_propname[MAXPROPNAMELEN]; 1231 boolean_t matched_name = B_FALSE; 1232 1233 /* Check that property value is within the allowed size */ 1234 if (!reset && strnlen(buf, MAXPROPVALLEN) >= MAXPROPVALLEN) 1235 return (IPADM_INVALID_ARG); 1236 1237 pdtbl = i_ipadm_get_propdesc_table(proto); 1238 /* 1239 * We already checked for supported protocol, 1240 * pdtbl better not be NULL. 1241 */ 1242 assert(pdtbl != NULL); 1243 1244 /* Walk through the property table to match the given property name */ 1245 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) { 1246 /* 1247 * we find the entry which matches <pname, proto> tuple 1248 */ 1249 if (strcmp(pname, pdp->ipd_name) == 0) { 1250 matched_name = B_TRUE; 1251 if (pdp->ipd_proto == proto) 1252 break; 1253 } 1254 } 1255 1256 if (pdp->ipd_name != NULL) { 1257 /* do some sanity checks */ 1258 if (is_if) { 1259 if (!(pdp->ipd_class & IPADMPROP_CLASS_IF)) 1260 return (IPADM_INVALID_ARG); 1261 } else { 1262 if (!(pdp->ipd_class & IPADMPROP_CLASS_MODULE)) 1263 return (IPADM_INVALID_ARG); 1264 } 1265 } else { 1266 /* 1267 * if we matched name, but failed protocol check, 1268 * then return error. 1269 */ 1270 if (matched_name) 1271 return (IPADM_BAD_PROTOCOL); 1272 1273 /* Possibly a private property, pass it to kernel directly */ 1274 1275 /* there are no private interface properties */ 1276 if (is_if) 1277 return (IPADM_PROP_UNKNOWN); 1278 1279 pdp = &ipadm_privprop; 1280 (void) strlcpy(priv_propname, pname, sizeof (priv_propname)); 1281 pdp->ipd_name = priv_propname; 1282 } 1283 1284 status = pdp->ipd_set(iph, ifname, pdp, buf, proto, pflags); 1285 if (status != IPADM_SUCCESS) 1286 return (status); 1287 1288 if (persist) { 1289 if (is_if) 1290 status = i_ipadm_persist_propval(iph, pdp, buf, ifname, 1291 pflags); 1292 else 1293 status = i_ipadm_persist_propval(iph, pdp, buf, 1294 ipadm_proto2str(proto), pflags); 1295 } 1296 return (status); 1297 } 1298 1299 /* 1300 * Sets the property value of the specified interface 1301 */ 1302 ipadm_status_t 1303 ipadm_set_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname, 1304 const char *buf, uint_t proto, uint_t pflags) 1305 { 1306 boolean_t reset = (pflags & IPADM_OPT_DEFAULT); 1307 ipadm_status_t status; 1308 1309 /* check for solaris.network.interface.config authorization */ 1310 if (!ipadm_check_auth()) 1311 return (IPADM_EAUTH); 1312 /* 1313 * validate the arguments of the function. 1314 */ 1315 if (iph == NULL || pname == NULL || (!reset && buf == NULL) || 1316 pflags == 0 || pflags == IPADM_OPT_PERSIST || 1317 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT))) { 1318 return (IPADM_INVALID_ARG); 1319 } 1320 1321 /* 1322 * Do we support this protocol, if not return error. 1323 */ 1324 if (ipadm_proto2str(proto) == NULL) 1325 return (IPADM_NOTSUP); 1326 1327 /* 1328 * Validate the interface and check if a persistent 1329 * operation is performed on a temporary object. 1330 */ 1331 status = i_ipadm_validate_if(iph, ifname, proto, pflags); 1332 if (status != IPADM_SUCCESS) 1333 return (status); 1334 1335 return (i_ipadm_setprop_common(iph, ifname, pname, buf, proto, 1336 pflags)); 1337 } 1338 1339 /* 1340 * Sets the property value of the specified protocol. 1341 */ 1342 ipadm_status_t 1343 ipadm_set_prop(ipadm_handle_t iph, const char *pname, const char *buf, 1344 uint_t proto, uint_t pflags) 1345 { 1346 boolean_t reset = (pflags & IPADM_OPT_DEFAULT); 1347 1348 /* check for solaris.network.interface.config authorization */ 1349 if (!ipadm_check_auth()) 1350 return (IPADM_EAUTH); 1351 /* 1352 * validate the arguments of the function. 1353 */ 1354 if (iph == NULL || pname == NULL ||(!reset && buf == NULL) || 1355 pflags == 0 || pflags == IPADM_OPT_PERSIST || 1356 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT| 1357 IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) { 1358 return (IPADM_INVALID_ARG); 1359 } 1360 1361 /* 1362 * Do we support this proto, if not return error. 1363 */ 1364 if (ipadm_proto2str(proto) == NULL) 1365 return (IPADM_NOTSUP); 1366 1367 return (i_ipadm_setprop_common(iph, NULL, pname, buf, proto, 1368 pflags)); 1369 } 1370 1371 /* helper function for ipadm_walk_proptbl */ 1372 static void 1373 i_ipadm_walk_proptbl(ipadm_prop_desc_t *pdtbl, uint_t proto, uint_t class, 1374 ipadm_prop_wfunc_t *func, void *arg) 1375 { 1376 ipadm_prop_desc_t *pdp; 1377 1378 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) { 1379 if (!(pdp->ipd_class & class)) 1380 continue; 1381 1382 if (proto != MOD_PROTO_NONE && !(pdp->ipd_proto & proto)) 1383 continue; 1384 1385 /* 1386 * we found a class specific match, call the 1387 * user callback function. 1388 */ 1389 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE) 1390 break; 1391 } 1392 } 1393 1394 /* 1395 * Walks through all the properties, for a given protocol and property class 1396 * (protocol or interface). 1397 * 1398 * Further if proto == MOD_PROTO_NONE, then it walks through all the supported 1399 * protocol property tables. 1400 */ 1401 ipadm_status_t 1402 ipadm_walk_proptbl(uint_t proto, uint_t class, ipadm_prop_wfunc_t *func, 1403 void *arg) 1404 { 1405 ipadm_prop_desc_t *pdtbl; 1406 ipadm_status_t status = IPADM_SUCCESS; 1407 int i; 1408 int count = A_CNT(protocols); 1409 1410 if (func == NULL) 1411 return (IPADM_INVALID_ARG); 1412 1413 switch (class) { 1414 case IPADMPROP_CLASS_ADDR: 1415 pdtbl = ipadm_addrprop_table; 1416 break; 1417 case IPADMPROP_CLASS_IF: 1418 case IPADMPROP_CLASS_MODULE: 1419 pdtbl = i_ipadm_get_propdesc_table(proto); 1420 if (pdtbl == NULL && proto != MOD_PROTO_NONE) 1421 return (IPADM_INVALID_ARG); 1422 break; 1423 default: 1424 return (IPADM_INVALID_ARG); 1425 } 1426 1427 if (pdtbl != NULL) { 1428 /* 1429 * proto will be MOD_PROTO_NONE in the case of 1430 * IPADMPROP_CLASS_ADDR. 1431 */ 1432 i_ipadm_walk_proptbl(pdtbl, proto, class, func, arg); 1433 } else { 1434 /* Walk thru all the protocol tables, we support */ 1435 for (i = 0; i < count; i++) { 1436 pdtbl = i_ipadm_get_propdesc_table(protocols[i]); 1437 i_ipadm_walk_proptbl(pdtbl, protocols[i], class, func, 1438 arg); 1439 } 1440 } 1441 return (status); 1442 } 1443 1444 /* 1445 * Given a property name, walks through all the instances of a property name. 1446 * Some properties have two instances one for v4 interfaces and another for v6 1447 * interfaces. For example: MTU. MTU can have different values for v4 and v6. 1448 * Therefore there are two properties for 'MTU'. 1449 * 1450 * This function invokes `func' for every instance of property `pname' 1451 */ 1452 ipadm_status_t 1453 ipadm_walk_prop(const char *pname, uint_t proto, uint_t class, 1454 ipadm_prop_wfunc_t *func, void *arg) 1455 { 1456 ipadm_prop_desc_t *pdtbl, *pdp; 1457 ipadm_status_t status = IPADM_SUCCESS; 1458 boolean_t matched = B_FALSE; 1459 1460 if (pname == NULL || func == NULL) 1461 return (IPADM_INVALID_ARG); 1462 1463 switch (class) { 1464 case IPADMPROP_CLASS_ADDR: 1465 pdtbl = ipadm_addrprop_table; 1466 break; 1467 case IPADMPROP_CLASS_IF: 1468 case IPADMPROP_CLASS_MODULE: 1469 pdtbl = i_ipadm_get_propdesc_table(proto); 1470 break; 1471 default: 1472 return (IPADM_INVALID_ARG); 1473 } 1474 1475 if (pdtbl == NULL) 1476 return (IPADM_INVALID_ARG); 1477 1478 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) { 1479 if (strcmp(pname, pdp->ipd_name) != 0) 1480 continue; 1481 if (!(pdp->ipd_proto & proto)) 1482 continue; 1483 matched = B_TRUE; 1484 /* we found a match, call the callback function */ 1485 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE) 1486 break; 1487 } 1488 if (!matched) 1489 status = IPADM_PROP_UNKNOWN; 1490 return (status); 1491 } 1492 1493 /* ARGSUSED */ 1494 ipadm_status_t 1495 i_ipadm_get_onoff(ipadm_handle_t iph, const void *arg, ipadm_prop_desc_t *dp, 1496 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype) 1497 { 1498 (void) snprintf(buf, *bufsize, "%s,%s", IPADM_ONSTR, IPADM_OFFSTR); 1499 return (IPADM_SUCCESS); 1500 } 1501 1502 /* 1503 * Makes a door call to ipmgmtd to retrieve the persisted property value 1504 */ 1505 ipadm_status_t 1506 i_ipadm_get_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp, 1507 char *gbuf, uint_t *gbufsize, const void *object) 1508 { 1509 ipmgmt_prop_arg_t parg; 1510 ipmgmt_getprop_rval_t rval, *rvalp; 1511 size_t nbytes; 1512 int err = 0; 1513 1514 bzero(&parg, sizeof (parg)); 1515 parg.ia_cmd = IPMGMT_CMD_GETPROP; 1516 i_ipadm_populate_proparg(&parg, pdp, NULL, object); 1517 1518 rvalp = &rval; 1519 err = ipadm_door_call(iph, &parg, sizeof (parg), (void **)&rvalp, 1520 sizeof (rval), B_FALSE); 1521 if (err == 0) { 1522 /* assert that rvalp was not reallocated */ 1523 assert(rvalp == &rval); 1524 1525 /* `ir_pval' contains the property value */ 1526 nbytes = snprintf(gbuf, *gbufsize, "%s", rvalp->ir_pval); 1527 if (nbytes >= *gbufsize) { 1528 /* insufficient buffer space */ 1529 *gbufsize = nbytes + 1; 1530 err = ENOBUFS; 1531 } 1532 } 1533 return (ipadm_errno2status(err)); 1534 } 1535 1536 /* 1537 * Persists the property value for a given property in the data store 1538 */ 1539 ipadm_status_t 1540 i_ipadm_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp, 1541 const char *pval, const void *object, uint_t flags) 1542 { 1543 ipmgmt_prop_arg_t parg; 1544 int err = 0; 1545 1546 bzero(&parg, sizeof (parg)); 1547 i_ipadm_populate_proparg(&parg, pdp, pval, object); 1548 1549 /* 1550 * Check if value to be persisted need to be appended or removed. This 1551 * is required for multi-valued property. 1552 */ 1553 if (flags & IPADM_OPT_APPEND) 1554 parg.ia_flags |= IPMGMT_APPEND; 1555 if (flags & IPADM_OPT_REMOVE) 1556 parg.ia_flags |= IPMGMT_REMOVE; 1557 1558 if (flags & (IPADM_OPT_DEFAULT|IPADM_OPT_REMOVE)) 1559 parg.ia_cmd = IPMGMT_CMD_RESETPROP; 1560 else 1561 parg.ia_cmd = IPMGMT_CMD_SETPROP; 1562 1563 err = ipadm_door_call(iph, &parg, sizeof (parg), NULL, 0, B_FALSE); 1564 1565 /* 1566 * its fine if there were no entry in the DB to delete. The user 1567 * might be changing property value, which was not changed 1568 * persistently. 1569 */ 1570 if (err == ENOENT) 1571 err = 0; 1572 return (ipadm_errno2status(err)); 1573 } 1574 1575 /* 1576 * Called during boot. 1577 * 1578 * Walk through the DB and apply all the global module properties. We plow 1579 * through the DB even if we fail to apply property. 1580 */ 1581 /* ARGSUSED */ 1582 boolean_t 1583 ipadm_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen, 1584 int *errp) 1585 { 1586 ipadm_handle_t iph = cbarg; 1587 nvpair_t *nvp, *pnvp; 1588 char *strval = NULL, *name, *mod = NULL; 1589 uint_t proto; 1590 1591 /* 1592 * We could have used nvl_exists() directly, however we need several 1593 * calls to it and each call traverses the list. Since this codepath 1594 * is exercised during boot, let's traverse the list ourselves and do 1595 * the necessary checks. 1596 */ 1597 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL; 1598 nvp = nvlist_next_nvpair(db_nvl, nvp)) { 1599 name = nvpair_name(nvp); 1600 if (IPADM_PRIV_NVP(name)) { 1601 if (strcmp(name, IPADM_NVP_IFNAME) == 0 || 1602 strcmp(name, IPADM_NVP_AOBJNAME) == 0) 1603 return (B_TRUE); 1604 else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 && 1605 nvpair_value_string(nvp, &mod) != 0) 1606 return (B_TRUE); 1607 } else { 1608 /* possible a property */ 1609 pnvp = nvp; 1610 } 1611 } 1612 1613 /* if we are here than we found a global property */ 1614 assert(mod != NULL); 1615 assert(nvpair_type(pnvp) == DATA_TYPE_STRING); 1616 1617 proto = ipadm_str2proto(mod); 1618 if (nvpair_value_string(pnvp, &strval) == 0) { 1619 (void) ipadm_set_prop(iph, name, strval, proto, 1620 IPADM_OPT_ACTIVE); 1621 } 1622 1623 return (B_TRUE); 1624 } 1625 1626 /* initialize global module properties */ 1627 ipadm_status_t 1628 ipadm_init_prop() 1629 { 1630 ipadm_handle_t iph = NULL; 1631 ipadm_status_t status; 1632 int err; 1633 1634 /* check for solaris.network.interface.config authorization */ 1635 if (!ipadm_check_auth()) 1636 return (IPADM_EAUTH); 1637 1638 if ((status = ipadm_open(&iph, IPH_INIT)) != IPADM_SUCCESS) 1639 return (status); 1640 1641 err = ipadm_rw_db(ipadm_db_init, iph, IPADM_DB_FILE, IPADM_FILE_MODE, 1642 IPADM_DB_READ); 1643 1644 ipadm_close(iph); 1645 return (ipadm_errno2status(err)); 1646 } 1647 1648 /* 1649 * This is called from ipadm_set_ifprop() to validate the set operation. 1650 * It does the following steps: 1651 * 1. Validates the interface name. 1652 * 2. Fails if it is an IPMP meta-interface or an underlying interface. 1653 * 3. In case of a persistent operation, verifies that the 1654 * interface is persistent. 1655 */ 1656 static ipadm_status_t 1657 i_ipadm_validate_if(ipadm_handle_t iph, const char *ifname, 1658 uint_t proto, uint_t flags) 1659 { 1660 sa_family_t af, other_af; 1661 ipadm_status_t status; 1662 boolean_t p_exists; 1663 boolean_t af_exists, other_af_exists, a_exists; 1664 1665 /* Check if the interface name is valid. */ 1666 if (!i_ipadm_validate_ifname(iph, ifname)) 1667 return (IPADM_INVALID_ARG); 1668 1669 af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET); 1670 /* 1671 * Setting properties on an IPMP meta-interface or underlying 1672 * interface is not supported. 1673 */ 1674 if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname)) 1675 return (IPADM_NOTSUP); 1676 1677 /* Check if interface exists in the persistent configuration. */ 1678 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists); 1679 if (status != IPADM_SUCCESS) 1680 return (status); 1681 1682 /* Check if interface exists in the active configuration. */ 1683 af_exists = ipadm_if_enabled(iph, ifname, af); 1684 other_af = (af == AF_INET ? AF_INET6 : AF_INET); 1685 other_af_exists = ipadm_if_enabled(iph, ifname, other_af); 1686 a_exists = (af_exists || other_af_exists); 1687 if (!a_exists && p_exists) 1688 return (IPADM_OP_DISABLE_OBJ); 1689 if (!af_exists) 1690 return (IPADM_ENXIO); 1691 1692 /* 1693 * If a persistent operation is requested, check if the underlying 1694 * IP interface is persistent. 1695 */ 1696 if ((flags & IPADM_OPT_PERSIST) && !p_exists) 1697 return (IPADM_TEMPORARY_OBJ); 1698 return (IPADM_SUCCESS); 1699 } 1700