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 char *port; 498 uint_t count = 0; 499 500 if (flags & IPADM_OPT_DEFAULT) { 501 assert(pval == NULL); 502 return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags)); 503 } 504 505 if ((err = ipadm_str2nvlist(pval, &portsnvl, IPADM_NORVAL)) != 0) 506 return (ipadm_errno2status(err)); 507 508 /* count the number of ports */ 509 for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL; 510 nvp = nvlist_next_nvpair(portsnvl, nvp)) { 511 ++count; 512 } 513 514 /* We allow only one port to be added or removed, at a time */ 515 if (count > 1 && (flags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) 516 return (IPADM_INVALID_ARG); 517 518 /* 519 * However on reboot, while initializing protocol properties, 520 * extra_priv_ports might have multiple values. Only in that case 521 * we allow setting multiple properties. 522 */ 523 if (count > 1 && !(iph->iph_flags & IPH_INIT)) 524 return (IPADM_INVALID_ARG); 525 526 count = 0; 527 for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL; 528 nvp = nvlist_next_nvpair(portsnvl, nvp)) { 529 port = nvpair_name(nvp); 530 if (count == 0) { 531 status = i_ipadm_set_prop(iph, arg, pdp, port, proto, 532 flags); 533 } else { 534 assert(iph->iph_flags & IPH_INIT); 535 status = i_ipadm_set_prop(iph, arg, pdp, port, proto, 536 IPADM_OPT_APPEND); 537 } 538 ++count; 539 if (status != IPADM_SUCCESS) 540 break; 541 } 542 ret: 543 nvlist_free(portsnvl); 544 return (status); 545 } 546 547 /* ARGSUSED */ 548 static ipadm_status_t 549 i_ipadm_set_forwarding(ipadm_handle_t iph, const void *arg, 550 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 551 { 552 const char *ifname = arg; 553 ipadm_status_t status; 554 555 /* 556 * if interface name is provided, then set forwarding using the 557 * IFF_ROUTER flag 558 */ 559 if (ifname != NULL) { 560 status = i_ipadm_set_ifprop_flags(iph, ifname, pdp, pval, 561 proto, flags); 562 } else { 563 char *val = NULL; 564 565 /* 566 * if the caller is IPH_LEGACY, `pval' already contains 567 * numeric values. 568 */ 569 if (!(flags & IPADM_OPT_DEFAULT) && 570 !(iph->iph_flags & IPH_LEGACY)) { 571 572 if (strcmp(pval, IPADM_ONSTR) == 0) 573 val = "1"; 574 else if (strcmp(pval, IPADM_OFFSTR) == 0) 575 val = "0"; 576 else 577 return (IPADM_INVALID_ARG); 578 pval = val; 579 } 580 581 status = i_ipadm_set_prop(iph, ifname, pdp, pval, proto, flags); 582 } 583 584 return (status); 585 } 586 587 /* ARGSUSED */ 588 static ipadm_status_t 589 i_ipadm_set_ecnsack(ipadm_handle_t iph, const void *arg, 590 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 591 { 592 uint_t i; 593 char val[MAXPROPVALLEN]; 594 595 /* if IPH_LEGACY is set, `pval' already contains numeric values */ 596 if (!(flags & IPADM_OPT_DEFAULT) && !(iph->iph_flags & IPH_LEGACY)) { 597 for (i = 0; ecn_sack_vals[i] != NULL; i++) { 598 if (strcmp(pval, ecn_sack_vals[i]) == 0) 599 break; 600 } 601 if (ecn_sack_vals[i] == NULL) 602 return (IPADM_INVALID_ARG); 603 (void) snprintf(val, MAXPROPVALLEN, "%d", i); 604 pval = val; 605 } 606 607 return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags)); 608 } 609 610 /* ARGSUSED */ 611 ipadm_status_t 612 i_ipadm_get_ecnsack(ipadm_handle_t iph, const void *arg, 613 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 614 uint_t valtype) 615 { 616 ipadm_status_t status = IPADM_SUCCESS; 617 uint_t i, nbytes = 0; 618 619 switch (valtype) { 620 case MOD_PROP_POSSIBLE: 621 for (i = 0; ecn_sack_vals[i] != NULL; i++) { 622 if (i == 0) 623 nbytes += snprintf(buf + nbytes, 624 *bufsize - nbytes, "%s", ecn_sack_vals[i]); 625 else 626 nbytes += snprintf(buf + nbytes, 627 *bufsize - nbytes, ",%s", ecn_sack_vals[i]); 628 if (nbytes >= *bufsize) 629 break; 630 } 631 break; 632 case MOD_PROP_PERM: 633 case MOD_PROP_DEFAULT: 634 case MOD_PROP_ACTIVE: 635 status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto, 636 valtype); 637 638 /* 639 * If IPH_LEGACY is set, do not convert the value returned 640 * from kernel, 641 */ 642 if (iph->iph_flags & IPH_LEGACY) 643 break; 644 645 /* 646 * For current and default value, convert the value returned 647 * from kernel to more discrete representation. 648 */ 649 if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE || 650 valtype == MOD_PROP_DEFAULT)) { 651 i = atoi(buf); 652 assert(i < 3); 653 nbytes = snprintf(buf, *bufsize, "%s", 654 ecn_sack_vals[i]); 655 } 656 break; 657 default: 658 return (IPADM_INVALID_ARG); 659 } 660 if (nbytes >= *bufsize) { 661 /* insufficient buffer space */ 662 *bufsize = nbytes + 1; 663 return (IPADM_NO_BUFS); 664 } 665 666 return (status); 667 } 668 669 /* ARGSUSED */ 670 static ipadm_status_t 671 i_ipadm_get_forwarding(ipadm_handle_t iph, const void *arg, 672 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 673 uint_t valtype) 674 { 675 const char *ifname = arg; 676 ipadm_status_t status = IPADM_SUCCESS; 677 678 /* 679 * if interface name is provided, then get forwarding status using 680 * SIOCGLIFFLAGS 681 */ 682 if (ifname != NULL) { 683 status = i_ipadm_get_ifprop_flags(iph, ifname, pdp, 684 buf, bufsize, pdp->ipd_proto, valtype); 685 } else { 686 status = i_ipadm_get_prop(iph, ifname, pdp, buf, 687 bufsize, proto, valtype); 688 /* 689 * If IPH_LEGACY is set, do not convert the value returned 690 * from kernel, 691 */ 692 if (iph->iph_flags & IPH_LEGACY) 693 goto ret; 694 if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE || 695 valtype == MOD_PROP_DEFAULT)) { 696 uint_t val = atoi(buf); 697 698 (void) snprintf(buf, *bufsize, 699 (val == 1 ? IPADM_ONSTR : IPADM_OFFSTR)); 700 } 701 } 702 703 ret: 704 return (status); 705 } 706 707 /* ARGSUSED */ 708 static ipadm_status_t 709 i_ipadm_get_mtu(ipadm_handle_t iph, const void *arg, 710 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 711 uint_t valtype) 712 { 713 struct lifreq lifr; 714 const char *ifname = arg; 715 size_t nbytes; 716 int s; 717 718 switch (valtype) { 719 case MOD_PROP_PERM: 720 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW); 721 break; 722 case MOD_PROP_DEFAULT: 723 case MOD_PROP_POSSIBLE: 724 return (i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, 725 proto, valtype)); 726 case MOD_PROP_ACTIVE: 727 bzero(&lifr, sizeof (lifr)); 728 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 729 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock); 730 731 if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) < 0) 732 return (ipadm_errno2status(errno)); 733 nbytes = snprintf(buf, *bufsize, "%u", lifr.lifr_mtu); 734 break; 735 default: 736 return (IPADM_INVALID_ARG); 737 } 738 if (nbytes >= *bufsize) { 739 /* insufficient buffer space */ 740 *bufsize = nbytes + 1; 741 return (IPADM_NO_BUFS); 742 } 743 return (IPADM_SUCCESS); 744 } 745 746 /* ARGSUSED */ 747 static ipadm_status_t 748 i_ipadm_get_metric(ipadm_handle_t iph, const void *arg, 749 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 750 uint_t valtype) 751 { 752 struct lifreq lifr; 753 const char *ifname = arg; 754 size_t nbytes; 755 int s, val; 756 757 switch (valtype) { 758 case MOD_PROP_PERM: 759 val = MOD_PROP_PERM_RW; 760 break; 761 case MOD_PROP_DEFAULT: 762 val = DEF_METRIC_VAL; 763 break; 764 case MOD_PROP_ACTIVE: 765 bzero(&lifr, sizeof (lifr)); 766 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 767 768 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock); 769 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) 770 return (ipadm_errno2status(errno)); 771 val = lifr.lifr_metric; 772 break; 773 default: 774 return (IPADM_INVALID_ARG); 775 } 776 nbytes = snprintf(buf, *bufsize, "%d", val); 777 if (nbytes >= *bufsize) { 778 /* insufficient buffer space */ 779 *bufsize = nbytes + 1; 780 return (IPADM_NO_BUFS); 781 } 782 783 return (IPADM_SUCCESS); 784 } 785 786 /* ARGSUSED */ 787 static ipadm_status_t 788 i_ipadm_get_usesrc(ipadm_handle_t iph, const void *arg, 789 ipadm_prop_desc_t *ipd, char *buf, uint_t *bufsize, uint_t proto, 790 uint_t valtype) 791 { 792 struct lifreq lifr; 793 const char *ifname = arg; 794 int s; 795 char if_name[IF_NAMESIZE]; 796 size_t nbytes; 797 798 switch (valtype) { 799 case MOD_PROP_PERM: 800 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW); 801 break; 802 case MOD_PROP_DEFAULT: 803 nbytes = snprintf(buf, *bufsize, "%s", IPADM_NONESTR); 804 break; 805 case MOD_PROP_ACTIVE: 806 bzero(&lifr, sizeof (lifr)); 807 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 808 809 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock); 810 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0) 811 return (ipadm_errno2status(errno)); 812 if (lifr.lifr_index == 0) { 813 /* no src address was set, so print 'none' */ 814 (void) strlcpy(if_name, IPADM_NONESTR, 815 sizeof (if_name)); 816 } else if (if_indextoname(lifr.lifr_index, if_name) == NULL) { 817 return (ipadm_errno2status(errno)); 818 } 819 nbytes = snprintf(buf, *bufsize, "%s", if_name); 820 break; 821 default: 822 return (IPADM_INVALID_ARG); 823 } 824 if (nbytes >= *bufsize) { 825 /* insufficient buffer space */ 826 *bufsize = nbytes + 1; 827 return (IPADM_NO_BUFS); 828 } 829 return (IPADM_SUCCESS); 830 } 831 832 /* ARGSUSED */ 833 static ipadm_status_t 834 i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg, 835 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 836 uint_t valtype) 837 { 838 uint64_t intf_flags; 839 char *val; 840 size_t nbytes; 841 const char *ifname = arg; 842 sa_family_t af; 843 ipadm_status_t status = IPADM_SUCCESS; 844 845 switch (valtype) { 846 case MOD_PROP_PERM: 847 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW); 848 break; 849 case MOD_PROP_DEFAULT: 850 if (strcmp(pdp->ipd_name, "exchange_routes") == 0 || 851 strcmp(pdp->ipd_name, "arp") == 0 || 852 strcmp(pdp->ipd_name, "nud") == 0) { 853 val = IPADM_ONSTR; 854 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) { 855 val = IPADM_OFFSTR; 856 } else { 857 return (IPADM_PROP_UNKNOWN); 858 } 859 nbytes = snprintf(buf, *bufsize, "%s", val); 860 break; 861 case MOD_PROP_ACTIVE: 862 af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET); 863 status = i_ipadm_get_flags(iph, ifname, af, &intf_flags); 864 if (status != IPADM_SUCCESS) 865 return (status); 866 867 val = IPADM_OFFSTR; 868 if (strcmp(pdp->ipd_name, "exchange_routes") == 0) { 869 if (!(intf_flags & IFF_NORTEXCH)) 870 val = IPADM_ONSTR; 871 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) { 872 if (intf_flags & IFF_ROUTER) 873 val = IPADM_ONSTR; 874 } else if (strcmp(pdp->ipd_name, "arp") == 0) { 875 if (!(intf_flags & IFF_NOARP)) 876 val = IPADM_ONSTR; 877 } else if (strcmp(pdp->ipd_name, "nud") == 0) { 878 if (!(intf_flags & IFF_NONUD)) 879 val = IPADM_ONSTR; 880 } 881 nbytes = snprintf(buf, *bufsize, "%s", val); 882 break; 883 default: 884 return (IPADM_INVALID_ARG); 885 } 886 if (nbytes >= *bufsize) { 887 /* insufficient buffer space */ 888 *bufsize = nbytes + 1; 889 status = IPADM_NO_BUFS; 890 } 891 892 return (status); 893 } 894 895 static void 896 i_ipadm_perm2str(char *buf, uint_t *bufsize) 897 { 898 uint_t perm = atoi(buf); 899 900 (void) snprintf(buf, *bufsize, "%c%c", 901 ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-', 902 ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-'); 903 } 904 905 /* ARGSUSED */ 906 static ipadm_status_t 907 i_ipadm_get_prop(ipadm_handle_t iph, const void *arg, 908 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto, 909 uint_t valtype) 910 { 911 ipadm_status_t status = IPADM_SUCCESS; 912 const char *ifname = arg; 913 mod_ioc_prop_t *mip; 914 char *pname = pdp->ipd_name; 915 uint_t iocsize; 916 917 /* allocate sufficient ioctl buffer to retrieve value */ 918 iocsize = sizeof (mod_ioc_prop_t) + *bufsize - 1; 919 if ((mip = calloc(1, iocsize)) == NULL) 920 return (IPADM_NO_BUFS); 921 922 mip->mpr_version = MOD_PROP_VERSION; 923 mip->mpr_flags = valtype; 924 mip->mpr_proto = proto; 925 if (ifname != NULL) { 926 (void) strlcpy(mip->mpr_ifname, ifname, 927 sizeof (mip->mpr_ifname)); 928 } 929 (void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name)); 930 mip->mpr_valsize = *bufsize; 931 932 if (i_ipadm_strioctl(iph->iph_sock, SIOCGETPROP, (char *)mip, 933 iocsize) < 0) { 934 if (errno == ENOENT) 935 status = IPADM_PROP_UNKNOWN; 936 else 937 status = ipadm_errno2status(errno); 938 } else { 939 bcopy(mip->mpr_val, buf, *bufsize); 940 } 941 942 free(mip); 943 return (status); 944 } 945 946 /* 947 * populates the ipmgmt_prop_arg_t based on the class of property. 948 */ 949 static void 950 i_ipadm_populate_proparg(ipmgmt_prop_arg_t *pargp, ipadm_prop_desc_t *pdp, 951 const char *pval, const void *object) 952 { 953 const struct ipadm_addrobj_s *ipaddr; 954 uint_t class = pdp->ipd_class; 955 uint_t proto = pdp->ipd_proto; 956 957 (void) strlcpy(pargp->ia_pname, pdp->ipd_name, 958 sizeof (pargp->ia_pname)); 959 if (pval != NULL) 960 (void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval)); 961 962 switch (class) { 963 case IPADMPROP_CLASS_MODULE: 964 (void) strlcpy(pargp->ia_module, object, 965 sizeof (pargp->ia_module)); 966 break; 967 case IPADMPROP_CLASS_MODIF: 968 /* check if object is protostr or an ifname */ 969 if (ipadm_str2proto(object) != MOD_PROTO_NONE) { 970 (void) strlcpy(pargp->ia_module, object, 971 sizeof (pargp->ia_module)); 972 break; 973 } 974 /* it's an interface property, fall through */ 975 /* FALLTHRU */ 976 case IPADMPROP_CLASS_IF: 977 (void) strlcpy(pargp->ia_ifname, object, 978 sizeof (pargp->ia_ifname)); 979 (void) strlcpy(pargp->ia_module, ipadm_proto2str(proto), 980 sizeof (pargp->ia_module)); 981 break; 982 case IPADMPROP_CLASS_ADDR: 983 ipaddr = object; 984 (void) strlcpy(pargp->ia_ifname, ipaddr->ipadm_ifname, 985 sizeof (pargp->ia_ifname)); 986 (void) strlcpy(pargp->ia_aobjname, ipaddr->ipadm_aobjname, 987 sizeof (pargp->ia_aobjname)); 988 break; 989 } 990 } 991 992 /* 993 * Common function to retrieve property value for a given interface `ifname' or 994 * for a given protocol `proto'. The property name is in `pname'. 995 * 996 * `valtype' determines the type of value that will be retrieved. 997 * IPADM_OPT_ACTIVE - current value of the property (active config) 998 * IPADM_OPT_PERSIST - value of the property from persistent store 999 * IPADM_OPT_DEFAULT - default hard coded value (boot-time value) 1000 * IPADM_OPT_PERM - read/write permissions for the value 1001 * IPADM_OPT_POSSIBLE - range of values 1002 */ 1003 static ipadm_status_t 1004 i_ipadm_getprop_common(ipadm_handle_t iph, const char *ifname, 1005 const char *pname, char *buf, uint_t *bufsize, uint_t proto, 1006 uint_t valtype) 1007 { 1008 ipadm_status_t status = IPADM_SUCCESS; 1009 ipadm_prop_desc_t *pdp, *pdtbl; 1010 char priv_propname[MAXPROPNAMELEN]; 1011 boolean_t matched_name = B_FALSE; 1012 boolean_t is_if = (ifname != NULL); 1013 1014 pdtbl = i_ipadm_get_propdesc_table(proto); 1015 1016 /* 1017 * We already checked for supported protocol, 1018 * pdtbl better not be NULL. 1019 */ 1020 assert(pdtbl != NULL); 1021 1022 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) { 1023 if (strcmp(pname, pdp->ipd_name) == 0) { 1024 matched_name = B_TRUE; 1025 if (proto == pdp->ipd_proto) 1026 break; 1027 } 1028 } 1029 1030 if (pdp->ipd_name != NULL) { 1031 /* 1032 * check whether the property can be 1033 * applied on an interface 1034 */ 1035 if (is_if && !(pdp->ipd_class & IPADMPROP_CLASS_IF)) 1036 return (IPADM_INVALID_ARG); 1037 /* 1038 * check whether the property can be 1039 * applied on a module 1040 */ 1041 if (!is_if && !(pdp->ipd_class & IPADMPROP_CLASS_MODULE)) 1042 return (IPADM_INVALID_ARG); 1043 1044 } else { 1045 /* 1046 * if we matched name, but failed protocol check, 1047 * then return error 1048 */ 1049 if (matched_name) 1050 return (IPADM_INVALID_ARG); 1051 1052 /* there are no private interface properties */ 1053 if (is_if) 1054 return (IPADM_PROP_UNKNOWN); 1055 1056 /* private protocol properties, pass it to kernel directly */ 1057 pdp = &ipadm_privprop; 1058 (void) strlcpy(priv_propname, pname, sizeof (priv_propname)); 1059 pdp->ipd_name = priv_propname; 1060 } 1061 1062 switch (valtype) { 1063 case IPADM_OPT_PERM: 1064 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto, 1065 MOD_PROP_PERM); 1066 if (status == IPADM_SUCCESS) 1067 i_ipadm_perm2str(buf, bufsize); 1068 break; 1069 case IPADM_OPT_ACTIVE: 1070 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto, 1071 MOD_PROP_ACTIVE); 1072 break; 1073 case IPADM_OPT_DEFAULT: 1074 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto, 1075 MOD_PROP_DEFAULT); 1076 break; 1077 case IPADM_OPT_POSSIBLE: 1078 if (pdp->ipd_get_range != NULL) { 1079 status = pdp->ipd_get_range(iph, ifname, pdp, buf, 1080 bufsize, proto, MOD_PROP_POSSIBLE); 1081 break; 1082 } 1083 buf[0] = '\0'; 1084 break; 1085 case IPADM_OPT_PERSIST: 1086 /* retrieve from database */ 1087 if (is_if) 1088 status = i_ipadm_get_persist_propval(iph, pdp, buf, 1089 bufsize, ifname); 1090 else 1091 status = i_ipadm_get_persist_propval(iph, pdp, buf, 1092 bufsize, ipadm_proto2str(proto)); 1093 break; 1094 default: 1095 status = IPADM_INVALID_ARG; 1096 break; 1097 } 1098 return (status); 1099 } 1100 1101 /* 1102 * Get protocol property of the specified protocol. 1103 */ 1104 ipadm_status_t 1105 ipadm_get_prop(ipadm_handle_t iph, const char *pname, char *buf, 1106 uint_t *bufsize, uint_t proto, uint_t valtype) 1107 { 1108 /* 1109 * validate the arguments of the function. 1110 */ 1111 if (iph == NULL || pname == NULL || buf == NULL || 1112 bufsize == NULL || *bufsize == 0) { 1113 return (IPADM_INVALID_ARG); 1114 } 1115 /* 1116 * Do we support this proto, if not return error. 1117 */ 1118 if (ipadm_proto2str(proto) == NULL) 1119 return (IPADM_NOTSUP); 1120 1121 return (i_ipadm_getprop_common(iph, NULL, pname, buf, bufsize, 1122 proto, valtype)); 1123 } 1124 1125 /* 1126 * Get interface property of the specified interface. 1127 */ 1128 ipadm_status_t 1129 ipadm_get_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname, 1130 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype) 1131 { 1132 /* validate the arguments of the function. */ 1133 if (iph == NULL || pname == NULL || buf == NULL || 1134 bufsize == NULL || *bufsize == 0) { 1135 return (IPADM_INVALID_ARG); 1136 } 1137 1138 /* Do we support this proto, if not return error. */ 1139 if (ipadm_proto2str(proto) == NULL) 1140 return (IPADM_NOTSUP); 1141 1142 /* 1143 * check if interface name is provided for interface property and 1144 * is valid. 1145 */ 1146 if (!i_ipadm_validate_ifname(iph, ifname)) 1147 return (IPADM_INVALID_ARG); 1148 1149 return (i_ipadm_getprop_common(iph, ifname, pname, buf, bufsize, 1150 proto, valtype)); 1151 } 1152 1153 /* 1154 * Allocates sufficient ioctl buffers and copies property name and the 1155 * value, among other things. If the flag IPADM_OPT_DEFAULT is set, then 1156 * `pval' will be NULL and it instructs the kernel to reset the current 1157 * value to property's default value. 1158 */ 1159 static ipadm_status_t 1160 i_ipadm_set_prop(ipadm_handle_t iph, const void *arg, 1161 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags) 1162 { 1163 ipadm_status_t status = IPADM_SUCCESS; 1164 const char *ifname = arg; 1165 mod_ioc_prop_t *mip; 1166 char *pname = pdp->ipd_name; 1167 uint_t valsize, iocsize; 1168 uint_t iocflags = 0; 1169 1170 if (flags & IPADM_OPT_DEFAULT) { 1171 iocflags |= MOD_PROP_DEFAULT; 1172 } else if (flags & IPADM_OPT_ACTIVE) { 1173 iocflags |= MOD_PROP_ACTIVE; 1174 if (flags & IPADM_OPT_APPEND) 1175 iocflags |= MOD_PROP_APPEND; 1176 else if (flags & IPADM_OPT_REMOVE) 1177 iocflags |= MOD_PROP_REMOVE; 1178 } 1179 1180 if (pval != NULL) { 1181 valsize = strlen(pval); 1182 iocsize = sizeof (mod_ioc_prop_t) + valsize - 1; 1183 } else { 1184 valsize = 0; 1185 iocsize = sizeof (mod_ioc_prop_t); 1186 } 1187 1188 if ((mip = calloc(1, iocsize)) == NULL) 1189 return (IPADM_NO_BUFS); 1190 1191 mip->mpr_version = MOD_PROP_VERSION; 1192 mip->mpr_flags = iocflags; 1193 mip->mpr_proto = proto; 1194 if (ifname != NULL) { 1195 (void) strlcpy(mip->mpr_ifname, ifname, 1196 sizeof (mip->mpr_ifname)); 1197 } 1198 1199 (void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name)); 1200 mip->mpr_valsize = valsize; 1201 if (pval != NULL) 1202 bcopy(pval, mip->mpr_val, valsize); 1203 1204 if (i_ipadm_strioctl(iph->iph_sock, SIOCSETPROP, (char *)mip, 1205 iocsize) < 0) { 1206 if (errno == ENOENT) 1207 status = IPADM_PROP_UNKNOWN; 1208 else 1209 status = ipadm_errno2status(errno); 1210 } 1211 free(mip); 1212 return (status); 1213 } 1214 1215 /* 1216 * Common function for modifying both protocol/interface property. 1217 * 1218 * If: 1219 * IPADM_OPT_PERSIST is set then the value is persisted. 1220 * IPADM_OPT_DEFAULT is set then the default value for the property will 1221 * be applied. 1222 */ 1223 static ipadm_status_t 1224 i_ipadm_setprop_common(ipadm_handle_t iph, const char *ifname, 1225 const char *pname, const char *buf, uint_t proto, uint_t pflags) 1226 { 1227 ipadm_status_t status = IPADM_SUCCESS; 1228 boolean_t persist = (pflags & IPADM_OPT_PERSIST); 1229 boolean_t reset = (pflags & IPADM_OPT_DEFAULT); 1230 ipadm_prop_desc_t *pdp, *pdtbl; 1231 boolean_t is_if = (ifname != NULL); 1232 char priv_propname[MAXPROPNAMELEN]; 1233 boolean_t matched_name = B_FALSE; 1234 1235 /* Check that property value is within the allowed size */ 1236 if (!reset && strnlen(buf, MAXPROPVALLEN) >= MAXPROPVALLEN) 1237 return (IPADM_INVALID_ARG); 1238 1239 pdtbl = i_ipadm_get_propdesc_table(proto); 1240 /* 1241 * We already checked for supported protocol, 1242 * pdtbl better not be NULL. 1243 */ 1244 assert(pdtbl != NULL); 1245 1246 /* Walk through the property table to match the given property name */ 1247 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) { 1248 /* 1249 * we find the entry which matches <pname, proto> tuple 1250 */ 1251 if (strcmp(pname, pdp->ipd_name) == 0) { 1252 matched_name = B_TRUE; 1253 if (pdp->ipd_proto == proto) 1254 break; 1255 } 1256 } 1257 1258 if (pdp->ipd_name != NULL) { 1259 /* do some sanity checks */ 1260 if (is_if) { 1261 if (!(pdp->ipd_class & IPADMPROP_CLASS_IF)) 1262 return (IPADM_INVALID_ARG); 1263 } else { 1264 if (!(pdp->ipd_class & IPADMPROP_CLASS_MODULE)) 1265 return (IPADM_INVALID_ARG); 1266 } 1267 /* 1268 * if the property is not multi-valued and IPADM_OPT_APPEND or 1269 * IPADM_OPT_REMOVE is specified, return IPADM_INVALID_ARG. 1270 */ 1271 if (!(pdp->ipd_flags & IPADMPROP_MULVAL) && (pflags & 1272 (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) { 1273 return (IPADM_INVALID_ARG); 1274 } 1275 } else { 1276 /* 1277 * if we matched name, but failed protocol check, 1278 * then return error. 1279 */ 1280 if (matched_name) 1281 return (IPADM_BAD_PROTOCOL); 1282 1283 /* Possibly a private property, pass it to kernel directly */ 1284 1285 /* there are no private interface properties */ 1286 if (is_if) 1287 return (IPADM_PROP_UNKNOWN); 1288 1289 pdp = &ipadm_privprop; 1290 (void) strlcpy(priv_propname, pname, sizeof (priv_propname)); 1291 pdp->ipd_name = priv_propname; 1292 } 1293 1294 status = pdp->ipd_set(iph, ifname, pdp, buf, proto, pflags); 1295 if (status != IPADM_SUCCESS) 1296 return (status); 1297 1298 if (persist) { 1299 if (is_if) 1300 status = i_ipadm_persist_propval(iph, pdp, buf, ifname, 1301 pflags); 1302 else 1303 status = i_ipadm_persist_propval(iph, pdp, buf, 1304 ipadm_proto2str(proto), pflags); 1305 } 1306 return (status); 1307 } 1308 1309 /* 1310 * Sets the property value of the specified interface 1311 */ 1312 ipadm_status_t 1313 ipadm_set_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname, 1314 const char *buf, uint_t proto, uint_t pflags) 1315 { 1316 boolean_t reset = (pflags & IPADM_OPT_DEFAULT); 1317 ipadm_status_t status; 1318 1319 /* check for solaris.network.interface.config authorization */ 1320 if (!ipadm_check_auth()) 1321 return (IPADM_EAUTH); 1322 /* 1323 * validate the arguments of the function. 1324 */ 1325 if (iph == NULL || pname == NULL || (!reset && buf == NULL) || 1326 pflags == 0 || pflags == IPADM_OPT_PERSIST || 1327 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT))) { 1328 return (IPADM_INVALID_ARG); 1329 } 1330 1331 /* 1332 * Do we support this protocol, if not return error. 1333 */ 1334 if (ipadm_proto2str(proto) == NULL) 1335 return (IPADM_NOTSUP); 1336 1337 /* 1338 * Validate the interface and check if a persistent 1339 * operation is performed on a temporary object. 1340 */ 1341 status = i_ipadm_validate_if(iph, ifname, proto, pflags); 1342 if (status != IPADM_SUCCESS) 1343 return (status); 1344 1345 return (i_ipadm_setprop_common(iph, ifname, pname, buf, proto, 1346 pflags)); 1347 } 1348 1349 /* 1350 * Sets the property value of the specified protocol. 1351 */ 1352 ipadm_status_t 1353 ipadm_set_prop(ipadm_handle_t iph, const char *pname, const char *buf, 1354 uint_t proto, uint_t pflags) 1355 { 1356 boolean_t reset = (pflags & IPADM_OPT_DEFAULT); 1357 1358 /* check for solaris.network.interface.config authorization */ 1359 if (!ipadm_check_auth()) 1360 return (IPADM_EAUTH); 1361 /* 1362 * validate the arguments of the function. 1363 */ 1364 if (iph == NULL || pname == NULL ||(!reset && buf == NULL) || 1365 pflags == 0 || pflags == IPADM_OPT_PERSIST || 1366 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT| 1367 IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) { 1368 return (IPADM_INVALID_ARG); 1369 } 1370 1371 /* 1372 * Do we support this proto, if not return error. 1373 */ 1374 if (ipadm_proto2str(proto) == NULL) 1375 return (IPADM_NOTSUP); 1376 1377 return (i_ipadm_setprop_common(iph, NULL, pname, buf, proto, 1378 pflags)); 1379 } 1380 1381 /* helper function for ipadm_walk_proptbl */ 1382 static void 1383 i_ipadm_walk_proptbl(ipadm_prop_desc_t *pdtbl, uint_t proto, uint_t class, 1384 ipadm_prop_wfunc_t *func, void *arg) 1385 { 1386 ipadm_prop_desc_t *pdp; 1387 1388 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) { 1389 if (!(pdp->ipd_class & class)) 1390 continue; 1391 1392 if (proto != MOD_PROTO_NONE && !(pdp->ipd_proto & proto)) 1393 continue; 1394 1395 /* 1396 * we found a class specific match, call the 1397 * user callback function. 1398 */ 1399 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE) 1400 break; 1401 } 1402 } 1403 1404 /* 1405 * Walks through all the properties, for a given protocol and property class 1406 * (protocol or interface). 1407 * 1408 * Further if proto == MOD_PROTO_NONE, then it walks through all the supported 1409 * protocol property tables. 1410 */ 1411 ipadm_status_t 1412 ipadm_walk_proptbl(uint_t proto, uint_t class, ipadm_prop_wfunc_t *func, 1413 void *arg) 1414 { 1415 ipadm_prop_desc_t *pdtbl; 1416 ipadm_status_t status = IPADM_SUCCESS; 1417 int i; 1418 int count = A_CNT(protocols); 1419 1420 if (func == NULL) 1421 return (IPADM_INVALID_ARG); 1422 1423 switch (class) { 1424 case IPADMPROP_CLASS_ADDR: 1425 pdtbl = ipadm_addrprop_table; 1426 break; 1427 case IPADMPROP_CLASS_IF: 1428 case IPADMPROP_CLASS_MODULE: 1429 pdtbl = i_ipadm_get_propdesc_table(proto); 1430 if (pdtbl == NULL && proto != MOD_PROTO_NONE) 1431 return (IPADM_INVALID_ARG); 1432 break; 1433 default: 1434 return (IPADM_INVALID_ARG); 1435 } 1436 1437 if (pdtbl != NULL) { 1438 /* 1439 * proto will be MOD_PROTO_NONE in the case of 1440 * IPADMPROP_CLASS_ADDR. 1441 */ 1442 i_ipadm_walk_proptbl(pdtbl, proto, class, func, arg); 1443 } else { 1444 /* Walk thru all the protocol tables, we support */ 1445 for (i = 0; i < count; i++) { 1446 pdtbl = i_ipadm_get_propdesc_table(protocols[i]); 1447 i_ipadm_walk_proptbl(pdtbl, protocols[i], class, func, 1448 arg); 1449 } 1450 } 1451 return (status); 1452 } 1453 1454 /* 1455 * Given a property name, walks through all the instances of a property name. 1456 * Some properties have two instances one for v4 interfaces and another for v6 1457 * interfaces. For example: MTU. MTU can have different values for v4 and v6. 1458 * Therefore there are two properties for 'MTU'. 1459 * 1460 * This function invokes `func' for every instance of property `pname' 1461 */ 1462 ipadm_status_t 1463 ipadm_walk_prop(const char *pname, uint_t proto, uint_t class, 1464 ipadm_prop_wfunc_t *func, void *arg) 1465 { 1466 ipadm_prop_desc_t *pdtbl, *pdp; 1467 ipadm_status_t status = IPADM_SUCCESS; 1468 boolean_t matched = B_FALSE; 1469 1470 if (pname == NULL || func == NULL) 1471 return (IPADM_INVALID_ARG); 1472 1473 switch (class) { 1474 case IPADMPROP_CLASS_ADDR: 1475 pdtbl = ipadm_addrprop_table; 1476 break; 1477 case IPADMPROP_CLASS_IF: 1478 case IPADMPROP_CLASS_MODULE: 1479 pdtbl = i_ipadm_get_propdesc_table(proto); 1480 break; 1481 default: 1482 return (IPADM_INVALID_ARG); 1483 } 1484 1485 if (pdtbl == NULL) 1486 return (IPADM_INVALID_ARG); 1487 1488 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) { 1489 if (strcmp(pname, pdp->ipd_name) != 0) 1490 continue; 1491 if (!(pdp->ipd_proto & proto)) 1492 continue; 1493 matched = B_TRUE; 1494 /* we found a match, call the callback function */ 1495 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE) 1496 break; 1497 } 1498 if (!matched) 1499 status = IPADM_PROP_UNKNOWN; 1500 return (status); 1501 } 1502 1503 /* ARGSUSED */ 1504 ipadm_status_t 1505 i_ipadm_get_onoff(ipadm_handle_t iph, const void *arg, ipadm_prop_desc_t *dp, 1506 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype) 1507 { 1508 (void) snprintf(buf, *bufsize, "%s,%s", IPADM_ONSTR, IPADM_OFFSTR); 1509 return (IPADM_SUCCESS); 1510 } 1511 1512 /* 1513 * Makes a door call to ipmgmtd to retrieve the persisted property value 1514 */ 1515 ipadm_status_t 1516 i_ipadm_get_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp, 1517 char *gbuf, uint_t *gbufsize, const void *object) 1518 { 1519 ipmgmt_prop_arg_t parg; 1520 ipmgmt_getprop_rval_t rval, *rvalp; 1521 size_t nbytes; 1522 int err = 0; 1523 1524 bzero(&parg, sizeof (parg)); 1525 parg.ia_cmd = IPMGMT_CMD_GETPROP; 1526 i_ipadm_populate_proparg(&parg, pdp, NULL, object); 1527 1528 rvalp = &rval; 1529 err = ipadm_door_call(iph, &parg, sizeof (parg), (void **)&rvalp, 1530 sizeof (rval), B_FALSE); 1531 if (err == 0) { 1532 /* assert that rvalp was not reallocated */ 1533 assert(rvalp == &rval); 1534 1535 /* `ir_pval' contains the property value */ 1536 nbytes = snprintf(gbuf, *gbufsize, "%s", rvalp->ir_pval); 1537 if (nbytes >= *gbufsize) { 1538 /* insufficient buffer space */ 1539 *gbufsize = nbytes + 1; 1540 err = ENOBUFS; 1541 } 1542 } 1543 return (ipadm_errno2status(err)); 1544 } 1545 1546 /* 1547 * Persists the property value for a given property in the data store 1548 */ 1549 ipadm_status_t 1550 i_ipadm_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp, 1551 const char *pval, const void *object, uint_t flags) 1552 { 1553 ipmgmt_prop_arg_t parg; 1554 int err = 0; 1555 1556 bzero(&parg, sizeof (parg)); 1557 i_ipadm_populate_proparg(&parg, pdp, pval, object); 1558 1559 /* 1560 * Check if value to be persisted need to be appended or removed. This 1561 * is required for multi-valued property. 1562 */ 1563 if (flags & IPADM_OPT_APPEND) 1564 parg.ia_flags |= IPMGMT_APPEND; 1565 if (flags & IPADM_OPT_REMOVE) 1566 parg.ia_flags |= IPMGMT_REMOVE; 1567 1568 if (flags & (IPADM_OPT_DEFAULT|IPADM_OPT_REMOVE)) 1569 parg.ia_cmd = IPMGMT_CMD_RESETPROP; 1570 else 1571 parg.ia_cmd = IPMGMT_CMD_SETPROP; 1572 1573 err = ipadm_door_call(iph, &parg, sizeof (parg), NULL, 0, B_FALSE); 1574 1575 /* 1576 * its fine if there were no entry in the DB to delete. The user 1577 * might be changing property value, which was not changed 1578 * persistently. 1579 */ 1580 if (err == ENOENT) 1581 err = 0; 1582 return (ipadm_errno2status(err)); 1583 } 1584 1585 /* 1586 * Called during boot. 1587 * 1588 * Walk through the DB and apply all the global module properties. We plow 1589 * through the DB even if we fail to apply property. 1590 */ 1591 /* ARGSUSED */ 1592 boolean_t 1593 ipadm_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen, 1594 int *errp) 1595 { 1596 ipadm_handle_t iph = cbarg; 1597 nvpair_t *nvp, *pnvp; 1598 char *strval = NULL, *name, *mod = NULL; 1599 uint_t proto; 1600 1601 /* 1602 * We could have used nvl_exists() directly, however we need several 1603 * calls to it and each call traverses the list. Since this codepath 1604 * is exercised during boot, let's traverse the list ourselves and do 1605 * the necessary checks. 1606 */ 1607 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL; 1608 nvp = nvlist_next_nvpair(db_nvl, nvp)) { 1609 name = nvpair_name(nvp); 1610 if (IPADM_PRIV_NVP(name)) { 1611 if (strcmp(name, IPADM_NVP_IFNAME) == 0 || 1612 strcmp(name, IPADM_NVP_AOBJNAME) == 0) 1613 return (B_TRUE); 1614 else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 && 1615 nvpair_value_string(nvp, &mod) != 0) 1616 return (B_TRUE); 1617 } else { 1618 /* possible a property */ 1619 pnvp = nvp; 1620 } 1621 } 1622 1623 /* if we are here than we found a global property */ 1624 assert(mod != NULL); 1625 assert(nvpair_type(pnvp) == DATA_TYPE_STRING); 1626 1627 proto = ipadm_str2proto(mod); 1628 if (nvpair_value_string(pnvp, &strval) == 0) { 1629 (void) ipadm_set_prop(iph, name, strval, proto, 1630 IPADM_OPT_ACTIVE); 1631 } 1632 1633 return (B_TRUE); 1634 } 1635 1636 /* initialize global module properties */ 1637 ipadm_status_t 1638 ipadm_init_prop() 1639 { 1640 ipadm_handle_t iph = NULL; 1641 ipadm_status_t status; 1642 int err; 1643 1644 /* check for solaris.network.interface.config authorization */ 1645 if (!ipadm_check_auth()) 1646 return (IPADM_EAUTH); 1647 1648 if ((status = ipadm_open(&iph, IPH_INIT)) != IPADM_SUCCESS) 1649 return (status); 1650 1651 err = ipadm_rw_db(ipadm_db_init, iph, IPADM_DB_FILE, IPADM_FILE_MODE, 1652 IPADM_DB_READ); 1653 1654 ipadm_close(iph); 1655 return (ipadm_errno2status(err)); 1656 } 1657 1658 /* 1659 * This is called from ipadm_set_ifprop() to validate the set operation. 1660 * It does the following steps: 1661 * 1. Validates the interface name. 1662 * 2. Fails if it is an IPMP meta-interface or an underlying interface. 1663 * 3. In case of a persistent operation, verifies that the 1664 * interface is persistent. 1665 */ 1666 static ipadm_status_t 1667 i_ipadm_validate_if(ipadm_handle_t iph, const char *ifname, 1668 uint_t proto, uint_t flags) 1669 { 1670 sa_family_t af, other_af; 1671 ipadm_status_t status; 1672 boolean_t p_exists; 1673 boolean_t af_exists, other_af_exists, a_exists; 1674 1675 /* Check if the interface name is valid. */ 1676 if (!i_ipadm_validate_ifname(iph, ifname)) 1677 return (IPADM_INVALID_ARG); 1678 1679 af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET); 1680 /* 1681 * Setting properties on an IPMP meta-interface or underlying 1682 * interface is not supported. 1683 */ 1684 if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname)) 1685 return (IPADM_NOTSUP); 1686 1687 /* Check if interface exists in the persistent configuration. */ 1688 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists); 1689 if (status != IPADM_SUCCESS) 1690 return (status); 1691 1692 /* Check if interface exists in the active configuration. */ 1693 af_exists = ipadm_if_enabled(iph, ifname, af); 1694 other_af = (af == AF_INET ? AF_INET6 : AF_INET); 1695 other_af_exists = ipadm_if_enabled(iph, ifname, other_af); 1696 a_exists = (af_exists || other_af_exists); 1697 if (!a_exists && p_exists) 1698 return (IPADM_OP_DISABLE_OBJ); 1699 if (!af_exists) 1700 return (IPADM_ENXIO); 1701 1702 /* 1703 * If a persistent operation is requested, check if the underlying 1704 * IP interface is persistent. 1705 */ 1706 if ((flags & IPADM_OPT_PERSIST) && !p_exists) 1707 return (IPADM_TEMPORARY_OBJ); 1708 return (IPADM_SUCCESS); 1709 } 1710