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