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