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