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