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