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