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