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