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) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  24  */
  25 
  26 #include <stdlib.h>
  27 #include <string.h>
  28 #include <strings.h>
  29 #include <errno.h>
  30 #include <ctype.h>
  31 #include <stddef.h>
  32 #include <sys/types.h>
  33 #include <sys/stat.h>
  34 #include <sys/dld.h>
  35 #include <sys/zone.h>
  36 #include <fcntl.h>
  37 #include <unistd.h>
  38 #include <libdevinfo.h>
  39 #include <zone.h>
  40 #include <libdllink.h>
  41 #include <libdladm_impl.h>
  42 #include <libdlwlan_impl.h>
  43 #include <libdlwlan.h>
  44 #include <libdlvlan.h>
  45 #include <libdlvnic.h>
  46 #include <libdlib.h>
  47 #include <libintl.h>
  48 #include <dlfcn.h>
  49 #include <link.h>
  50 #include <inet/wifi_ioctl.h>
  51 #include <libdladm.h>
  52 #include <libdlstat.h>
  53 #include <sys/param.h>
  54 #include <sys/debug.h>
  55 #include <sys/dld.h>
  56 #include <inttypes.h>
  57 #include <sys/ethernet.h>
  58 #include <inet/iptun.h>
  59 #include <net/wpa.h>
  60 #include <sys/sysmacros.h>
  61 #include <sys/vlan.h>
  62 #include <libdlbridge.h>
  63 #include <stp_in.h>
  64 #include <netinet/dhcp.h>
  65 #include <netinet/dhcp6.h>
  66 #include <net/if_types.h>
  67 #include <libinetutil.h>
  68 #include <pool.h>
  69 #include <libdlaggr.h>
  70 
  71 /*
  72  * The linkprop get() callback.
  73  * - pd:        pointer to the prop_desc_t
  74  * - propstrp:  a property string array to keep the returned property.
  75  *              Caller allocated.
  76  * - cntp:      number of returned properties.
  77  *              Caller also uses it to indicate how many it expects.
  78  */
  79 struct prop_desc;
  80 typedef struct prop_desc prop_desc_t;
  81 
  82 typedef dladm_status_t  pd_getf_t(dladm_handle_t, prop_desc_t *pdp,
  83                         datalink_id_t, char **propstp, uint_t *cntp,
  84                         datalink_media_t, uint_t, uint_t *);
  85 
  86 /*
  87  * The linkprop set() callback.
  88  * - propval:   a val_desc_t array which keeps the property values to be set.
  89  * - cnt:       number of properties to be set.
  90  * - flags:     additional flags passed down the system call.
  91  *
  92  * pd_set takes val_desc_t given by pd_check(), translates it into
  93  * a format suitable for kernel consumption. This may require allocation
  94  * of ioctl buffers etc. pd_set() may call another common routine (used
  95  * by all other pd_sets) which invokes the ioctl.
  96  */
  97 typedef dladm_status_t  pd_setf_t(dladm_handle_t, prop_desc_t *, datalink_id_t,
  98                             val_desc_t *propval, uint_t cnt, uint_t flags,
  99                             datalink_media_t);
 100 
 101 /*
 102  * The linkprop check() callback.
 103  * - propstrp:  property string array which keeps the property to be checked.
 104  * - cnt:       number of properties.
 105  * - propval:   return value; the property values of the given property strings.
 106  *
 107  * pd_check checks that the input values are valid. It does so by
 108  * iteraring through the pd_modval list for the property. If
 109  * the modifiable values cannot be expressed as a list, a pd_check
 110  * specific to this property can be used. If the input values are
 111  * verified to be valid, pd_check allocates a val_desc_t and fills it
 112  * with either a val_desc_t found on the pd_modval list or something
 113  * generated on the fly.
 114  */
 115 typedef dladm_status_t  pd_checkf_t(dladm_handle_t, prop_desc_t *pdp,
 116                             datalink_id_t, char **propstrp, uint_t *cnt,
 117                             uint_t flags, val_desc_t **propval,
 118                             datalink_media_t);
 119 
 120 typedef struct link_attr_s {
 121         mac_prop_id_t   pp_id;
 122         size_t          pp_valsize;
 123         char            *pp_name;
 124 } link_attr_t;
 125 
 126 typedef struct dladm_linkprop_args_s {
 127         dladm_status_t  dla_status;
 128         uint_t          dla_flags;
 129 } dladm_linkprop_args_t;
 130 
 131 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t,
 132                             const char *, uint_t, dladm_status_t *);
 133 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t,
 134                             mac_prop_id_t, uint_t, dladm_status_t *);
 135 static dladm_status_t   i_dladm_get_public_prop(dladm_handle_t, datalink_id_t,
 136                             char *, uint_t, uint_t *, void *, size_t);
 137 
 138 static dladm_status_t   i_dladm_set_private_prop(dladm_handle_t, datalink_id_t,
 139                             const char *, char **, uint_t, uint_t);
 140 static dladm_status_t   i_dladm_get_priv_prop(dladm_handle_t, datalink_id_t,
 141                             const char *, char **, uint_t *, dladm_prop_type_t,
 142                             uint_t);
 143 static dladm_status_t   i_dladm_macprop(dladm_handle_t, void *, boolean_t);
 144 static const char       *dladm_perm2str(uint_t, char *);
 145 static link_attr_t      *dladm_name2prop(const char *);
 146 static link_attr_t      *dladm_id2prop(mac_prop_id_t);
 147 
 148 static pd_getf_t        get_zone, get_autopush, get_rate_mod, get_rate,
 149                         get_speed, get_channel, get_powermode, get_radio,
 150                         get_duplex, get_link_state, get_binary, get_uint32,
 151                         get_flowctl, get_maxbw, get_cpus, get_priority,
 152                         get_tagmode, get_range, get_stp, get_bridge_forward,
 153                         get_bridge_pvid, get_protection, get_rxrings,
 154                         get_txrings, get_cntavail, get_secondary_macs,
 155                         get_allowedips, get_allowedcids, get_pool,
 156                         get_rings_range, get_linkmode_prop;
 157 
 158 static pd_setf_t        set_zone, set_rate, set_powermode, set_radio,
 159                         set_public_prop, set_resource, set_stp_prop,
 160                         set_bridge_forward, set_bridge_pvid, set_secondary_macs;
 161 
 162 static pd_checkf_t      check_zone, check_autopush, check_rate, check_hoplimit,
 163                         check_encaplim, check_uint32, check_maxbw, check_cpus,
 164                         check_stp_prop, check_bridge_pvid, check_allowedips,
 165                         check_allowedcids, check_secondary_macs, check_rings,
 166                         check_pool, check_prop;
 167 
 168 struct prop_desc {
 169         /*
 170          * link property name
 171          */
 172         char                    *pd_name;
 173 
 174         /*
 175          * default property value, can be set to { "", NULL }
 176          */
 177         val_desc_t              pd_defval;
 178 
 179         /*
 180          * list of optional property values, can be NULL.
 181          *
 182          * This is set to non-NULL if there is a list of possible property
 183          * values.  pd_optval would point to the array of possible values.
 184          */
 185         val_desc_t              *pd_optval;
 186 
 187         /*
 188          * count of the above optional property values. 0 if pd_optval is NULL.
 189          */
 190         uint_t                  pd_noptval;
 191 
 192         /*
 193          * callback to set link property; set to NULL if this property is
 194          * read-only and may be called before or after permanent update; see
 195          * flags.
 196          */
 197         pd_setf_t               *pd_set;
 198 
 199         /*
 200          * callback to get modifiable link property
 201          */
 202         pd_getf_t               *pd_getmod;
 203 
 204         /*
 205          * callback to get current link property
 206          */
 207         pd_getf_t               *pd_get;
 208 
 209         /*
 210          * callback to validate link property value, set to NULL if pd_optval
 211          * is not NULL. In that case, validate the value by comparing it with
 212          * the pd_optval. Return a val_desc_t array pointer if the value is
 213          * valid.
 214          */
 215         pd_checkf_t             *pd_check;
 216 
 217         uint_t                  pd_flags;
 218 #define PD_TEMPONLY     0x1     /* property is temporary only */
 219 #define PD_CHECK_ALLOC  0x2     /* alloc vd_val as part of pd_check */
 220 #define PD_AFTER_PERM   0x4     /* pd_set after db update; no temporary */
 221         /*
 222          * indicate link classes this property applies to.
 223          */
 224         datalink_class_t        pd_class;
 225 
 226         /*
 227          * indicate link media type this property applies to.
 228          */
 229         datalink_media_t        pd_dmedia;
 230 };
 231 
 232 #define MAC_PROP_BUFSIZE(v)     sizeof (dld_ioc_macprop_t) + (v) - 1
 233 
 234 /*
 235  * Supported link properties enumerated in the prop_table[] array are
 236  * computed using the callback functions in that array. To compute the
 237  * property value, multiple distinct system calls may be needed (e.g.,
 238  * for wifi speed, we need to issue system calls to get desired/supported
 239  * rates). The link_attr[] table enumerates the interfaces to the kernel,
 240  * and the type/size of the data passed in the user-kernel interface.
 241  */
 242 static link_attr_t link_attr[] = {
 243         { MAC_PROP_DUPLEX,      sizeof (link_duplex_t), "duplex"},
 244 
 245         { MAC_PROP_SPEED,       sizeof (uint64_t),      "speed"},
 246 
 247         { MAC_PROP_STATUS,      sizeof (link_state_t),  "state"},
 248 
 249         { MAC_PROP_AUTONEG,     sizeof (uint8_t),       "adv_autoneg_cap"},
 250 
 251         { MAC_PROP_MTU,         sizeof (uint32_t),      "mtu"},
 252 
 253         { MAC_PROP_FLOWCTRL,    sizeof (link_flowctrl_t), "flowctrl"},
 254 
 255         { MAC_PROP_ZONE,        sizeof (dld_ioc_zid_t), "zone"},
 256 
 257         { MAC_PROP_AUTOPUSH,    sizeof (struct dlautopush), "autopush"},
 258 
 259         { MAC_PROP_ADV_10GFDX_CAP, sizeof (uint8_t),    "adv_10gfdx_cap"},
 260 
 261         { MAC_PROP_EN_10GFDX_CAP, sizeof (uint8_t),     "en_10gfdx_cap"},
 262 
 263         { MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t),   "adv_1000fdx_cap"},
 264 
 265         { MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t),    "en_1000fdx_cap"},
 266 
 267         { MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t),   "adv_1000hdx_cap"},
 268 
 269         { MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t),    "en_1000hdx_cap"},
 270 
 271         { MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t),    "adv_100fdx_cap"},
 272 
 273         { MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t),     "en_100fdx_cap"},
 274 
 275         { MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t),    "adv_100hdx_cap"},
 276 
 277         { MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t),     "en_100hdx_cap"},
 278 
 279         { MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t),     "adv_10fdx_cap"},
 280 
 281         { MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t),      "en_10fdx_cap"},
 282 
 283         { MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t),     "adv_10hdx_cap"},
 284 
 285         { MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t),      "en_10hdx_cap"},
 286 
 287         { MAC_PROP_WL_ESSID,    sizeof (wl_linkstatus_t), "essid"},
 288 
 289         { MAC_PROP_WL_BSSID,    sizeof (wl_bssid_t),    "bssid"},
 290 
 291         { MAC_PROP_WL_BSSTYPE,  sizeof (wl_bss_type_t), "bsstype"},
 292 
 293         { MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"},
 294 
 295         /* wl_rates_t has variable length */
 296         { MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"},
 297 
 298         /* wl_rates_t has variable length */
 299         { MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"},
 300 
 301         { MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"},
 302 
 303         { MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"},
 304 
 305         { MAC_PROP_WL_RSSI,     sizeof (wl_rssi_t),     "signal"},
 306 
 307         { MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"},
 308 
 309         { MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"},
 310 
 311         { MAC_PROP_WL_WPA,      sizeof (wl_wpa_t),      "wpa"},
 312 
 313         /*  wl_wpa_ess_t has variable length */
 314         { MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"},
 315 
 316         { MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"},
 317 
 318         { MAC_PROP_WL_RADIO,    sizeof (dladm_wlan_radio_t), "wl_radio"},
 319 
 320         { MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t), "wl_ess_list"},
 321 
 322         { MAC_PROP_WL_KEY_TAB,  sizeof (wl_wep_key_tab_t), "wl_wep_key"},
 323 
 324         { MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"},
 325 
 326         /* wl_wpa_ie_t has variable length */
 327         { MAC_PROP_WL_SETOPTIE, sizeof (wl_wpa_ie_t),   "set_ie"},
 328 
 329         { MAC_PROP_WL_DELKEY,   sizeof (wl_del_key_t),  "wpa_del_key"},
 330 
 331         { MAC_PROP_WL_KEY,      sizeof (wl_key_t),      "wl_key"},
 332 
 333         { MAC_PROP_WL_MLME,     sizeof (wl_mlme_t),     "mlme"},
 334 
 335         { MAC_PROP_TAGMODE,     sizeof (link_tagmode_t),        "tagmode"},
 336 
 337         { MAC_PROP_IPTUN_HOPLIMIT, sizeof (uint32_t),   "hoplimit"},
 338 
 339         { MAC_PROP_IPTUN_ENCAPLIMIT, sizeof (uint32_t), "encaplimit"},
 340 
 341         { MAC_PROP_PVID,        sizeof (uint16_t),      "default_tag"},
 342 
 343         { MAC_PROP_LLIMIT,      sizeof (uint32_t),      "learn_limit"},
 344 
 345         { MAC_PROP_LDECAY,      sizeof (uint32_t),      "learn_decay"},
 346 
 347         { MAC_PROP_RESOURCE,    sizeof (mac_resource_props_t),  "resource"},
 348 
 349         { MAC_PROP_RESOURCE_EFF, sizeof (mac_resource_props_t),
 350             "resource-effective"},
 351 
 352         { MAC_PROP_RXRINGSRANGE, sizeof (mac_propval_range_t),  "rxrings"},
 353 
 354         { MAC_PROP_TXRINGSRANGE, sizeof (mac_propval_range_t),  "txrings"},
 355 
 356         { MAC_PROP_MAX_TX_RINGS_AVAIL,  sizeof (uint_t),
 357             "txrings-available"},
 358 
 359         { MAC_PROP_MAX_RX_RINGS_AVAIL,  sizeof (uint_t),
 360             "rxrings-available"},
 361 
 362         { MAC_PROP_MAX_RXHWCLNT_AVAIL,  sizeof (uint_t), "rxhwclnt-available"},
 363 
 364         { MAC_PROP_MAX_TXHWCLNT_AVAIL,  sizeof (uint_t), "txhwclnt-available"},
 365 
 366         { MAC_PROP_IB_LINKMODE, sizeof (uint32_t),      "linkmode"},
 367 
 368         { MAC_PROP_SECONDARY_ADDRS, sizeof (mac_secondary_addr_t),
 369             "secondary-macs"},
 370 
 371         { MAC_PROP_PRIVATE,     0,                      "driver-private"}
 372 };
 373 
 374 typedef struct bridge_public_prop_s {
 375         const char      *bpp_name;
 376         int             bpp_code;
 377 } bridge_public_prop_t;
 378 
 379 static const bridge_public_prop_t bridge_prop[] = {
 380         { "stp", PT_CFG_NON_STP },
 381         { "stp_priority", PT_CFG_PRIO },
 382         { "stp_cost", PT_CFG_COST },
 383         { "stp_edge", PT_CFG_EDGE },
 384         { "stp_p2p", PT_CFG_P2P },
 385         { "stp_mcheck", PT_CFG_MCHECK },
 386         { NULL, 0 }
 387 };
 388 
 389 static  val_desc_t      link_duplex_vals[] = {
 390         { "half",       LINK_DUPLEX_HALF        },
 391         { "full",       LINK_DUPLEX_HALF        }
 392 };
 393 static  val_desc_t      link_status_vals[] = {
 394         { "up",         LINK_STATE_UP           },
 395         { "down",       LINK_STATE_DOWN         }
 396 };
 397 static  val_desc_t      link_01_vals[] = {
 398         { "1",          1                       },
 399         { "0",          0                       }
 400 };
 401 static  val_desc_t      link_flow_vals[] = {
 402         { "no",         LINK_FLOWCTRL_NONE      },
 403         { "tx",         LINK_FLOWCTRL_TX        },
 404         { "rx",         LINK_FLOWCTRL_RX        },
 405         { "bi",         LINK_FLOWCTRL_BI        }
 406 };
 407 static  val_desc_t      link_priority_vals[] = {
 408         { "low",        MPL_LOW },
 409         { "medium",     MPL_MEDIUM      },
 410         { "high",       MPL_HIGH        }
 411 };
 412 
 413 static val_desc_t       link_tagmode_vals[] = {
 414         { "normal",     LINK_TAGMODE_NORMAL     },
 415         { "vlanonly",   LINK_TAGMODE_VLANONLY   }
 416 };
 417 
 418 static  val_desc_t      link_protect_vals[] = {
 419         { "mac-nospoof",        MPT_MACNOSPOOF  },
 420         { "restricted",         MPT_RESTRICTED  },
 421         { "ip-nospoof",         MPT_IPNOSPOOF   },
 422         { "dhcp-nospoof",       MPT_DHCPNOSPOOF },
 423 };
 424 
 425 static val_desc_t       dladm_wlan_radio_vals[] = {
 426         { "on",         DLADM_WLAN_RADIO_ON     },
 427         { "off",        DLADM_WLAN_RADIO_OFF    }
 428 };
 429 
 430 static val_desc_t       dladm_wlan_powermode_vals[] = {
 431         { "off",        DLADM_WLAN_PM_OFF       },
 432         { "fast",       DLADM_WLAN_PM_FAST      },
 433         { "max",        DLADM_WLAN_PM_MAX       }
 434 };
 435 
 436 static  val_desc_t      stp_p2p_vals[] = {
 437         { "true",       P2P_FORCE_TRUE          },
 438         { "false",      P2P_FORCE_FALSE         },
 439         { "auto",       P2P_AUTO                }
 440 };
 441 
 442 static  val_desc_t      dladm_part_linkmode_vals[] = {
 443         { "cm",         DLADM_PART_CM_MODE      },
 444         { "ud",         DLADM_PART_UD_MODE      },
 445 };
 446 
 447 #define VALCNT(vals)    (sizeof ((vals)) / sizeof (val_desc_t))
 448 #define RESET_VAL       ((uintptr_t)-1)
 449 #define UNSPEC_VAL      ((uintptr_t)-2)
 450 
 451 /*
 452  * For the default, if defaults are not defined for the property,
 453  * pd_defval.vd_name should be null. If the driver has to be contacted for the
 454  * value, vd_name should be the empty string (""). Otherwise, dladm will
 455  * just print whatever is in the table.
 456  */
 457 static prop_desc_t      prop_table[] = {
 458         { "channel",    { NULL, 0 },
 459             NULL, 0, NULL, NULL,
 460             get_channel, NULL, 0,
 461             DATALINK_CLASS_PHYS, DL_WIFI },
 462 
 463         { "powermode",  { "off", DLADM_WLAN_PM_OFF },
 464             dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
 465             set_powermode, NULL,
 466             get_powermode, NULL, 0,
 467             DATALINK_CLASS_PHYS, DL_WIFI },
 468 
 469         { "radio",      { "on", DLADM_WLAN_RADIO_ON },
 470             dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
 471             set_radio, NULL,
 472             get_radio, NULL, 0,
 473             DATALINK_CLASS_PHYS, DL_WIFI },
 474 
 475         { "linkmode",   { "cm", DLADM_PART_CM_MODE },
 476             dladm_part_linkmode_vals, VALCNT(dladm_part_linkmode_vals),
 477             set_public_prop, NULL, get_linkmode_prop, NULL, 0,
 478             DATALINK_CLASS_PART, DL_IB },
 479 
 480         { "speed",      { "", 0 }, NULL, 0,
 481             set_rate, get_rate_mod,
 482             get_rate, check_rate, 0,
 483             DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE },
 484 
 485         { "autopush",   { "", 0 }, NULL, 0,
 486             set_public_prop, NULL,
 487             get_autopush, check_autopush, PD_CHECK_ALLOC,
 488             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 489 
 490         { "zone",       { "", 0 }, NULL, 0,
 491             set_zone, NULL,
 492             get_zone, check_zone, PD_TEMPONLY|PD_CHECK_ALLOC,
 493             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 494 
 495         { "duplex",     { "", 0 },
 496             link_duplex_vals, VALCNT(link_duplex_vals),
 497             NULL, NULL, get_duplex, NULL,
 498             0, DATALINK_CLASS_PHYS, DL_ETHER },
 499 
 500         { "state",      { "up", LINK_STATE_UP },
 501             link_status_vals, VALCNT(link_status_vals),
 502             NULL, NULL, get_link_state, NULL,
 503             0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 504 
 505         { "adv_autoneg_cap", { "", 0 },
 506             link_01_vals, VALCNT(link_01_vals),
 507             set_public_prop, NULL, get_binary, NULL,
 508             0, DATALINK_CLASS_PHYS, DL_ETHER },
 509 
 510         { "mtu", { "", 0 }, NULL, 0,
 511             set_public_prop, get_range,
 512             get_uint32, check_uint32, 0, DATALINK_CLASS_ALL,
 513             DATALINK_ANY_MEDIATYPE },
 514 
 515         { "flowctrl", { "", 0 },
 516             link_flow_vals, VALCNT(link_flow_vals),
 517             set_public_prop, NULL, get_flowctl, NULL,
 518             0, DATALINK_CLASS_PHYS, DL_ETHER },
 519 
 520         { "secondary-macs", { "--", 0 }, NULL, 0,
 521             set_secondary_macs, NULL,
 522             get_secondary_macs, check_secondary_macs, PD_CHECK_ALLOC,
 523             DATALINK_CLASS_VNIC, DL_ETHER },
 524 
 525         { "adv_10gfdx_cap", { "", 0 },
 526             link_01_vals, VALCNT(link_01_vals),
 527             NULL, NULL, get_binary, NULL,
 528             0, DATALINK_CLASS_PHYS, DL_ETHER },
 529 
 530         { "en_10gfdx_cap", { "", 0 },
 531             link_01_vals, VALCNT(link_01_vals),
 532             set_public_prop, NULL, get_binary, NULL,
 533             0, DATALINK_CLASS_PHYS, DL_ETHER },
 534 
 535         { "adv_1000fdx_cap", { "", 0 },
 536             link_01_vals, VALCNT(link_01_vals),
 537             NULL, NULL, get_binary, NULL,
 538             0, DATALINK_CLASS_PHYS, DL_ETHER },
 539 
 540         { "en_1000fdx_cap", { "", 0 },
 541             link_01_vals, VALCNT(link_01_vals),
 542             set_public_prop, NULL, get_binary, NULL,
 543             0, DATALINK_CLASS_PHYS, DL_ETHER },
 544 
 545         { "adv_1000hdx_cap", { "", 0 },
 546             link_01_vals, VALCNT(link_01_vals),
 547             NULL, NULL, get_binary, NULL,
 548             0, DATALINK_CLASS_PHYS, DL_ETHER },
 549 
 550         { "en_1000hdx_cap", { "", 0 },
 551             link_01_vals, VALCNT(link_01_vals),
 552             set_public_prop, NULL, get_binary, NULL,
 553             0, DATALINK_CLASS_PHYS, DL_ETHER },
 554 
 555         { "adv_100fdx_cap", { "", 0 },
 556             link_01_vals, VALCNT(link_01_vals),
 557             NULL, NULL, get_binary, NULL,
 558             0, DATALINK_CLASS_PHYS, DL_ETHER },
 559 
 560         { "en_100fdx_cap", { "", 0 },
 561             link_01_vals, VALCNT(link_01_vals),
 562             set_public_prop, NULL, get_binary, NULL,
 563             0, DATALINK_CLASS_PHYS, DL_ETHER },
 564 
 565         { "adv_100hdx_cap", { "", 0 },
 566             link_01_vals, VALCNT(link_01_vals),
 567             NULL, NULL, get_binary, NULL,
 568             0, DATALINK_CLASS_PHYS, DL_ETHER },
 569 
 570         { "en_100hdx_cap", { "", 0 },
 571             link_01_vals, VALCNT(link_01_vals),
 572             set_public_prop, NULL, get_binary, NULL,
 573             0, DATALINK_CLASS_PHYS, DL_ETHER },
 574 
 575         { "adv_10fdx_cap", { "", 0 },
 576             link_01_vals, VALCNT(link_01_vals),
 577             NULL, NULL, get_binary, NULL,
 578             0, DATALINK_CLASS_PHYS, DL_ETHER },
 579 
 580         { "en_10fdx_cap", { "", 0 },
 581             link_01_vals, VALCNT(link_01_vals),
 582             set_public_prop, NULL, get_binary, NULL,
 583             0, DATALINK_CLASS_PHYS, DL_ETHER },
 584 
 585         { "adv_10hdx_cap", { "", 0 },
 586             link_01_vals, VALCNT(link_01_vals),
 587             NULL, NULL, get_binary, NULL,
 588             0, DATALINK_CLASS_PHYS, DL_ETHER },
 589 
 590         { "en_10hdx_cap", { "", 0 },
 591             link_01_vals, VALCNT(link_01_vals),
 592             set_public_prop, NULL, get_binary, NULL,
 593             0, DATALINK_CLASS_PHYS, DL_ETHER },
 594 
 595         { "maxbw", { "--", RESET_VAL }, NULL, 0,
 596             set_resource, NULL,
 597             get_maxbw, check_maxbw, PD_CHECK_ALLOC,
 598             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 599 
 600         { "cpus", { "--", RESET_VAL }, NULL, 0,
 601             set_resource, NULL,
 602             get_cpus, check_cpus, 0,
 603             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 604 
 605         { "cpus-effective", { "--", 0 },
 606             NULL, 0, NULL, NULL,
 607             get_cpus, 0, 0,
 608             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 609 
 610         { "pool", { "--", RESET_VAL }, NULL, 0,
 611             set_resource, NULL,
 612             get_pool, check_pool, 0,
 613             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 614 
 615         { "pool-effective", { "--", 0 },
 616             NULL, 0, NULL, NULL,
 617             get_pool, 0, 0,
 618             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 619 
 620         { "priority", { "high", MPL_RESET },
 621             link_priority_vals, VALCNT(link_priority_vals), set_resource,
 622             NULL, get_priority, check_prop, 0,
 623             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 624 
 625         { "tagmode", { "vlanonly", LINK_TAGMODE_VLANONLY },
 626             link_tagmode_vals, VALCNT(link_tagmode_vals),
 627             set_public_prop, NULL, get_tagmode,
 628             NULL, 0,
 629             DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | DATALINK_CLASS_VNIC,
 630             DL_ETHER },
 631 
 632         { "hoplimit", { "", 0 }, NULL, 0,
 633             set_public_prop, get_range, get_uint32,
 634             check_hoplimit, 0, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE},
 635 
 636         { "encaplimit", { "", 0 }, NULL, 0,
 637             set_public_prop, get_range, get_uint32,
 638             check_encaplim, 0, DATALINK_CLASS_IPTUN, DL_IPV6},
 639 
 640         { "forward", { "1", 1 },
 641             link_01_vals, VALCNT(link_01_vals),
 642             set_bridge_forward, NULL, get_bridge_forward, NULL, PD_AFTER_PERM,
 643             DATALINK_CLASS_ALL & ~DATALINK_CLASS_VNIC, DL_ETHER },
 644 
 645         { "default_tag", { "1", 1 }, NULL, 0,
 646             set_bridge_pvid, NULL, get_bridge_pvid, check_bridge_pvid,
 647             0, DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
 648             DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
 649 
 650         { "learn_limit", { "1000", 1000 }, NULL, 0,
 651             set_public_prop, NULL, get_uint32,
 652             check_uint32, 0,
 653             DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
 654             DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
 655 
 656         { "learn_decay", { "200", 200 }, NULL, 0,
 657             set_public_prop, NULL, get_uint32,
 658             check_uint32, 0,
 659             DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
 660             DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
 661 
 662         { "stp", { "1", 1 },
 663             link_01_vals, VALCNT(link_01_vals),
 664             set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
 665             DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
 666             DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
 667 
 668         { "stp_priority", { "128", 128 }, NULL, 0,
 669             set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
 670             DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
 671             DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
 672 
 673         { "stp_cost", { "auto", 0 }, NULL, 0,
 674             set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
 675             DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
 676             DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
 677 
 678         { "stp_edge", { "1", 1 },
 679             link_01_vals, VALCNT(link_01_vals),
 680             set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
 681             DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
 682             DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
 683 
 684         { "stp_p2p", { "auto", P2P_AUTO },
 685             stp_p2p_vals, VALCNT(stp_p2p_vals),
 686             set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
 687             DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
 688             DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
 689 
 690         { "stp_mcheck", { "0", 0 },
 691             link_01_vals, VALCNT(link_01_vals),
 692             set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
 693             DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
 694             DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
 695 
 696         { "protection", { "--", RESET_VAL },
 697             link_protect_vals, VALCNT(link_protect_vals),
 698             set_resource, NULL, get_protection, check_prop, 0,
 699             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 700 
 701         { "allowed-ips", { "--", 0 },
 702             NULL, 0, set_resource, NULL,
 703             get_allowedips, check_allowedips, PD_CHECK_ALLOC,
 704             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 705 
 706         { "allowed-dhcp-cids", { "--", 0 },
 707             NULL, 0, set_resource, NULL,
 708             get_allowedcids, check_allowedcids, PD_CHECK_ALLOC,
 709             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 710 
 711         { "rxrings", { "--", RESET_VAL }, NULL, 0,
 712             set_resource, get_rings_range, get_rxrings, check_rings, 0,
 713             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 714 
 715         { "rxrings-effective", { "--", 0 },
 716             NULL, 0, NULL, NULL,
 717             get_rxrings, NULL, 0,
 718             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 719 
 720         { "txrings", { "--", RESET_VAL }, NULL, 0,
 721             set_resource, get_rings_range, get_txrings, check_rings, 0,
 722             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 723 
 724         { "txrings-effective", { "--", 0 },
 725             NULL, 0, NULL, NULL,
 726             get_txrings, NULL, 0,
 727             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 728 
 729         { "txrings-available", { "", 0 }, NULL, 0,
 730             NULL, NULL, get_cntavail, NULL, 0,
 731             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 732 
 733         { "rxrings-available", { "", 0 }, NULL, 0,
 734             NULL, NULL, get_cntavail, NULL, 0,
 735             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 736 
 737         { "rxhwclnt-available", { "", 0 }, NULL, 0,
 738             NULL, NULL, get_cntavail, NULL, 0,
 739             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 740 
 741         { "txhwclnt-available", { "", 0 }, NULL, 0,
 742             NULL, NULL, get_cntavail, NULL, 0,
 743             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 744 
 745 };
 746 
 747 #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t))
 748 
 749 static resource_prop_t rsrc_prop_table[] = {
 750         {"maxbw",               extract_maxbw},
 751         {"priority",            extract_priority},
 752         {"cpus",                extract_cpus},
 753         {"cpus-effective",      extract_cpus},
 754         {"pool",                extract_pool},
 755         {"pool-effective",      extract_pool},
 756         {"protection",          extract_protection},
 757         {"allowed-ips",         extract_allowedips},
 758         {"allowed-dhcp-cids",   extract_allowedcids},
 759         {"rxrings",             extract_rxrings},
 760         {"rxrings-effective",   extract_rxrings},
 761         {"txrings",             extract_txrings},
 762         {"txrings-effective",   extract_txrings}
 763 };
 764 #define DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
 765         sizeof (resource_prop_t))
 766 
 767 /*
 768  * when retrieving  private properties, we pass down a buffer with
 769  * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value.
 770  */
 771 #define DLADM_PROP_BUF_CHUNK    1024
 772 
 773 static dladm_status_t   i_dladm_set_linkprop_db(dladm_handle_t, datalink_id_t,
 774                             const char *, char **, uint_t);
 775 static dladm_status_t   i_dladm_get_linkprop_db(dladm_handle_t, datalink_id_t,
 776                             const char *, char **, uint_t *);
 777 static dladm_status_t   i_dladm_walk_linkprop_priv_db(dladm_handle_t,
 778                             datalink_id_t, void *, int (*)(dladm_handle_t,
 779                             datalink_id_t, const char *, void *));
 780 static dladm_status_t   i_dladm_set_single_prop(dladm_handle_t, datalink_id_t,
 781                             datalink_class_t, uint32_t, prop_desc_t *, char **,
 782                             uint_t, uint_t);
 783 static dladm_status_t   i_dladm_set_linkprop(dladm_handle_t, datalink_id_t,
 784                             const char *, char **, uint_t, uint_t);
 785 static dladm_status_t   i_dladm_getset_defval(dladm_handle_t, prop_desc_t *,
 786                             datalink_id_t, datalink_media_t, uint_t);
 787 
 788 /*
 789  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
 790  * rates to be retrieved. However, we cannot increase it at this
 791  * time because it will break binary compatibility with unbundled
 792  * WiFi drivers and utilities. So for now we define an additional
 793  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
 794  */
 795 #define MAX_SUPPORT_RATES       64
 796 
 797 #define AP_ANCHOR       "[anchor]"
 798 #define AP_DELIMITER    '.'
 799 
 800 /* ARGSUSED */
 801 static dladm_status_t
 802 check_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
 803     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
 804     datalink_media_t media)
 805 {
 806         int             i, j;
 807         uint_t          val_cnt = *val_cntp;
 808         val_desc_t      *vdp = *vdpp;
 809 
 810         for (j = 0; j < val_cnt; j++) {
 811                 for (i = 0; i < pdp->pd_noptval; i++) {
 812                         if (strcasecmp(prop_val[j],
 813                             pdp->pd_optval[i].vd_name) == 0) {
 814                                 break;
 815                         }
 816                 }
 817                 if (i == pdp->pd_noptval)
 818                         return (DLADM_STATUS_BADVAL);
 819 
 820                 (void) memcpy(&vdp[j], &pdp->pd_optval[i], sizeof (val_desc_t));
 821         }
 822         return (DLADM_STATUS_OK);
 823 }
 824 
 825 static dladm_status_t
 826 i_dladm_set_single_prop(dladm_handle_t handle, datalink_id_t linkid,
 827     datalink_class_t class, uint32_t media, prop_desc_t *pdp, char **prop_val,
 828     uint_t val_cnt, uint_t flags)
 829 {
 830         dladm_status_t  status = DLADM_STATUS_OK;
 831         val_desc_t      *vdp = NULL;
 832         boolean_t       needfree = B_FALSE;
 833         uint_t          cnt, i;
 834 
 835         if (!(pdp->pd_class & class))
 836                 return (DLADM_STATUS_BADARG);
 837 
 838         if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
 839                 return (DLADM_STATUS_BADARG);
 840 
 841         if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
 842                 return (DLADM_STATUS_TEMPONLY);
 843 
 844         if (!(flags & DLADM_OPT_ACTIVE))
 845                 return (DLADM_STATUS_OK);
 846 
 847         if (pdp->pd_set == NULL)
 848                 return (DLADM_STATUS_PROPRDONLY);
 849 
 850         if (prop_val != NULL) {
 851                 vdp = calloc(val_cnt, sizeof (val_desc_t));
 852                 if (vdp == NULL)
 853                         return (DLADM_STATUS_NOMEM);
 854 
 855                 if (pdp->pd_check != NULL) {
 856                         needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0);
 857                         status = pdp->pd_check(handle, pdp, linkid, prop_val,
 858                             &val_cnt, flags, &vdp, media);
 859                 } else if (pdp->pd_optval != NULL) {
 860                         status = check_prop(handle, pdp, linkid, prop_val,
 861                             &val_cnt, flags, &vdp, media);
 862                 } else {
 863                         status = DLADM_STATUS_BADARG;
 864                 }
 865 
 866                 if (status != DLADM_STATUS_OK)
 867                         goto done;
 868 
 869                 cnt = val_cnt;
 870         } else {
 871                 boolean_t       defval = B_FALSE;
 872 
 873                 if (pdp->pd_defval.vd_name == NULL)
 874                         return (DLADM_STATUS_NOTSUP);
 875 
 876                 cnt = 1;
 877                 defval = (strlen(pdp->pd_defval.vd_name) > 0);
 878                 if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || defval) {
 879                         if ((vdp = calloc(1, sizeof (val_desc_t))) == NULL)
 880                                 return (DLADM_STATUS_NOMEM);
 881 
 882                         if (defval) {
 883                                 (void) memcpy(vdp, &pdp->pd_defval,
 884                                     sizeof (val_desc_t));
 885                         } else if (pdp->pd_check != NULL) {
 886                                 status = pdp->pd_check(handle, pdp, linkid,
 887                                     prop_val, &cnt, flags, &vdp, media);
 888                                 if (status != DLADM_STATUS_OK)
 889                                         goto done;
 890                         }
 891                 } else {
 892                         status = i_dladm_getset_defval(handle, pdp, linkid,
 893                             media, flags);
 894                         return (status);
 895                 }
 896         }
 897         if (pdp->pd_flags & PD_AFTER_PERM)
 898                 status = (flags & DLADM_OPT_PERSIST) ? DLADM_STATUS_OK :
 899                     DLADM_STATUS_PERMONLY;
 900         else
 901                 status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags,
 902                     media);
 903         if (needfree) {
 904                 for (i = 0; i < cnt; i++)
 905                         free((void *)((val_desc_t *)vdp + i)->vd_val);
 906         }
 907 done:
 908         free(vdp);
 909         return (status);
 910 }
 911 
 912 static dladm_status_t
 913 i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
 914     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
 915 {
 916         int                     i;
 917         boolean_t               found = B_FALSE;
 918         datalink_class_t        class;
 919         uint32_t                media;
 920         dladm_status_t          status = DLADM_STATUS_OK;
 921 
 922         status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
 923             NULL, 0);
 924         if (status != DLADM_STATUS_OK)
 925                 return (status);
 926 
 927         for (i = 0; i < DLADM_MAX_PROPS; i++) {
 928                 prop_desc_t     *pdp = &prop_table[i];
 929                 dladm_status_t  s;
 930 
 931                 if (prop_name != NULL &&
 932                     (strcasecmp(prop_name, pdp->pd_name) != 0))
 933                         continue;
 934                 found = B_TRUE;
 935                 s = i_dladm_set_single_prop(handle, linkid, class, media, pdp,
 936                     prop_val, val_cnt, flags);
 937 
 938                 if (prop_name != NULL) {
 939                         status = s;
 940                         break;
 941                 } else {
 942                         if (s != DLADM_STATUS_OK &&
 943                             s != DLADM_STATUS_NOTSUP)
 944                                 status = s;
 945                 }
 946         }
 947         if (!found) {
 948                 if (prop_name[0] == '_') {
 949                         /* other private properties */
 950                         status = i_dladm_set_private_prop(handle, linkid,
 951                             prop_name, prop_val, val_cnt, flags);
 952                 } else  {
 953                         status = DLADM_STATUS_NOTFOUND;
 954                 }
 955         }
 956         return (status);
 957 }
 958 
 959 /*
 960  * Set/reset link property for specific link
 961  */
 962 dladm_status_t
 963 dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
 964     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
 965 {
 966         dladm_status_t  status = DLADM_STATUS_OK;
 967 
 968         if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
 969             (prop_val == NULL && val_cnt > 0) ||
 970             (prop_val != NULL && val_cnt == 0) ||
 971             (prop_name == NULL && prop_val != NULL)) {
 972                 return (DLADM_STATUS_BADARG);
 973         }
 974 
 975         /*
 976          * Check for valid link property against the flags passed
 977          * and set the link property when active flag is passed.
 978          */
 979         status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val,
 980             val_cnt, flags);
 981         if (status != DLADM_STATUS_OK)
 982                 return (status);
 983 
 984         if (flags & DLADM_OPT_PERSIST) {
 985                 status = i_dladm_set_linkprop_db(handle, linkid, prop_name,
 986                     prop_val, val_cnt);
 987 
 988                 if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
 989                         prop_desc_t *pdp = prop_table;
 990                         int i;
 991 
 992                         for (i = 0; i < DLADM_MAX_PROPS; i++, pdp++) {
 993                                 if (!(pdp->pd_flags & PD_AFTER_PERM))
 994                                         continue;
 995                                 if (prop_name != NULL &&
 996                                     strcasecmp(prop_name, pdp->pd_name) != 0)
 997                                         continue;
 998                                 status = pdp->pd_set(handle, pdp, linkid, NULL,
 999                                     0, flags, 0);
1000                         }
1001                 }
1002         }
1003         return (status);
1004 }
1005 
1006 /*
1007  * Walk all link properties of the given specific link.
1008  *
1009  * Note: this function currently lacks the ability to walk _all_ private
1010  * properties if the link, because there is no kernel interface to
1011  * retrieve all known private property names. Once such an interface
1012  * is added, this function should be fixed accordingly.
1013  */
1014 dladm_status_t
1015 dladm_walk_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg,
1016     int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
1017 {
1018         dladm_status_t          status;
1019         datalink_class_t        class;
1020         uint_t                  media;
1021         int                     i;
1022 
1023         if (linkid == DATALINK_INVALID_LINKID || func == NULL)
1024                 return (DLADM_STATUS_BADARG);
1025 
1026         status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1027             NULL, 0);
1028         if (status != DLADM_STATUS_OK)
1029                 return (status);
1030 
1031         /* public */
1032         for (i = 0; i < DLADM_MAX_PROPS; i++) {
1033                 if (!(prop_table[i].pd_class & class))
1034                         continue;
1035 
1036                 if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
1037                         continue;
1038 
1039                 if (func(handle, linkid, prop_table[i].pd_name, arg) ==
1040                     DLADM_WALK_TERMINATE) {
1041                         break;
1042                 }
1043         }
1044 
1045         /* private */
1046         status = i_dladm_walk_linkprop_priv_db(handle, linkid, arg, func);
1047 
1048         return (status);
1049 }
1050 
1051 /*
1052  * Get linkprop of the given specific link.
1053  */
1054 dladm_status_t
1055 dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1056     dladm_prop_type_t type, const char *prop_name, char **prop_val,
1057     uint_t *val_cntp)
1058 {
1059         dladm_status_t          status = DLADM_STATUS_OK;
1060         datalink_class_t        class;
1061         uint_t                  media;
1062         prop_desc_t             *pdp;
1063         uint_t                  cnt, dld_flags = 0;
1064         int                     i;
1065         uint_t                  perm_flags;
1066 
1067         if (type == DLADM_PROP_VAL_DEFAULT)
1068                 dld_flags |= DLD_PROP_DEFAULT;
1069         else if (type == DLADM_PROP_VAL_MODIFIABLE)
1070                 dld_flags |= DLD_PROP_POSSIBLE;
1071 
1072         if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
1073             prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
1074                 return (DLADM_STATUS_BADARG);
1075 
1076         for (i = 0; i < DLADM_MAX_PROPS; i++)
1077                 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
1078                         break;
1079 
1080         if (i == DLADM_MAX_PROPS) {
1081                 if (prop_name[0] == '_') {
1082                         /*
1083                          * private property.
1084                          */
1085                         if (type == DLADM_PROP_VAL_PERSISTENT)
1086                                 return (i_dladm_get_linkprop_db(handle, linkid,
1087                                     prop_name, prop_val, val_cntp));
1088                         else
1089                                 return (i_dladm_get_priv_prop(handle, linkid,
1090                                     prop_name, prop_val, val_cntp, type,
1091                                     dld_flags));
1092                 } else {
1093                         return (DLADM_STATUS_NOTFOUND);
1094                 }
1095         }
1096 
1097         pdp = &prop_table[i];
1098 
1099         status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1100             NULL, 0);
1101         if (status != DLADM_STATUS_OK)
1102                 return (status);
1103 
1104         if (!(pdp->pd_class & class))
1105                 return (DLADM_STATUS_BADARG);
1106 
1107         if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
1108                 return (DLADM_STATUS_BADARG);
1109 
1110         switch (type) {
1111         case DLADM_PROP_VAL_CURRENT:
1112                 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1113                     media, dld_flags, &perm_flags);
1114                 break;
1115 
1116         case DLADM_PROP_VAL_PERM:
1117                 if (pdp->pd_set == NULL) {
1118                         perm_flags = MAC_PROP_PERM_READ;
1119                 } else {
1120                         status = pdp->pd_get(handle, pdp, linkid, prop_val,
1121                             val_cntp, media, dld_flags, &perm_flags);
1122                 }
1123 
1124                 *prop_val[0] = '\0';
1125                 *val_cntp = 1;
1126                 if (status == DLADM_STATUS_OK)
1127                         (void) dladm_perm2str(perm_flags, *prop_val);
1128                 break;
1129 
1130         case DLADM_PROP_VAL_DEFAULT:
1131                 /*
1132                  * If defaults are not defined for the property,
1133                  * pd_defval.vd_name should be null. If the driver
1134                  * has to be contacted for the value, vd_name should
1135                  * be the empty string (""). Otherwise, dladm will
1136                  * just print whatever is in the table.
1137                  */
1138                 if (pdp->pd_defval.vd_name == NULL) {
1139                         status = DLADM_STATUS_NOTSUP;
1140                         break;
1141                 }
1142 
1143                 if (strlen(pdp->pd_defval.vd_name) == 0) {
1144                         status = pdp->pd_get(handle, pdp, linkid, prop_val,
1145                             val_cntp, media, dld_flags, &perm_flags);
1146                 } else {
1147                         (void) strcpy(*prop_val, pdp->pd_defval.vd_name);
1148                 }
1149                 *val_cntp = 1;
1150                 break;
1151 
1152         case DLADM_PROP_VAL_MODIFIABLE:
1153                 if (pdp->pd_getmod != NULL) {
1154                         status = pdp->pd_getmod(handle, pdp, linkid, prop_val,
1155                             val_cntp, media, dld_flags, &perm_flags);
1156                         break;
1157                 }
1158                 cnt = pdp->pd_noptval;
1159                 if (cnt == 0) {
1160                         status = DLADM_STATUS_NOTSUP;
1161                 } else if (cnt > *val_cntp) {
1162                         status = DLADM_STATUS_TOOSMALL;
1163                 } else {
1164                         for (i = 0; i < cnt; i++) {
1165                                 (void) strcpy(prop_val[i],
1166                                     pdp->pd_optval[i].vd_name);
1167                         }
1168                         *val_cntp = cnt;
1169                 }
1170                 break;
1171         case DLADM_PROP_VAL_PERSISTENT:
1172                 if (pdp->pd_flags & PD_TEMPONLY)
1173                         return (DLADM_STATUS_TEMPONLY);
1174                 status = i_dladm_get_linkprop_db(handle, linkid, prop_name,
1175                     prop_val, val_cntp);
1176                 break;
1177         default:
1178                 status = DLADM_STATUS_BADARG;
1179                 break;
1180         }
1181 
1182         return (status);
1183 }
1184 
1185 /*
1186  * Get linkprop of the given specific link and run any possible conversion
1187  * of the values using the check function for the property. Fails if the
1188  * check function doesn't succeed for the property value.
1189  */
1190 dladm_status_t
1191 dladm_get_linkprop_values(dladm_handle_t handle, datalink_id_t linkid,
1192     dladm_prop_type_t type, const char *prop_name, uint_t *ret_val,
1193     uint_t *val_cntp)
1194 {
1195         dladm_status_t          status;
1196         datalink_class_t        class;
1197         uint_t                  media;
1198         prop_desc_t             *pdp;
1199         uint_t                  dld_flags;
1200         int                     valc, i;
1201         char                    **prop_val;
1202         uint_t                  perm_flags;
1203 
1204         if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
1205             ret_val == NULL || val_cntp == NULL || *val_cntp == 0)
1206                 return (DLADM_STATUS_BADARG);
1207 
1208         for (pdp = prop_table; pdp < prop_table + DLADM_MAX_PROPS; pdp++)
1209                 if (strcasecmp(prop_name, pdp->pd_name) == 0)
1210                         break;
1211 
1212         if (pdp == prop_table + DLADM_MAX_PROPS)
1213                 return (DLADM_STATUS_NOTFOUND);
1214 
1215         if (pdp->pd_flags & PD_CHECK_ALLOC)
1216                 return (DLADM_STATUS_BADARG);
1217 
1218         status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1219             NULL, 0);
1220         if (status != DLADM_STATUS_OK)
1221                 return (status);
1222 
1223         if (!(pdp->pd_class & class))
1224                 return (DLADM_STATUS_BADARG);
1225 
1226         if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
1227                 return (DLADM_STATUS_BADARG);
1228 
1229         prop_val = malloc(*val_cntp * sizeof (*prop_val) +
1230             *val_cntp * DLADM_PROP_VAL_MAX);
1231         if (prop_val == NULL)
1232                 return (DLADM_STATUS_NOMEM);
1233         for (valc = 0; valc < *val_cntp; valc++)
1234                 prop_val[valc] = (char *)(prop_val + *val_cntp) +
1235                     valc * DLADM_PROP_VAL_MAX;
1236 
1237         dld_flags = (type == DLADM_PROP_VAL_DEFAULT) ? DLD_PROP_DEFAULT : 0;
1238 
1239         switch (type) {
1240         case DLADM_PROP_VAL_CURRENT:
1241                 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1242                     media, dld_flags, &perm_flags);
1243                 break;
1244 
1245         case DLADM_PROP_VAL_DEFAULT:
1246                 /*
1247                  * If defaults are not defined for the property,
1248                  * pd_defval.vd_name should be null. If the driver
1249                  * has to be contacted for the value, vd_name should
1250                  * be the empty string (""). Otherwise, dladm will
1251                  * just print whatever is in the table.
1252                  */
1253                 if (pdp->pd_defval.vd_name == NULL) {
1254                         status = DLADM_STATUS_NOTSUP;
1255                         break;
1256                 }
1257 
1258                 if (pdp->pd_defval.vd_name[0] != '\0') {
1259                         *val_cntp = 1;
1260                         *ret_val = pdp->pd_defval.vd_val;
1261                         free(prop_val);
1262                         return (DLADM_STATUS_OK);
1263                 }
1264                 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1265                     media, dld_flags, &perm_flags);
1266                 break;
1267 
1268         case DLADM_PROP_VAL_PERSISTENT:
1269                 if (pdp->pd_flags & PD_TEMPONLY)
1270                         status = DLADM_STATUS_TEMPONLY;
1271                 else
1272                         status = i_dladm_get_linkprop_db(handle, linkid,
1273                             prop_name, prop_val, val_cntp);
1274                 break;
1275 
1276         default:
1277                 status = DLADM_STATUS_BADARG;
1278                 break;
1279         }
1280 
1281         if (status == DLADM_STATUS_OK) {
1282                 if (pdp->pd_check != NULL) {
1283                         val_desc_t *vdp;
1284 
1285                         vdp = malloc(sizeof (val_desc_t) * *val_cntp);
1286                         if (vdp == NULL)
1287                                 status = DLADM_STATUS_NOMEM;
1288                         else
1289                                 status = pdp->pd_check(handle, pdp, linkid,
1290                                     prop_val, val_cntp, 0, &vdp, media);
1291                         if (status == DLADM_STATUS_OK) {
1292                                 for (valc = 0; valc < *val_cntp; valc++)
1293                                         ret_val[valc] = vdp[valc].vd_val;
1294                         }
1295                         free(vdp);
1296                 } else {
1297                         for (valc = 0; valc < *val_cntp; valc++) {
1298                                 for (i = 0; i < pdp->pd_noptval; i++) {
1299                                         if (strcmp(pdp->pd_optval[i].vd_name,
1300                                             prop_val[valc]) == 0) {
1301                                                 ret_val[valc] =
1302                                                     pdp->pd_optval[i].vd_val;
1303                                                 break;
1304                                         }
1305                                 }
1306                                 if (i == pdp->pd_noptval) {
1307                                         status = DLADM_STATUS_FAILED;
1308                                         break;
1309                                 }
1310                         }
1311                 }
1312         }
1313 
1314         free(prop_val);
1315 
1316         return (status);
1317 }
1318 
1319 /*ARGSUSED*/
1320 static int
1321 i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid,
1322     const char *prop_name, void *arg)
1323 {
1324         char                    *buf, **propvals;
1325         uint_t                  i, valcnt = DLADM_MAX_PROP_VALCNT;
1326         dladm_status_t          status;
1327         dladm_linkprop_args_t   *dla = arg;
1328 
1329         if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
1330             DLADM_MAX_PROP_VALCNT)) == NULL) {
1331                 return (DLADM_WALK_CONTINUE);
1332         }
1333 
1334         propvals = (char **)(void *)buf;
1335         for (i = 0; i < valcnt; i++) {
1336                 propvals[i] = buf +
1337                     sizeof (char *) * DLADM_MAX_PROP_VALCNT +
1338                     i * DLADM_PROP_VAL_MAX;
1339         }
1340 
1341         if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
1342             prop_name, propvals, &valcnt) != DLADM_STATUS_OK) {
1343                 goto done;
1344         }
1345 
1346         status = dladm_set_linkprop(handle, linkid, prop_name, propvals,
1347             valcnt, dla->dla_flags | DLADM_OPT_ACTIVE);
1348 
1349         if (status != DLADM_STATUS_OK)
1350                 dla->dla_status = status;
1351 
1352 done:
1353         if (buf != NULL)
1354                 free(buf);
1355 
1356         return (DLADM_WALK_CONTINUE);
1357 }
1358 
1359 /*ARGSUSED*/
1360 static int
1361 i_dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg)
1362 {
1363         datalink_class_t        class;
1364         dladm_status_t          status;
1365 
1366         status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
1367             NULL, 0);
1368         if (status != DLADM_STATUS_OK)
1369                 return (DLADM_WALK_TERMINATE);
1370 
1371         if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0)
1372                 (void) dladm_init_linkprop(handle, linkid, B_TRUE);
1373 
1374         return (DLADM_WALK_CONTINUE);
1375 }
1376 
1377 dladm_status_t
1378 dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1379     boolean_t any_media)
1380 {
1381         dladm_status_t          status = DLADM_STATUS_OK;
1382         datalink_media_t        dmedia;
1383         uint32_t                media;
1384         dladm_linkprop_args_t   *dla;
1385 
1386         dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI;
1387 
1388         dla = malloc(sizeof (dladm_linkprop_args_t));
1389         if (dla == NULL)
1390                 return (DLADM_STATUS_NOMEM);
1391         dla->dla_flags = DLADM_OPT_BOOT;
1392         dla->dla_status = DLADM_STATUS_OK;
1393 
1394         if (linkid == DATALINK_ALL_LINKID) {
1395                 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
1396                     NULL, DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST);
1397         } else if (any_media ||
1398             ((dladm_datalink_id2info(handle, linkid, NULL, NULL, &media, NULL,
1399             0) == DLADM_STATUS_OK) &&
1400             DATALINK_MEDIA_ACCEPTED(dmedia, media))) {
1401                 (void) dladm_walk_linkprop(handle, linkid, (void *)dla,
1402                     i_dladm_init_one_prop);
1403                 status = dla->dla_status;
1404         }
1405         free(dla);
1406         return (status);
1407 }
1408 
1409 /* ARGSUSED */
1410 static dladm_status_t
1411 get_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1412     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1413     uint_t flags, uint_t *perm_flags)
1414 {
1415         char                    zone_name[ZONENAME_MAX];
1416         zoneid_t                zid;
1417         dladm_status_t          status;
1418 
1419         if (flags != 0)
1420                 return (DLADM_STATUS_NOTSUP);
1421 
1422         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1423             perm_flags, &zid, sizeof (zid));
1424         if (status != DLADM_STATUS_OK)
1425                 return (status);
1426 
1427         *val_cnt = 1;
1428         if (zid != GLOBAL_ZONEID) {
1429                 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) {
1430                         return (dladm_errno2status(errno));
1431                 }
1432 
1433                 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
1434         } else {
1435                 *prop_val[0] = '\0';
1436         }
1437 
1438         return (DLADM_STATUS_OK);
1439 }
1440 
1441 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
1442 
1443 static int
1444 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
1445 {
1446         char                    root[MAXPATHLEN];
1447         zone_get_devroot_t      real_zone_get_devroot;
1448         void                    *dlhandle;
1449         void                    *sym;
1450         int                     ret;
1451 
1452         if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
1453                 return (-1);
1454 
1455         if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
1456                 (void) dlclose(dlhandle);
1457                 return (-1);
1458         }
1459 
1460         real_zone_get_devroot = (zone_get_devroot_t)sym;
1461 
1462         if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
1463                 (void) snprintf(dev, devlen, "%s%s", root, "/dev");
1464         (void) dlclose(dlhandle);
1465         return (ret);
1466 }
1467 
1468 static dladm_status_t
1469 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid,
1470     datalink_id_t linkid, boolean_t add)
1471 {
1472         char            path[MAXPATHLEN];
1473         char            name[MAXLINKNAMELEN];
1474         di_prof_t       prof = NULL;
1475         char            zone_name[ZONENAME_MAX];
1476         dladm_status_t  status;
1477         int             ret;
1478 
1479         if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
1480                 return (dladm_errno2status(errno));
1481         if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
1482                 return (dladm_errno2status(errno));
1483         if (di_prof_init(path, &prof) != 0)
1484                 return (dladm_errno2status(errno));
1485 
1486         status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN);
1487         if (status != DLADM_STATUS_OK)
1488                 goto cleanup;
1489 
1490         if (add)
1491                 ret = di_prof_add_dev(prof, name);
1492         else
1493                 ret = di_prof_add_exclude(prof, name);
1494 
1495         if (ret != 0) {
1496                 status = dladm_errno2status(errno);
1497                 goto cleanup;
1498         }
1499 
1500         if (di_prof_commit(prof) != 0)
1501                 status = dladm_errno2status(errno);
1502 cleanup:
1503         if (prof)
1504                 di_prof_fini(prof);
1505 
1506         return (status);
1507 }
1508 
1509 /* ARGSUSED */
1510 static dladm_status_t
1511 set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1512     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1513 {
1514         dladm_status_t          status = DLADM_STATUS_OK;
1515         zoneid_t                zid_old, zid_new;
1516         dld_ioc_zid_t           *dzp;
1517 
1518         if (val_cnt != 1)
1519                 return (DLADM_STATUS_BADVALCNT);
1520 
1521         dzp = (dld_ioc_zid_t *)vdp->vd_val;
1522 
1523         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1524             NULL, &zid_old, sizeof (zid_old));
1525         if (status != DLADM_STATUS_OK)
1526                 return (status);
1527 
1528         zid_new = dzp->diz_zid;
1529         if (zid_new == zid_old)
1530                 return (DLADM_STATUS_OK);
1531 
1532         if (flags & DLADM_OPT_TRANSIENT)
1533                 dzp->diz_transient = B_TRUE;
1534 
1535         if ((status = set_public_prop(handle, pdp, linkid, vdp, val_cnt,
1536             flags, media)) != DLADM_STATUS_OK)
1537                 return (status);
1538 
1539         /*
1540          * It is okay to fail to update the /dev entry (some vanity-named
1541          * links do not have a /dev entry).
1542          */
1543         if (zid_old != GLOBAL_ZONEID) {
1544                 (void) i_dladm_update_deventry(handle, zid_old, linkid,
1545                     B_FALSE);
1546         }
1547         if (zid_new != GLOBAL_ZONEID)
1548                 (void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE);
1549 
1550         return (DLADM_STATUS_OK);
1551 }
1552 
1553 /* ARGSUSED */
1554 static dladm_status_t
1555 check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1556     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1557     datalink_media_t media)
1558 {
1559         char            *zone_name;
1560         zoneid_t        zoneid;
1561         dladm_status_t  status = DLADM_STATUS_OK;
1562         dld_ioc_zid_t   *dzp;
1563         uint_t          val_cnt = *val_cntp;
1564         val_desc_t      *vdp = *vdpp;
1565 
1566         if (val_cnt != 1)
1567                 return (DLADM_STATUS_BADVALCNT);
1568 
1569         dzp = malloc(sizeof (dld_ioc_zid_t));
1570         if (dzp == NULL)
1571                 return (DLADM_STATUS_NOMEM);
1572 
1573         zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME;
1574         if ((zoneid = getzoneidbyname(zone_name)) == -1) {
1575                 status = DLADM_STATUS_BADVAL;
1576                 goto done;
1577         }
1578 
1579         if (zoneid != GLOBAL_ZONEID) {
1580                 ushort_t        flags;
1581 
1582                 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
1583                     sizeof (flags)) < 0) {
1584                         status = dladm_errno2status(errno);
1585                         goto done;
1586                 }
1587 
1588                 if (!(flags & ZF_NET_EXCL)) {
1589                         status = DLADM_STATUS_BADVAL;
1590                         goto done;
1591                 }
1592         }
1593 
1594         (void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
1595 
1596         dzp->diz_zid = zoneid;
1597         dzp->diz_linkid = linkid;
1598 
1599         vdp->vd_val = (uintptr_t)dzp;
1600         return (DLADM_STATUS_OK);
1601 done:
1602         free(dzp);
1603         return (status);
1604 }
1605 
1606 /* ARGSUSED */
1607 static dladm_status_t
1608 get_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1609     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1610     uint_t flags, uint_t *perm_flags)
1611 {
1612         mac_resource_props_t    mrp;
1613         dladm_status_t          status;
1614 
1615         status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
1616             perm_flags, &mrp, sizeof (mrp));
1617         if (status != DLADM_STATUS_OK)
1618                 return (status);
1619 
1620         if ((mrp.mrp_mask & MRP_MAXBW) == 0) {
1621                 *val_cnt = 0;
1622                 return (DLADM_STATUS_OK);
1623         }
1624 
1625         (void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]);
1626         *val_cnt = 1;
1627         return (DLADM_STATUS_OK);
1628 }
1629 
1630 /* ARGSUSED */
1631 static dladm_status_t
1632 check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1633     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1634     datalink_media_t media)
1635 {
1636         uint64_t        *maxbw;
1637         dladm_status_t  status = DLADM_STATUS_OK;
1638         uint_t          val_cnt = *val_cntp;
1639         val_desc_t      *vdp = *vdpp;
1640 
1641         if (val_cnt != 1)
1642                 return (DLADM_STATUS_BADVALCNT);
1643 
1644         maxbw = malloc(sizeof (uint64_t));
1645         if (maxbw == NULL)
1646                 return (DLADM_STATUS_NOMEM);
1647 
1648         status = dladm_str2bw(*prop_val, maxbw);
1649         if (status != DLADM_STATUS_OK) {
1650                 free(maxbw);
1651                 return (status);
1652         }
1653 
1654         if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
1655                 free(maxbw);
1656                 return (DLADM_STATUS_MINMAXBW);
1657         }
1658 
1659         vdp->vd_val = (uintptr_t)maxbw;
1660         return (DLADM_STATUS_OK);
1661 }
1662 
1663 /* ARGSUSED */
1664 dladm_status_t
1665 extract_maxbw(val_desc_t *vdp, uint_t cnt, void *arg)
1666 {
1667         mac_resource_props_t *mrp = arg;
1668 
1669         if (vdp->vd_val == RESET_VAL) {
1670                 mrp->mrp_maxbw = MRP_MAXBW_RESETVAL;
1671         } else {
1672                 bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
1673         }
1674         mrp->mrp_mask |= MRP_MAXBW;
1675 
1676         return (DLADM_STATUS_OK);
1677 }
1678 
1679 /* ARGSUSED */
1680 static dladm_status_t
1681 get_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1682     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1683     uint_t flags, uint_t *perm_flags)
1684 {
1685         dladm_status_t          status;
1686         mac_resource_props_t    mrp;
1687         mac_propval_range_t     *pv_range;
1688         int                     err;
1689 
1690         if (strcmp(pdp->pd_name, "cpus-effective") == 0) {
1691                 status = i_dladm_get_public_prop(handle, linkid,
1692                     "resource-effective", flags, perm_flags, &mrp,
1693                     sizeof (mrp));
1694         } else {
1695                 status = i_dladm_get_public_prop(handle, linkid,
1696                     "resource", flags, perm_flags, &mrp, sizeof (mrp));
1697         }
1698 
1699         if (status != DLADM_STATUS_OK)
1700                 return (status);
1701 
1702         if (mrp.mrp_ncpus > *val_cnt)
1703                 return (DLADM_STATUS_TOOSMALL);
1704 
1705         if (mrp.mrp_ncpus == 0) {
1706                 *val_cnt = 0;
1707                 return (DLADM_STATUS_OK);
1708         }
1709 
1710         /* Sort CPU list and convert it to a mac_propval_range */
1711         status = dladm_list2range(mrp.mrp_cpu, mrp.mrp_ncpus,
1712             MAC_PROPVAL_UINT32, &pv_range);
1713         if (status != DLADM_STATUS_OK)
1714                 return (status);
1715 
1716         /* Write CPU ranges and individual CPUs */
1717         err = dladm_range2strs(pv_range, prop_val);
1718         if (err != 0) {
1719                 free(pv_range);
1720                 return (dladm_errno2status(err));
1721         }
1722 
1723         *val_cnt = pv_range->mpr_count;
1724         free(pv_range);
1725 
1726         return (DLADM_STATUS_OK);
1727 }
1728 
1729 /* ARGSUSED */
1730 static dladm_status_t
1731 check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1732     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1733     datalink_media_t media)
1734 {
1735         int                     i, j, rc;
1736         long                    nproc = sysconf(_SC_NPROCESSORS_CONF);
1737         mac_resource_props_t    mrp;
1738         mac_propval_range_t     *pv_range;
1739         uint_t                  perm_flags;
1740         uint32_t                ncpus;
1741         uint32_t                *cpus = mrp.mrp_cpu;
1742         val_desc_t              *vdp = *vdpp;
1743         val_desc_t              *newvdp;
1744         uint_t                  val_cnt = *val_cntp;
1745         dladm_status_t          status = DLADM_STATUS_OK;
1746 
1747         /* Get the current pool property */
1748         status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1749             &perm_flags, &mrp, sizeof (mrp));
1750 
1751         if (status == DLADM_STATUS_OK) {
1752                 /* Can't set cpus if a pool is set */
1753                 if (strlen(mrp.mrp_pool) != 0)
1754                         return (DLADM_STATUS_POOLCPU);
1755         }
1756 
1757         /* Read ranges and convert to mac_propval_range */
1758         status = dladm_strs2range(prop_val, val_cnt, MAC_PROPVAL_UINT32,
1759             &pv_range);
1760         if (status != DLADM_STATUS_OK)
1761                 goto done1;
1762 
1763         /* Convert mac_propval_range to a single CPU list */
1764         ncpus = MRP_NCPUS;
1765         status = dladm_range2list(pv_range, cpus, &ncpus);
1766         if (status != DLADM_STATUS_OK)
1767                 goto done1;
1768 
1769         /*
1770          * If a range of CPUs was entered, update value count and reallocate
1771          * the array of val_desc_t's.  The array allocated was sized for
1772          * indvidual elements, but needs to be reallocated to accomodate the
1773          * expanded list of CPUs.
1774          */
1775         if (val_cnt < ncpus) {
1776                 newvdp = calloc(*val_cntp, sizeof (val_desc_t));
1777                 if (newvdp == NULL) {
1778                         status = DLADM_STATUS_NOMEM;
1779                         goto done1;
1780                 }
1781                 vdp = newvdp;
1782         }
1783 
1784         /* Check if all CPUs in the list are online */
1785         for (i = 0; i < ncpus; i++) {
1786                 if (cpus[i] >= nproc) {
1787                         status = DLADM_STATUS_BADCPUID;
1788                         goto done2;
1789                 }
1790 
1791                 rc = p_online(cpus[i], P_STATUS);
1792                 if (rc < 1) {
1793                         status = DLADM_STATUS_CPUERR;
1794                         goto done2;
1795                 }
1796 
1797                 if (rc != P_ONLINE) {
1798                         status = DLADM_STATUS_CPUNOTONLINE;
1799                         goto done2;
1800                 }
1801 
1802                 vdp[i].vd_val = (uintptr_t)cpus[i];
1803         }
1804 
1805         /* Check for duplicate CPUs */
1806         for (i = 0; i < *val_cntp; i++) {
1807                 for (j = 0; j < *val_cntp; j++) {
1808                         if (i != j && vdp[i].vd_val == vdp[j].vd_val) {
1809                                 status = DLADM_STATUS_BADVAL;
1810                                 goto done2;
1811                         }
1812                 }
1813         }
1814 
1815         /* Update *val_cntp and *vdpp if everything was OK */
1816         if (val_cnt < ncpus) {
1817                 *val_cntp = ncpus;
1818                 free(*vdpp);
1819                 *vdpp = newvdp;
1820         }
1821 
1822         status = DLADM_STATUS_OK;
1823         goto done1;
1824 
1825 done2:
1826         free(newvdp);
1827 done1:
1828         free(pv_range);
1829         return (status);
1830 }
1831 
1832 /* ARGSUSED */
1833 dladm_status_t
1834 extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg)
1835 {
1836         mac_resource_props_t    *mrp = arg;
1837         int                     i;
1838 
1839         if (vdp[0].vd_val == RESET_VAL) {
1840                 bzero(&mrp->mrp_cpus, sizeof (mac_cpus_t));
1841                 mrp->mrp_mask |= MRP_CPUS;
1842                 return (DLADM_STATUS_OK);
1843         }
1844 
1845         for (i = 0; i < cnt; i++)
1846                 mrp->mrp_cpu[i] = (uint32_t)vdp[i].vd_val;
1847 
1848         mrp->mrp_ncpus = cnt;
1849         mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC);
1850         mrp->mrp_fanout_mode = MCM_CPUS;
1851         mrp->mrp_rx_intr_cpu = -1;
1852 
1853         return (DLADM_STATUS_OK);
1854 }
1855 
1856 /*
1857  * Get the pool datalink property from the kernel.  This is used
1858  * for both the user specified pool and effective pool properties.
1859  */
1860 /* ARGSUSED */
1861 static dladm_status_t
1862 get_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1863     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1864     uint_t flags, uint_t *perm_flags)
1865 {
1866         mac_resource_props_t    mrp;
1867         dladm_status_t          status;
1868 
1869         if (strcmp(pdp->pd_name, "pool-effective") == 0) {
1870                 status = i_dladm_get_public_prop(handle, linkid,
1871                     "resource-effective", flags, perm_flags, &mrp,
1872                     sizeof (mrp));
1873         } else {
1874                 status = i_dladm_get_public_prop(handle, linkid,
1875                     "resource", flags, perm_flags, &mrp, sizeof (mrp));
1876         }
1877 
1878         if (status != DLADM_STATUS_OK)
1879                 return (status);
1880 
1881         if (strlen(mrp.mrp_pool) == 0) {
1882                 (*prop_val)[0] = '\0';
1883         } else {
1884                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
1885                     "%s", mrp.mrp_pool);
1886         }
1887         *val_cnt = 1;
1888 
1889         return (DLADM_STATUS_OK);
1890 }
1891 
1892 /* ARGSUSED */
1893 static dladm_status_t
1894 check_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1895     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1896     datalink_media_t media)
1897 {
1898         pool_conf_t             *poolconf;
1899         pool_t                  *pool;
1900         mac_resource_props_t    mrp;
1901         dladm_status_t          status;
1902         uint_t                  perm_flags;
1903         char                    *poolname;
1904         val_desc_t              *vdp = *vdpp;
1905 
1906         /* Get the current cpus property */
1907         status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1908             &perm_flags, &mrp, sizeof (mrp));
1909 
1910         if (status == DLADM_STATUS_OK) {
1911                 /* Can't set pool if cpus are set */
1912                 if (mrp.mrp_ncpus != 0)
1913                         return (DLADM_STATUS_POOLCPU);
1914         }
1915 
1916         poolname = malloc(sizeof (mrp.mrp_pool));
1917         if (poolname == NULL)
1918                 return (DLADM_STATUS_NOMEM);
1919 
1920         /* Check for pool's availability if not booting */
1921         if ((flags & DLADM_OPT_BOOT) == 0) {
1922 
1923                 /* Allocate and open pool configuration */
1924                 if ((poolconf = pool_conf_alloc()) == NULL)
1925                         return (DLADM_STATUS_BADVAL);
1926 
1927                 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY)
1928                     != PO_SUCCESS) {
1929                         pool_conf_free(poolconf);
1930                         return (DLADM_STATUS_BADVAL);
1931                 }
1932 
1933                 /* Look for pool name */
1934                 if ((pool = pool_get_pool(poolconf, *prop_val)) == NULL) {
1935                         pool_conf_free(poolconf);
1936                         return (DLADM_STATUS_BADVAL);
1937                 }
1938 
1939                 pool_conf_free(poolconf);
1940                 free(pool);
1941         }
1942 
1943         (void) strlcpy(poolname, *prop_val, sizeof (mrp.mrp_pool));
1944         vdp->vd_val = (uintptr_t)poolname;
1945 
1946         return (DLADM_STATUS_OK);
1947 }
1948 
1949 /* ARGSUSED */
1950 dladm_status_t
1951 extract_pool(val_desc_t *vdp, uint_t cnt, void *arg)
1952 {
1953         mac_resource_props_t    *mrp = (mac_resource_props_t *)arg;
1954 
1955         if (vdp->vd_val == RESET_VAL) {
1956                 bzero(&mrp->mrp_pool, sizeof (mrp->mrp_pool));
1957                 mrp->mrp_mask |= MRP_POOL;
1958                 return (DLADM_STATUS_OK);
1959         }
1960 
1961         (void) strlcpy(mrp->mrp_pool, (char *)vdp->vd_val,
1962             sizeof (mrp->mrp_pool));
1963         mrp->mrp_mask |= MRP_POOL;
1964         /*
1965          * Use MCM_CPUS since the fanout count is not user specified
1966          * and will be determined by the cpu list generated from the
1967          * pool.
1968          */
1969         mrp->mrp_fanout_mode = MCM_CPUS;
1970 
1971         return (DLADM_STATUS_OK);
1972 }
1973 
1974 /* ARGSUSED */
1975 static dladm_status_t
1976 get_priority(dladm_handle_t handle, prop_desc_t *pdp,
1977     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
1978     datalink_media_t media, uint_t flags, uint_t *perm_flags)
1979 {
1980         mac_resource_props_t    mrp;
1981         mac_priority_level_t    pri;
1982         dladm_status_t          status;
1983 
1984         status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
1985             perm_flags, &mrp, sizeof (mrp));
1986         if (status != DLADM_STATUS_OK)
1987                 return (status);
1988 
1989         pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH :
1990             mrp.mrp_priority;
1991 
1992         (void) dladm_pri2str(pri, prop_val[0]);
1993         *val_cnt = 1;
1994         return (DLADM_STATUS_OK);
1995 }
1996 
1997 /* ARGSUSED */
1998 dladm_status_t
1999 extract_priority(val_desc_t *vdp, uint_t cnt, void *arg)
2000 {
2001         mac_resource_props_t *mrp = arg;
2002 
2003         if (cnt != 1)
2004                 return (DLADM_STATUS_BADVAL);
2005 
2006         mrp->mrp_priority = (mac_priority_level_t)vdp->vd_val;
2007         mrp->mrp_mask |= MRP_PRIORITY;
2008 
2009         return (DLADM_STATUS_OK);
2010 }
2011 
2012 /*
2013  * Determines the size of the structure that needs to be sent to drivers
2014  * for retrieving the property range values.
2015  */
2016 static int
2017 i_dladm_range_size(mac_propval_range_t *r, size_t *sz, uint_t *rcount)
2018 {
2019         uint_t count = r->mpr_count;
2020 
2021         *sz = sizeof (mac_propval_range_t);
2022         *rcount = count;
2023         --count;
2024 
2025         switch (r->mpr_type) {
2026         case MAC_PROPVAL_UINT32:
2027                 *sz += (count * sizeof (mac_propval_uint32_range_t));
2028                 return (0);
2029         default:
2030                 break;
2031         }
2032         *sz = 0;
2033         *rcount = 0;
2034         return (EINVAL);
2035 }
2036 
2037 
2038 /* ARGSUSED */
2039 static dladm_status_t
2040 check_rings(dladm_handle_t handle, prop_desc_t *pdp,
2041     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2042     val_desc_t **vp, datalink_media_t media)
2043 {
2044         uint_t          val_cnt = *val_cntp;
2045         val_desc_t      *v = *vp;
2046 
2047         if (val_cnt != 1)
2048                 return (DLADM_STATUS_BADVAL);
2049         if (strncasecmp(prop_val[0], "hw", strlen("hw")) == 0) {
2050                 v->vd_val = UNSPEC_VAL;
2051         } else if (strncasecmp(prop_val[0], "sw", strlen("sw")) == 0) {
2052                 v->vd_val = 0;
2053         } else {
2054                 v->vd_val = strtoul(prop_val[0], NULL, 0);
2055                 if (v->vd_val == 0)
2056                         return (DLADM_STATUS_BADVAL);
2057         }
2058         return (DLADM_STATUS_OK);
2059 }
2060 
2061 /* ARGSUSED */
2062 static dladm_status_t
2063 get_rings_range(dladm_handle_t handle, prop_desc_t *pdp,
2064     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2065     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2066 {
2067         dld_ioc_macprop_t *dip;
2068         dladm_status_t status = DLADM_STATUS_OK;
2069         mac_propval_range_t *rangep;
2070         size_t  sz;
2071         mac_propval_uint32_range_t *ur;
2072 
2073         sz = sizeof (mac_propval_range_t);
2074 
2075         if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
2076             &status)) == NULL)
2077                 return (status);
2078 
2079         status = i_dladm_macprop(handle, dip, B_FALSE);
2080         if (status != DLADM_STATUS_OK)
2081                 return (status);
2082 
2083         rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
2084         *val_cnt = 1;
2085         ur = &rangep->mpr_range_uint32[0];
2086         /* This is the case where the dev doesn't have any rings/groups */
2087         if (rangep->mpr_count == 0) {
2088                 (*prop_val)[0] = '\0';
2089         /*
2090          * This is the case where the dev supports rings, but static
2091          * grouping.
2092          */
2093         } else if (ur->mpur_min == ur->mpur_max &&
2094             ur->mpur_max == 0) {
2095                 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw");
2096         /*
2097          * This is the case where the dev supports rings and dynamic
2098          * grouping, but has only one value (say 2 rings and 2 groups).
2099          */
2100         } else if (ur->mpur_min == ur->mpur_max) {
2101                 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw,%d",
2102                     ur->mpur_min);
2103         /*
2104          * This is the case where the dev supports rings and dynamic
2105          * grouping and has a range of rings.
2106          */
2107         } else {
2108                 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX,
2109                     "sw,hw,<%ld-%ld>", ur->mpur_min, ur->mpur_max);
2110         }
2111         free(dip);
2112         return (status);
2113 }
2114 
2115 
2116 /* ARGSUSED */
2117 static dladm_status_t
2118 get_rxrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2119     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2120     uint_t flags, uint_t *perm_flags)
2121 {
2122         mac_resource_props_t    mrp;
2123         dladm_status_t          status;
2124         uint32_t                nrings = 0;
2125 
2126         /*
2127          * Get the number of (effective-)rings from the resource property.
2128          */
2129         if (strcmp(pdp->pd_name, "rxrings-effective") == 0) {
2130                 status = i_dladm_get_public_prop(handle, linkid,
2131                     "resource-effective", flags, perm_flags, &mrp,
2132                     sizeof (mrp));
2133         } else {
2134                 /*
2135                  * Get the permissions from the "rxrings" property.
2136                  */
2137                 status = i_dladm_get_public_prop(handle, linkid, "rxrings",
2138                     flags, perm_flags, NULL, 0);
2139                 if (status != DLADM_STATUS_OK)
2140                         return (status);
2141 
2142                 status = i_dladm_get_public_prop(handle, linkid,
2143                     "resource", flags, NULL, &mrp, sizeof (mrp));
2144         }
2145 
2146         if (status != DLADM_STATUS_OK)
2147                 return (status);
2148 
2149         if ((mrp.mrp_mask & MRP_RX_RINGS) == 0) {
2150                 *val_cnt = 0;
2151                 return (DLADM_STATUS_OK);
2152         }
2153         nrings = mrp.mrp_nrxrings;
2154         *val_cnt = 1;
2155         if (mrp.mrp_mask & MRP_RXRINGS_UNSPEC)
2156                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2157         else if (nrings == 0)
2158                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2159         else
2160                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2161         return (DLADM_STATUS_OK);
2162 }
2163 
2164 /* ARGSUSED */
2165 dladm_status_t
2166 extract_rxrings(val_desc_t *vdp, uint_t cnt, void *arg)
2167 {
2168         mac_resource_props_t    *mrp = (mac_resource_props_t *)arg;
2169 
2170         mrp->mrp_nrxrings = 0;
2171         if (vdp->vd_val == RESET_VAL)
2172                 mrp->mrp_mask = MRP_RINGS_RESET;
2173         else if (vdp->vd_val == UNSPEC_VAL)
2174                 mrp->mrp_mask = MRP_RXRINGS_UNSPEC;
2175         else
2176                 mrp->mrp_nrxrings = vdp->vd_val;
2177         mrp->mrp_mask |= MRP_RX_RINGS;
2178 
2179         return (DLADM_STATUS_OK);
2180 }
2181 
2182 /* ARGSUSED */
2183 static dladm_status_t
2184 get_txrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2185     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2186     uint_t flags, uint_t *perm_flags)
2187 {
2188         mac_resource_props_t    mrp;
2189         dladm_status_t          status;
2190         uint32_t                nrings = 0;
2191 
2192 
2193         /*
2194          * Get the number of (effective-)rings from the resource property.
2195          */
2196         if (strcmp(pdp->pd_name, "txrings-effective") == 0) {
2197                 status = i_dladm_get_public_prop(handle, linkid,
2198                     "resource-effective", flags, perm_flags, &mrp,
2199                     sizeof (mrp));
2200         } else {
2201                 /*
2202                  * Get the permissions from the "txrings" property.
2203                  */
2204                 status = i_dladm_get_public_prop(handle, linkid, "txrings",
2205                     flags, perm_flags, NULL, 0);
2206                 if (status != DLADM_STATUS_OK)
2207                         return (status);
2208 
2209                 /*
2210                  * Get the number of rings from the "resource" property.
2211                  */
2212                 status = i_dladm_get_public_prop(handle, linkid, "resource",
2213                     flags, NULL, &mrp, sizeof (mrp));
2214         }
2215 
2216         if (status != DLADM_STATUS_OK)
2217                 return (status);
2218 
2219         if ((mrp.mrp_mask & MRP_TX_RINGS) == 0) {
2220                 *val_cnt = 0;
2221                 return (DLADM_STATUS_OK);
2222         }
2223         nrings = mrp.mrp_ntxrings;
2224         *val_cnt = 1;
2225         if (mrp.mrp_mask & MRP_TXRINGS_UNSPEC)
2226                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2227         else if (nrings == 0)
2228                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2229         else
2230                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2231         return (DLADM_STATUS_OK);
2232 }
2233 
2234 /* ARGSUSED */
2235 dladm_status_t
2236 extract_txrings(val_desc_t *vdp, uint_t cnt, void *arg)
2237 {
2238         mac_resource_props_t    *mrp = (mac_resource_props_t *)arg;
2239 
2240         mrp->mrp_ntxrings = 0;
2241         if (vdp->vd_val == RESET_VAL)
2242                 mrp->mrp_mask = MRP_RINGS_RESET;
2243         else if (vdp->vd_val == UNSPEC_VAL)
2244                 mrp->mrp_mask = MRP_TXRINGS_UNSPEC;
2245         else
2246                 mrp->mrp_ntxrings = vdp->vd_val;
2247         mrp->mrp_mask |= MRP_TX_RINGS;
2248 
2249         return (DLADM_STATUS_OK);
2250 }
2251 
2252 /* ARGSUSED */
2253 static dladm_status_t
2254 get_cntavail(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2255     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
2256     uint_t *perm_flags)
2257 {
2258         if (flags & DLD_PROP_DEFAULT)
2259                 return (DLADM_STATUS_NOTDEFINED);
2260 
2261         return (get_uint32(handle, pdp, linkid, prop_val, val_cnt, media,
2262             flags, perm_flags));
2263 }
2264 
2265 /* ARGSUSED */
2266 static dladm_status_t
2267 set_resource(dladm_handle_t handle, prop_desc_t *pdp,
2268     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt,
2269     uint_t flags, datalink_media_t media)
2270 {
2271         mac_resource_props_t    mrp;
2272         dladm_status_t          status = DLADM_STATUS_OK;
2273         dld_ioc_macprop_t       *dip;
2274         int                     i;
2275 
2276         bzero(&mrp, sizeof (mac_resource_props_t));
2277         dip = i_dladm_buf_alloc_by_name(0, linkid, "resource",
2278             flags, &status);
2279 
2280         if (dip == NULL)
2281                 return (status);
2282 
2283         for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
2284                 resource_prop_t *rp = &rsrc_prop_table[i];
2285 
2286                 if (strcmp(pdp->pd_name, rp->rp_name) != 0)
2287                         continue;
2288 
2289                 status = rp->rp_extract(vdp, val_cnt, &mrp);
2290                 if (status != DLADM_STATUS_OK)
2291                         goto done;
2292 
2293                 break;
2294         }
2295 
2296         (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
2297         status = i_dladm_macprop(handle, dip, B_TRUE);
2298 
2299 done:
2300         free(dip);
2301         return (status);
2302 }
2303 
2304 /* ARGSUSED */
2305 static dladm_status_t
2306 get_protection(dladm_handle_t handle, prop_desc_t *pdp,
2307     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2308     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2309 {
2310         mac_resource_props_t    mrp;
2311         mac_protect_t           *p;
2312         dladm_status_t          status;
2313         uint32_t                i, cnt = 0, setbits[32];
2314 
2315         status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2316             perm_flags, &mrp, sizeof (mrp));
2317         if (status != DLADM_STATUS_OK)
2318                 return (status);
2319 
2320         p = &mrp.mrp_protect;
2321         if ((mrp.mrp_mask & MRP_PROTECT) == 0) {
2322                 *val_cnt = 0;
2323                 return (DLADM_STATUS_OK);
2324         }
2325         dladm_find_setbits32(p->mp_types, setbits, &cnt);
2326         if (cnt > *val_cnt)
2327                 return (DLADM_STATUS_BADVALCNT);
2328 
2329         for (i = 0; i < cnt; i++)
2330                 (void) dladm_protect2str(setbits[i], prop_val[i]);
2331 
2332         *val_cnt = cnt;
2333         return (DLADM_STATUS_OK);
2334 }
2335 
2336 /* ARGSUSED */
2337 static dladm_status_t
2338 get_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2339     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2340     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2341 {
2342         mac_resource_props_t    mrp;
2343         mac_protect_t           *p;
2344         dladm_status_t          status;
2345         int                     i;
2346 
2347         status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2348             perm_flags, &mrp, sizeof (mrp));
2349         if (status != DLADM_STATUS_OK)
2350                 return (status);
2351 
2352         p = &mrp.mrp_protect;
2353         if (p->mp_ipaddrcnt == 0) {
2354                 *val_cnt = 0;
2355                 return (DLADM_STATUS_OK);
2356         }
2357         if (p->mp_ipaddrcnt > *val_cnt)
2358                 return (DLADM_STATUS_BADVALCNT);
2359 
2360         for (i = 0; i < p->mp_ipaddrcnt; i++) {
2361                 int len;
2362                 if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) {
2363                         ipaddr_t        v4addr;
2364 
2365                         v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr);
2366                         (void) dladm_ipv4addr2str(&v4addr, prop_val[i]);
2367                 } else {
2368                         (void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr,
2369                             prop_val[i]);
2370                 }
2371                 len = strlen(prop_val[i]);
2372                 (void) sprintf(prop_val[i] + len, "/%d",
2373                     p->mp_ipaddrs[i].ip_netmask);
2374         }
2375         *val_cnt = p->mp_ipaddrcnt;
2376         return (DLADM_STATUS_OK);
2377 }
2378 
2379 dladm_status_t
2380 extract_protection(val_desc_t *vdp, uint_t cnt, void *arg)
2381 {
2382         mac_resource_props_t    *mrp = arg;
2383         uint32_t                types = 0;
2384         int                     i;
2385 
2386         for (i = 0; i < cnt; i++)
2387                 types |= (uint32_t)vdp[i].vd_val;
2388 
2389         mrp->mrp_protect.mp_types = types;
2390         mrp->mrp_mask |= MRP_PROTECT;
2391         return (DLADM_STATUS_OK);
2392 }
2393 
2394 dladm_status_t
2395 extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg)
2396 {
2397         mac_resource_props_t    *mrp = arg;
2398         mac_protect_t           *p = &mrp->mrp_protect;
2399         int                     i;
2400 
2401         if (vdp->vd_val == 0) {
2402                 cnt = (uint_t)-1;
2403         } else {
2404                 for (i = 0; i < cnt; i++) {
2405                         bcopy((void *)vdp[i].vd_val, &p->mp_ipaddrs[i],
2406                             sizeof (mac_ipaddr_t));
2407                 }
2408         }
2409         p->mp_ipaddrcnt = cnt;
2410         mrp->mrp_mask |= MRP_PROTECT;
2411         return (DLADM_STATUS_OK);
2412 }
2413 
2414 static dladm_status_t
2415 check_single_ip(char *buf, mac_ipaddr_t *addr)
2416 {
2417         dladm_status_t  status;
2418         ipaddr_t        v4addr;
2419         in6_addr_t      v6addr;
2420         boolean_t       isv4 = B_TRUE;
2421         char            *p;
2422         uint32_t        mask = 0;
2423 
2424         /*
2425          * If the IP address is in CIDR format, parse the bits component
2426          * seperately. An address in this style will be used to indicate an
2427          * entire subnet, so it must be a network number with no host address.
2428          */
2429         if ((p = strchr(buf, '/')) != NULL) {
2430                 char *end = NULL;
2431 
2432                 *p++ = '\0';
2433                 if (!isdigit(*p))
2434                         return (DLADM_STATUS_INVALID_IP);
2435                 mask = strtol(p, &end, 10);
2436                 if (end != NULL && *end != '\0')
2437                         return (DLADM_STATUS_INVALID_IP);
2438                 if (mask > 128|| mask < 1)
2439                         return (DLADM_STATUS_INVALID_IP);
2440         }
2441 
2442         status = dladm_str2ipv4addr(buf, &v4addr);
2443         if (status == DLADM_STATUS_INVALID_IP) {
2444                 status = dladm_str2ipv6addr(buf, &v6addr);
2445                 if (status == DLADM_STATUS_OK)
2446                         isv4 = B_FALSE;
2447         }
2448         if (status != DLADM_STATUS_OK)
2449                 return (status);
2450 
2451         if (isv4) {
2452                 if (v4addr == INADDR_ANY)
2453                         return (DLADM_STATUS_INVALID_IP);
2454 
2455                 IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr);
2456                 addr->ip_version = IPV4_VERSION;
2457                 if (p != NULL) {
2458                         uint32_t smask;
2459 
2460                         /*
2461                          * Validate the netmask is in the proper range for v4
2462                          */
2463                         if (mask > 32 || mask < 1)
2464                                 return (DLADM_STATUS_INVALID_IP);
2465 
2466                         /*
2467                          * We have a CIDR style address, confirm that only the
2468                          * network number is set.
2469                          */
2470                         smask = 0xFFFFFFFFu << (32 - mask);
2471                         if (htonl(v4addr) & ~smask)
2472                                 return (DLADM_STATUS_INVALID_IP);
2473                 } else {
2474                         mask = 32;
2475                 }
2476                 addr->ip_netmask = mask;
2477         } else {
2478                 if (IN6_IS_ADDR_UNSPECIFIED(&v6addr))
2479                         return (DLADM_STATUS_INVALID_IP);
2480 
2481                 if (IN6_IS_ADDR_V4MAPPED_ANY(&v6addr))
2482                         return (DLADM_STATUS_INVALID_IP);
2483 
2484                 if (p != NULL) {
2485                         int i, off, high;
2486 
2487                         /*
2488                          * Note that the address in our buffer is stored in
2489                          * network byte order.
2490                          */
2491                         off = 0;
2492                         for (i = 3; i >= 0; i--) {
2493                                 high = ffsl(ntohl(v6addr._S6_un._S6_u32[i]));
2494                                 if (high != 0)
2495                                         break;
2496                                 off += 32;
2497                         }
2498                         off += high;
2499                         if (128 - off >= mask)
2500                                 return (DLADM_STATUS_INVALID_IP);
2501                 } else {
2502                         mask = 128;
2503                 }
2504 
2505                 addr->ip_addr = v6addr;
2506                 addr->ip_version = IPV6_VERSION;
2507                 addr->ip_netmask = mask;
2508         }
2509         return (DLADM_STATUS_OK);
2510 }
2511 
2512 /* ARGSUSED */
2513 static dladm_status_t
2514 check_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2515     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2516     val_desc_t **vdpp, datalink_media_t media)
2517 {
2518         dladm_status_t  status;
2519         mac_ipaddr_t    *addr;
2520         int             i;
2521         uint_t          val_cnt = *val_cntp;
2522         val_desc_t      *vdp = *vdpp;
2523 
2524         if (val_cnt > MPT_MAXIPADDR)
2525                 return (DLADM_STATUS_BADVALCNT);
2526 
2527         for (i = 0; i < val_cnt; i++) {
2528                 if ((addr = calloc(1, sizeof (mac_ipaddr_t))) == NULL) {
2529                         status = DLADM_STATUS_NOMEM;
2530                         goto fail;
2531                 }
2532                 vdp[i].vd_val = (uintptr_t)addr;
2533 
2534                 status = check_single_ip(prop_val[i], addr);
2535                 if (status != DLADM_STATUS_OK)
2536                         goto fail;
2537         }
2538         return (DLADM_STATUS_OK);
2539 
2540 fail:
2541         for (i = 0; i < val_cnt; i++) {
2542                 free((void *)vdp[i].vd_val);
2543                 vdp[i].vd_val = NULL;
2544         }
2545         return (status);
2546 }
2547 
2548 static void
2549 dladm_cid2str(mac_dhcpcid_t *cid, char *buf)
2550 {
2551         char    tmp_buf[DLADM_STRSIZE];
2552         uint_t  hexlen;
2553 
2554         switch (cid->dc_form) {
2555         case CIDFORM_TYPED: {
2556                 uint16_t        duidtype, hwtype;
2557                 uint32_t        timestamp, ennum;
2558                 char            *lladdr;
2559 
2560                 if (cid->dc_len < sizeof (duidtype))
2561                         goto fail;
2562 
2563                 bcopy(cid->dc_id, &duidtype, sizeof (duidtype));
2564                 duidtype = ntohs(duidtype);
2565                 switch (duidtype) {
2566                 case DHCPV6_DUID_LLT: {
2567                         duid_llt_t      llt;
2568 
2569                         if (cid->dc_len < sizeof (llt))
2570                                 goto fail;
2571 
2572                         bcopy(cid->dc_id, &llt, sizeof (llt));
2573                         hwtype = ntohs(llt.dllt_hwtype);
2574                         timestamp = ntohl(llt.dllt_time);
2575                         lladdr = _link_ntoa(cid->dc_id + sizeof (llt),
2576                             NULL, cid->dc_len - sizeof (llt), IFT_OTHER);
2577                         if (lladdr == NULL)
2578                                 goto fail;
2579 
2580                         (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%d.%s",
2581                             duidtype, hwtype, timestamp, lladdr);
2582                         free(lladdr);
2583                         break;
2584                 }
2585                 case DHCPV6_DUID_EN: {
2586                         duid_en_t       en;
2587 
2588                         if (cid->dc_len < sizeof (en))
2589                                 goto fail;
2590 
2591                         bcopy(cid->dc_id, &en, sizeof (en));
2592                         ennum = DHCPV6_GET_ENTNUM(&en);
2593                         hexlen = sizeof (tmp_buf);
2594                         if (octet_to_hexascii(cid->dc_id + sizeof (en),
2595                             cid->dc_len - sizeof (en), tmp_buf, &hexlen) != 0)
2596                                 goto fail;
2597 
2598                         (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2599                             duidtype, ennum, tmp_buf);
2600                         break;
2601                 }
2602                 case DHCPV6_DUID_LL: {
2603                         duid_ll_t       ll;
2604 
2605                         if (cid->dc_len < sizeof (ll))
2606                                 goto fail;
2607 
2608                         bcopy(cid->dc_id, &ll, sizeof (ll));
2609                         hwtype = ntohs(ll.dll_hwtype);
2610                         lladdr = _link_ntoa(cid->dc_id + sizeof (ll),
2611                             NULL, cid->dc_len - sizeof (ll), IFT_OTHER);
2612                         if (lladdr == NULL)
2613                                 goto fail;
2614 
2615                         (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2616                             duidtype, hwtype, lladdr);
2617                         free(lladdr);
2618                         break;
2619                 }
2620                 default: {
2621                         hexlen = sizeof (tmp_buf);
2622                         if (octet_to_hexascii(cid->dc_id + sizeof (duidtype),
2623                             cid->dc_len - sizeof (duidtype),
2624                             tmp_buf, &hexlen) != 0)
2625                                 goto fail;
2626 
2627                         (void) snprintf(buf, DLADM_STRSIZE, "%d.%s",
2628                             duidtype, tmp_buf);
2629                 }
2630                 }
2631                 break;
2632         }
2633         case CIDFORM_HEX: {
2634                 hexlen = sizeof (tmp_buf);
2635                 if (octet_to_hexascii(cid->dc_id, cid->dc_len,
2636                     tmp_buf, &hexlen) != 0)
2637                         goto fail;
2638 
2639                 (void) snprintf(buf, DLADM_STRSIZE, "0x%s", tmp_buf);
2640                 break;
2641         }
2642         case CIDFORM_STR: {
2643                 int     i;
2644 
2645                 for (i = 0; i < cid->dc_len; i++) {
2646                         if (!isprint(cid->dc_id[i]))
2647                                 goto fail;
2648                 }
2649                 (void) snprintf(buf, DLADM_STRSIZE, "%s", cid->dc_id);
2650                 break;
2651         }
2652         default:
2653                 goto fail;
2654         }
2655         return;
2656 
2657 fail:
2658         (void) snprintf(buf, DLADM_STRSIZE, "<unknown>");
2659 }
2660 
2661 static dladm_status_t
2662 dladm_str2cid(char *buf, mac_dhcpcid_t *cid)
2663 {
2664         char    *ptr = buf;
2665         char    tmp_buf[DLADM_STRSIZE];
2666         uint_t  hexlen, cidlen;
2667 
2668         bzero(cid, sizeof (*cid));
2669         if (isdigit(*ptr) &&
2670             ptr[strspn(ptr, "0123456789")] == '.') {
2671                 char    *cp;
2672                 ulong_t duidtype;
2673                 ulong_t subtype;
2674                 ulong_t timestamp;
2675                 uchar_t *lladdr;
2676                 int     addrlen;
2677 
2678                 errno = 0;
2679                 duidtype = strtoul(ptr, &cp, 0);
2680                 if (ptr == cp || errno != 0 || *cp != '.' ||
2681                     duidtype > USHRT_MAX)
2682                         return (DLADM_STATUS_BADARG);
2683                 ptr = cp + 1;
2684 
2685                 if (duidtype != 0 && duidtype <= DHCPV6_DUID_LL) {
2686                         errno = 0;
2687                         subtype = strtoul(ptr, &cp, 0);
2688                         if (ptr == cp || errno != 0 || *cp != '.')
2689                                 return (DLADM_STATUS_BADARG);
2690                         ptr = cp + 1;
2691                 }
2692                 switch (duidtype) {
2693                 case DHCPV6_DUID_LLT: {
2694                         duid_llt_t      llt;
2695 
2696                         errno = 0;
2697                         timestamp = strtoul(ptr, &cp, 0);
2698                         if (ptr == cp || errno != 0 || *cp != '.')
2699                                 return (DLADM_STATUS_BADARG);
2700 
2701                         ptr = cp + 1;
2702                         lladdr = _link_aton(ptr, &addrlen);
2703                         if (lladdr == NULL)
2704                                 return (DLADM_STATUS_BADARG);
2705 
2706                         cidlen = sizeof (llt) + addrlen;
2707                         if (cidlen > sizeof (cid->dc_id)) {
2708                                 free(lladdr);
2709                                 return (DLADM_STATUS_TOOSMALL);
2710                         }
2711                         llt.dllt_dutype = htons(duidtype);
2712                         llt.dllt_hwtype = htons(subtype);
2713                         llt.dllt_time = htonl(timestamp);
2714                         bcopy(&llt, cid->dc_id, sizeof (llt));
2715                         bcopy(lladdr, cid->dc_id + sizeof (llt), addrlen);
2716                         free(lladdr);
2717                         break;
2718                 }
2719                 case DHCPV6_DUID_LL: {
2720                         duid_ll_t       ll;
2721 
2722                         lladdr = _link_aton(ptr, &addrlen);
2723                         if (lladdr == NULL)
2724                                 return (DLADM_STATUS_BADARG);
2725 
2726                         cidlen = sizeof (ll) + addrlen;
2727                         if (cidlen > sizeof (cid->dc_id)) {
2728                                 free(lladdr);
2729                                 return (DLADM_STATUS_TOOSMALL);
2730                         }
2731                         ll.dll_dutype = htons(duidtype);
2732                         ll.dll_hwtype = htons(subtype);
2733                         bcopy(&ll, cid->dc_id, sizeof (ll));
2734                         bcopy(lladdr, cid->dc_id + sizeof (ll), addrlen);
2735                         free(lladdr);
2736                         break;
2737                 }
2738                 default: {
2739                         hexlen = sizeof (tmp_buf);
2740                         if (hexascii_to_octet(ptr, strlen(ptr),
2741                             tmp_buf, &hexlen) != 0)
2742                                 return (DLADM_STATUS_BADARG);
2743 
2744                         if (duidtype == DHCPV6_DUID_EN) {
2745                                 duid_en_t       en;
2746 
2747                                 en.den_dutype = htons(duidtype);
2748                                 DHCPV6_SET_ENTNUM(&en, subtype);
2749 
2750                                 cidlen = sizeof (en) + hexlen;
2751                                 if (cidlen > sizeof (cid->dc_id))
2752                                         return (DLADM_STATUS_TOOSMALL);
2753 
2754                                 bcopy(&en, cid->dc_id, sizeof (en));
2755                                 bcopy(tmp_buf, cid->dc_id + sizeof (en),
2756                                     hexlen);
2757                         } else {
2758                                 uint16_t        dutype = htons(duidtype);
2759 
2760                                 cidlen = sizeof (dutype) + hexlen;
2761                                 if (cidlen > sizeof (cid->dc_id))
2762                                         return (DLADM_STATUS_TOOSMALL);
2763 
2764                                 bcopy(&dutype, cid->dc_id, sizeof (dutype));
2765                                 bcopy(tmp_buf, cid->dc_id + sizeof (dutype),
2766                                     hexlen);
2767                         }
2768                         break;
2769                 }
2770                 }
2771                 cid->dc_form = CIDFORM_TYPED;
2772         } else if (strncasecmp("0x", ptr, 2) == 0 && ptr[2] != '\0') {
2773                 ptr += 2;
2774                 hexlen = sizeof (tmp_buf);
2775                 if (hexascii_to_octet(ptr, strlen(ptr), tmp_buf,
2776                     &hexlen) != 0) {
2777                         return (DLADM_STATUS_BADARG);
2778                 }
2779                 cidlen = hexlen;
2780                 if (cidlen > sizeof (cid->dc_id))
2781                         return (DLADM_STATUS_TOOSMALL);
2782 
2783                 bcopy(tmp_buf, cid->dc_id, cidlen);
2784                 cid->dc_form = CIDFORM_HEX;
2785         } else {
2786                 cidlen = strlen(ptr);
2787                 if (cidlen > sizeof (cid->dc_id))
2788                         return (DLADM_STATUS_TOOSMALL);
2789 
2790                 bcopy(ptr, cid->dc_id, cidlen);
2791                 cid->dc_form = CIDFORM_STR;
2792         }
2793         cid->dc_len = cidlen;
2794         return (DLADM_STATUS_OK);
2795 }
2796 
2797 /* ARGSUSED */
2798 static dladm_status_t
2799 get_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2800     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2801     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2802 {
2803         mac_resource_props_t    mrp;
2804         mac_protect_t           *p;
2805         dladm_status_t          status;
2806         int                     i;
2807 
2808         status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2809             perm_flags, &mrp, sizeof (mrp));
2810         if (status != DLADM_STATUS_OK)
2811                 return (status);
2812 
2813         p = &mrp.mrp_protect;
2814         if (p->mp_cidcnt == 0) {
2815                 *val_cnt = 0;
2816                 return (DLADM_STATUS_OK);
2817         }
2818         if (p->mp_cidcnt > *val_cnt)
2819                 return (DLADM_STATUS_BADVALCNT);
2820 
2821         for (i = 0; i < p->mp_cidcnt; i++) {
2822                 mac_dhcpcid_t   *cid = &p->mp_cids[i];
2823 
2824                 dladm_cid2str(cid, prop_val[i]);
2825         }
2826         *val_cnt = p->mp_cidcnt;
2827         return (DLADM_STATUS_OK);
2828 }
2829 
2830 dladm_status_t
2831 extract_allowedcids(val_desc_t *vdp, uint_t cnt, void *arg)
2832 {
2833         mac_resource_props_t    *mrp = arg;
2834         mac_protect_t           *p = &mrp->mrp_protect;
2835         int                     i;
2836 
2837         if (vdp->vd_val == 0) {
2838                 cnt = (uint_t)-1;
2839         } else {
2840                 for (i = 0; i < cnt; i++) {
2841                         bcopy((void *)vdp[i].vd_val, &p->mp_cids[i],
2842                             sizeof (mac_dhcpcid_t));
2843                 }
2844         }
2845         p->mp_cidcnt = cnt;
2846         mrp->mrp_mask |= MRP_PROTECT;
2847         return (DLADM_STATUS_OK);
2848 }
2849 
2850 /* ARGSUSED */
2851 static dladm_status_t
2852 check_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2853     datalink_id_t linkid, char **prop_val, uint_t *val_cntp,
2854     uint_t flags, val_desc_t **vdpp, datalink_media_t media)
2855 {
2856         dladm_status_t  status;
2857         mac_dhcpcid_t   *cid;
2858         int             i;
2859         uint_t          val_cnt = *val_cntp;
2860         val_desc_t      *vdp = *vdpp;
2861 
2862         if (val_cnt > MPT_MAXCID)
2863                 return (DLADM_STATUS_BADVALCNT);
2864 
2865         for (i = 0; i < val_cnt; i++) {
2866                 if ((cid = calloc(1, sizeof (mac_dhcpcid_t))) == NULL) {
2867                         status = DLADM_STATUS_NOMEM;
2868                         goto fail;
2869                 }
2870                 vdp[i].vd_val = (uintptr_t)cid;
2871 
2872                 status = dladm_str2cid(prop_val[i], cid);
2873                 if (status != DLADM_STATUS_OK)
2874                         goto fail;
2875         }
2876         return (DLADM_STATUS_OK);
2877 
2878 fail:
2879         for (i = 0; i < val_cnt; i++) {
2880                 free((void *)vdp[i].vd_val);
2881                 vdp[i].vd_val = NULL;
2882         }
2883         return (status);
2884 }
2885 
2886 /* ARGSUSED */
2887 static dladm_status_t
2888 get_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
2889     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2890     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2891 {
2892         mac_secondary_addr_t    sa;
2893         dladm_status_t          status;
2894         int                     i;
2895 
2896         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2897             perm_flags, &sa, sizeof (sa));
2898         if (status != DLADM_STATUS_OK)
2899                 return (status);
2900 
2901         if (sa.ms_addrcnt > *val_cnt)
2902                 return (DLADM_STATUS_BADVALCNT);
2903 
2904         for (i = 0; i < sa.ms_addrcnt; i++) {
2905                 if (dladm_aggr_macaddr2str(
2906                     (const unsigned char *)&sa.ms_addrs[i], prop_val[i]) ==
2907                     NULL) {
2908                         *val_cnt = i;
2909                         return (DLADM_STATUS_NOMEM);
2910                 }
2911         }
2912         *val_cnt = sa.ms_addrcnt;
2913         return (DLADM_STATUS_OK);
2914 }
2915 
2916 /* ARGSUSED */
2917 static dladm_status_t
2918 check_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
2919     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2920     val_desc_t **vdpp, datalink_media_t media)
2921 {
2922         dladm_status_t  status;
2923         uchar_t         *addr;
2924         uint_t          len = 0;
2925         int             i;
2926         uint_t          val_cnt = *val_cntp;
2927         val_desc_t      *vdp = *vdpp;
2928 
2929         if (val_cnt >= MPT_MAXMACADDR)
2930                 return (DLADM_STATUS_BADVALCNT);
2931 
2932         for (i = 0; i < val_cnt; i++) {
2933                 addr = _link_aton(prop_val[i], (int *)&len);
2934                 if (addr == NULL) {
2935                         if (len == (uint_t)-1)
2936                                 status = DLADM_STATUS_MACADDRINVAL;
2937                         else
2938                                 status = DLADM_STATUS_NOMEM;
2939                         goto fail;
2940                 }
2941 
2942                 vdp[i].vd_val = (uintptr_t)addr;
2943         }
2944         return (DLADM_STATUS_OK);
2945 
2946 fail:
2947         for (i = 0; i < val_cnt; i++) {
2948                 free((void *)vdp[i].vd_val);
2949                 vdp[i].vd_val = NULL;
2950         }
2951         return (status);
2952 }
2953 
2954 /* ARGSUSED */
2955 static dladm_status_t
2956 set_secondary_macs(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
2957     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
2958 {
2959         dladm_status_t status;
2960         dld_ioc_macprop_t *dip;
2961         int i;
2962         mac_secondary_addr_t msa;
2963 
2964         dip = i_dladm_buf_alloc_by_name(0, linkid, "secondary-macs", 0,
2965             &status);
2966         if (dip == NULL)
2967                 return (status);
2968 
2969         if (vdp->vd_val == 0) {
2970                 val_cnt = (uint_t)-1;
2971         } else {
2972                 for (i = 0; i < val_cnt; i++) {
2973                         bcopy((void *)vdp[i].vd_val, msa.ms_addrs[i],
2974                             MAXMACADDRLEN);
2975                 }
2976         }
2977         msa.ms_addrcnt = val_cnt;
2978         bcopy(&msa, dip->pr_val, dip->pr_valsize);
2979 
2980         status = i_dladm_macprop(handle, dip, B_TRUE);
2981 
2982         free(dip);
2983         return (status);
2984 }
2985 
2986 /* ARGSUSED */
2987 static dladm_status_t
2988 get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2989     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2990     uint_t flags, uint_t *perm_flags)
2991 {
2992         struct          dlautopush dlap;
2993         int             i, len;
2994         dladm_status_t  status;
2995 
2996         if (flags & DLD_PROP_DEFAULT)
2997                 return (DLADM_STATUS_NOTDEFINED);
2998 
2999         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3000             perm_flags, &dlap, sizeof (dlap));
3001         if (status != DLADM_STATUS_OK)
3002                 return (status);
3003 
3004         if (dlap.dap_npush == 0) {
3005                 *val_cnt = 0;
3006                 return (DLADM_STATUS_OK);
3007         }
3008         for (i = 0, len = 0; i < dlap.dap_npush; i++) {
3009                 if (i != 0) {
3010                         (void) snprintf(*prop_val + len,
3011                             DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
3012                         len += 1;
3013                 }
3014                 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
3015                     "%s", dlap.dap_aplist[i]);
3016                 len += strlen(dlap.dap_aplist[i]);
3017                 if (dlap.dap_anchor - 1 == i) {
3018                         (void) snprintf(*prop_val + len,
3019                             DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
3020                             AP_ANCHOR);
3021                         len += (strlen(AP_ANCHOR) + 1);
3022                 }
3023         }
3024         *val_cnt = 1;
3025         return (DLADM_STATUS_OK);
3026 }
3027 
3028 /*
3029  * Add the specified module to the dlautopush structure; returns a
3030  * DLADM_STATUS_* code.
3031  */
3032 dladm_status_t
3033 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
3034 {
3035         if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
3036                 return (DLADM_STATUS_BADVAL);
3037 
3038         if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
3039                 /*
3040                  * We don't allow multiple anchors, and the anchor must
3041                  * be after at least one module.
3042                  */
3043                 if (dlap->dap_anchor != 0)
3044                         return (DLADM_STATUS_BADVAL);
3045                 if (dlap->dap_npush == 0)
3046                         return (DLADM_STATUS_BADVAL);
3047 
3048                 dlap->dap_anchor = dlap->dap_npush;
3049                 return (DLADM_STATUS_OK);
3050         }
3051         if (dlap->dap_npush >= MAXAPUSH)
3052                 return (DLADM_STATUS_BADVALCNT);
3053 
3054         (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
3055             FMNAMESZ + 1);
3056 
3057         return (DLADM_STATUS_OK);
3058 }
3059 
3060 /*
3061  * Currently, both '.' and ' '(space) can be used as the delimiters between
3062  * autopush modules. The former is used in dladm set-linkprop, and the
3063  * latter is used in the autopush(1M) file.
3064  */
3065 /* ARGSUSED */
3066 static dladm_status_t
3067 check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3068     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3069     datalink_media_t media)
3070 {
3071         char                    *module;
3072         struct dlautopush       *dlap;
3073         dladm_status_t          status;
3074         char                    val[DLADM_PROP_VAL_MAX];
3075         char                    delimiters[4];
3076         uint_t                  val_cnt = *val_cntp;
3077         val_desc_t              *vdp = *vdpp;
3078 
3079         if (val_cnt != 1)
3080                 return (DLADM_STATUS_BADVALCNT);
3081 
3082         if (prop_val != NULL) {
3083                 dlap = malloc(sizeof (struct dlautopush));
3084                 if (dlap == NULL)
3085                         return (DLADM_STATUS_NOMEM);
3086 
3087                 (void) memset(dlap, 0, sizeof (struct dlautopush));
3088                 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
3089                 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
3090                 module = strtok(val, delimiters);
3091                 while (module != NULL) {
3092                         status = i_dladm_add_ap_module(module, dlap);
3093                         if (status != DLADM_STATUS_OK)
3094                                 return (status);
3095                         module = strtok(NULL, delimiters);
3096                 }
3097 
3098                 vdp->vd_val = (uintptr_t)dlap;
3099         } else {
3100                 vdp->vd_val = 0;
3101         }
3102         return (DLADM_STATUS_OK);
3103 }
3104 
3105 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
3106 
3107 /* ARGSUSED */
3108 static dladm_status_t
3109 get_rate_common(dladm_handle_t handle, prop_desc_t *pdp,
3110     datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id,
3111     uint_t *perm_flags)
3112 {
3113         wl_rates_t      *wrp;
3114         uint_t          i;
3115         dladm_status_t  status = DLADM_STATUS_OK;
3116 
3117         wrp = malloc(WLDP_BUFSIZE);
3118         if (wrp == NULL)
3119                 return (DLADM_STATUS_NOMEM);
3120 
3121         status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE,
3122             B_FALSE);
3123         if (status != DLADM_STATUS_OK)
3124                 goto done;
3125 
3126         if (wrp->wl_rates_num > *val_cnt) {
3127                 status = DLADM_STATUS_TOOSMALL;
3128                 goto done;
3129         }
3130 
3131         if (wrp->wl_rates_rates[0] == 0) {
3132                 prop_val[0][0] = '\0';
3133                 *val_cnt = 1;
3134                 goto done;
3135         }
3136 
3137         for (i = 0; i < wrp->wl_rates_num; i++) {
3138                 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
3139                     wrp->wl_rates_rates[i] % 2,
3140                     (float)wrp->wl_rates_rates[i] / 2);
3141         }
3142         *val_cnt = wrp->wl_rates_num;
3143         *perm_flags = MAC_PROP_PERM_RW;
3144 
3145 done:
3146         free(wrp);
3147         return (status);
3148 }
3149 
3150 static dladm_status_t
3151 get_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3152     char **prop_val, uint_t *val_cnt, datalink_media_t media,
3153     uint_t flags, uint_t *perm_flags)
3154 {
3155         if (media != DL_WIFI) {
3156                 return (get_speed(handle, pdp, linkid, prop_val,
3157                     val_cnt, media, flags, perm_flags));
3158         }
3159 
3160         return (get_rate_common(handle, pdp, linkid, prop_val, val_cnt,
3161             MAC_PROP_WL_DESIRED_RATES, perm_flags));
3162 }
3163 
3164 /* ARGSUSED */
3165 static dladm_status_t
3166 get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3167     char **prop_val, uint_t *val_cnt, datalink_media_t media,
3168     uint_t flags, uint_t *perm_flags)
3169 {
3170         switch (media) {
3171         case DL_ETHER:
3172                 /*
3173                  * Speed for ethernet links is unbounded. E.g., 802.11b
3174                  * links can have a speed of 5.5 Gbps.
3175                  */
3176                 return (DLADM_STATUS_NOTSUP);
3177 
3178         case DL_WIFI:
3179                 return (get_rate_common(handle, pdp, linkid, prop_val,
3180                     val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags));
3181         default:
3182                 return (DLADM_STATUS_BADARG);
3183         }
3184 }
3185 
3186 static dladm_status_t
3187 set_wlan_rate(dladm_handle_t handle, datalink_id_t linkid,
3188     dladm_wlan_rates_t *rates)
3189 {
3190         int             i;
3191         uint_t          len;
3192         wl_rates_t      *wrp;
3193         dladm_status_t  status = DLADM_STATUS_OK;
3194 
3195         wrp = malloc(WLDP_BUFSIZE);
3196         if (wrp == NULL)
3197                 return (DLADM_STATUS_NOMEM);
3198 
3199         bzero(wrp, WLDP_BUFSIZE);
3200         for (i = 0; i < rates->wr_cnt; i++)
3201                 wrp->wl_rates_rates[i] = rates->wr_rates[i];
3202         wrp->wl_rates_num = rates->wr_cnt;
3203 
3204         len = offsetof(wl_rates_t, wl_rates_rates) +
3205             (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
3206         status = i_dladm_wlan_param(handle, linkid, wrp,
3207             MAC_PROP_WL_DESIRED_RATES, len, B_TRUE);
3208 
3209         free(wrp);
3210         return (status);
3211 }
3212 
3213 /* ARGSUSED */
3214 static dladm_status_t
3215 set_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3216     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3217 {
3218         dladm_wlan_rates_t      rates;
3219         dladm_status_t          status;
3220 
3221         /*
3222          * can currently set rate on WIFI links only.
3223          */
3224         if (media != DL_WIFI)
3225                 return (DLADM_STATUS_PROPRDONLY);
3226 
3227         if (val_cnt != 1)
3228                 return (DLADM_STATUS_BADVALCNT);
3229 
3230         rates.wr_cnt = 1;
3231         rates.wr_rates[0] = vdp[0].vd_val;
3232 
3233         status = set_wlan_rate(handle, linkid, &rates);
3234 
3235         return (status);
3236 }
3237 
3238 /* ARGSUSED */
3239 static dladm_status_t
3240 check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3241     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3242     datalink_media_t media)
3243 {
3244         int             i;
3245         uint_t          modval_cnt = MAX_SUPPORT_RATES;
3246         char            *buf, **modval;
3247         dladm_status_t  status;
3248         uint_t          perm_flags;
3249         uint_t          val_cnt = *val_cntp;
3250         val_desc_t      *vdp = *vdpp;
3251 
3252         if (val_cnt != 1)
3253                 return (DLADM_STATUS_BADVALCNT);
3254 
3255         buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
3256             MAX_SUPPORT_RATES);
3257         if (buf == NULL) {
3258                 status = DLADM_STATUS_NOMEM;
3259                 goto done;
3260         }
3261 
3262         modval = (char **)(void *)buf;
3263         for (i = 0; i < MAX_SUPPORT_RATES; i++) {
3264                 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
3265                     i * DLADM_STRSIZE;
3266         }
3267 
3268         status = get_rate_mod(handle, NULL, linkid, modval, &modval_cnt,
3269             media, 0, &perm_flags);
3270         if (status != DLADM_STATUS_OK)
3271                 goto done;
3272 
3273         for (i = 0; i < modval_cnt; i++) {
3274                 if (strcasecmp(*prop_val, modval[i]) == 0) {
3275                         vdp->vd_val = (uintptr_t)(uint_t)
3276                             (atof(*prop_val) * 2);
3277                         status = DLADM_STATUS_OK;
3278                         break;
3279                 }
3280         }
3281         if (i == modval_cnt)
3282                 status = DLADM_STATUS_BADVAL;
3283 done:
3284         free(buf);
3285         return (status);
3286 }
3287 
3288 static dladm_status_t
3289 get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf,
3290     int buflen)
3291 {
3292         return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
3293             buflen, B_FALSE));
3294 }
3295 
3296 /* ARGSUSED */
3297 static dladm_status_t
3298 get_channel(dladm_handle_t handle, prop_desc_t *pdp,
3299     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3300     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3301 {
3302         uint32_t        channel;
3303         char            buf[WLDP_BUFSIZE];
3304         dladm_status_t  status;
3305         wl_phy_conf_t   wl_phy_conf;
3306 
3307         if ((status = get_phyconf(handle, linkid, buf, sizeof (buf)))
3308             != DLADM_STATUS_OK)
3309                 return (status);
3310 
3311         (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
3312         if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel))
3313                 return (DLADM_STATUS_NOTFOUND);
3314 
3315         (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
3316         *val_cnt = 1;
3317         *perm_flags = MAC_PROP_PERM_READ;
3318         return (DLADM_STATUS_OK);
3319 }
3320 
3321 /* ARGSUSED */
3322 static dladm_status_t
3323 get_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3324     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3325     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3326 {
3327         wl_ps_mode_t    mode;
3328         const char      *s;
3329         char            buf[WLDP_BUFSIZE];
3330         dladm_status_t  status;
3331 
3332         if ((status = i_dladm_wlan_param(handle, linkid, buf,
3333             MAC_PROP_WL_POWER_MODE, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3334                 return (status);
3335 
3336         (void) memcpy(&mode, buf, sizeof (mode));
3337         switch (mode.wl_ps_mode) {
3338         case WL_PM_AM:
3339                 s = "off";
3340                 break;
3341         case WL_PM_MPS:
3342                 s = "max";
3343                 break;
3344         case WL_PM_FAST:
3345                 s = "fast";
3346                 break;
3347         default:
3348                 return (DLADM_STATUS_NOTFOUND);
3349         }
3350         (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3351         *val_cnt = 1;
3352         *perm_flags = MAC_PROP_PERM_RW;
3353         return (DLADM_STATUS_OK);
3354 }
3355 
3356 /* ARGSUSED */
3357 static dladm_status_t
3358 set_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3359     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3360     datalink_media_t media)
3361 {
3362         dladm_wlan_powermode_t  powermode = vdp->vd_val;
3363         wl_ps_mode_t            ps_mode;
3364 
3365         if (val_cnt != 1)
3366                 return (DLADM_STATUS_BADVALCNT);
3367 
3368         (void) memset(&ps_mode, 0xff, sizeof (ps_mode));
3369 
3370         switch (powermode) {
3371         case DLADM_WLAN_PM_OFF:
3372                 ps_mode.wl_ps_mode = WL_PM_AM;
3373                 break;
3374         case DLADM_WLAN_PM_MAX:
3375                 ps_mode.wl_ps_mode = WL_PM_MPS;
3376                 break;
3377         case DLADM_WLAN_PM_FAST:
3378                 ps_mode.wl_ps_mode = WL_PM_FAST;
3379                 break;
3380         default:
3381                 return (DLADM_STATUS_NOTSUP);
3382         }
3383         return (i_dladm_wlan_param(handle, linkid, &ps_mode,
3384             MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE));
3385 }
3386 
3387 /* ARGSUSED */
3388 static dladm_status_t
3389 get_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3390     char **prop_val, uint_t *val_cnt, datalink_media_t media,
3391     uint_t flags, uint_t *perm_flags)
3392 {
3393         wl_radio_t      radio;
3394         const char      *s;
3395         char            buf[WLDP_BUFSIZE];
3396         dladm_status_t  status;
3397 
3398         if ((status = i_dladm_wlan_param(handle, linkid, buf,
3399             MAC_PROP_WL_RADIO, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3400                 return (status);
3401 
3402         (void) memcpy(&radio, buf, sizeof (radio));
3403         switch (radio) {
3404         case B_TRUE:
3405                 s = "on";
3406                 break;
3407         case B_FALSE:
3408                 s = "off";
3409                 break;
3410         default:
3411                 return (DLADM_STATUS_NOTFOUND);
3412         }
3413         (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3414         *val_cnt = 1;
3415         *perm_flags = MAC_PROP_PERM_RW;
3416         return (DLADM_STATUS_OK);
3417 }
3418 
3419 /* ARGSUSED */
3420 static dladm_status_t
3421 set_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3422     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3423 {
3424         dladm_wlan_radio_t      radio = vdp->vd_val;
3425         wl_radio_t              r;
3426 
3427         if (val_cnt != 1)
3428                 return (DLADM_STATUS_BADVALCNT);
3429 
3430         switch (radio) {
3431         case DLADM_WLAN_RADIO_ON:
3432                 r = B_TRUE;
3433                 break;
3434         case DLADM_WLAN_RADIO_OFF:
3435                 r = B_FALSE;
3436                 break;
3437         default:
3438                 return (DLADM_STATUS_NOTSUP);
3439         }
3440         return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO,
3441             sizeof (r), B_TRUE));
3442 }
3443 
3444 /* ARGSUSED */
3445 static dladm_status_t
3446 check_hoplimit(dladm_handle_t handle, prop_desc_t *pdp,
3447     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3448     val_desc_t **vdpp, datalink_media_t media)
3449 {
3450         int32_t         hlim;
3451         char            *ep;
3452         uint_t          val_cnt = *val_cntp;
3453         val_desc_t      *vdp = *vdpp;
3454 
3455         if (val_cnt != 1)
3456                 return (DLADM_STATUS_BADVALCNT);
3457 
3458         errno = 0;
3459         hlim = strtol(*prop_val, &ep, 10);
3460         if (errno != 0 || ep == *prop_val || hlim < 1 ||
3461             hlim > (int32_t)UINT8_MAX)
3462                 return (DLADM_STATUS_BADVAL);
3463         vdp->vd_val = hlim;
3464         return (DLADM_STATUS_OK);
3465 }
3466 
3467 /* ARGSUSED */
3468 static dladm_status_t
3469 check_encaplim(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3470     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3471     datalink_media_t media)
3472 {
3473         int32_t         elim;
3474         char            *ep;
3475         uint_t          val_cnt = *val_cntp;
3476         val_desc_t      *vdp = *vdpp;
3477 
3478         if (media != DL_IPV6)
3479                 return (DLADM_STATUS_BADARG);
3480 
3481         if (val_cnt != 1)
3482                 return (DLADM_STATUS_BADVALCNT);
3483 
3484         errno = 0;
3485         elim = strtol(*prop_val, &ep, 10);
3486         if (errno != 0 || ep == *prop_val || elim < 0 ||
3487             elim > (int32_t)UINT8_MAX)
3488                 return (DLADM_STATUS_BADVAL);
3489         vdp->vd_val = elim;
3490         return (DLADM_STATUS_OK);
3491 }
3492 
3493 static dladm_status_t
3494 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3495     const char *prop_name, char **prop_val, uint_t val_cnt)
3496 {
3497         char            buf[MAXLINELEN];
3498         int             i;
3499         dladm_conf_t    conf;
3500         dladm_status_t  status;
3501 
3502         status = dladm_open_conf(handle, linkid, &conf);
3503         if (status != DLADM_STATUS_OK)
3504                 return (status);
3505 
3506         /*
3507          * reset case.
3508          */
3509         if (val_cnt == 0) {
3510                 status = dladm_unset_conf_field(handle, conf, prop_name);
3511                 if (status == DLADM_STATUS_OK)
3512                         status = dladm_write_conf(handle, conf);
3513                 goto done;
3514         }
3515 
3516         buf[0] = '\0';
3517         for (i = 0; i < val_cnt; i++) {
3518                 (void) strlcat(buf, prop_val[i], MAXLINELEN);
3519                 if (i != val_cnt - 1)
3520                         (void) strlcat(buf, ",", MAXLINELEN);
3521         }
3522 
3523         status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR,
3524             buf);
3525         if (status == DLADM_STATUS_OK)
3526                 status = dladm_write_conf(handle, conf);
3527 
3528 done:
3529         dladm_destroy_conf(handle, conf);
3530         return (status);
3531 }
3532 
3533 static dladm_status_t
3534 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3535     const char *prop_name, char **prop_val, uint_t *val_cntp)
3536 {
3537         char            buf[MAXLINELEN], *str;
3538         uint_t          cnt = 0;
3539         dladm_conf_t    conf;
3540         dladm_status_t  status;
3541 
3542         status = dladm_getsnap_conf(handle, linkid, &conf);
3543         if (status != DLADM_STATUS_OK)
3544                 return (status);
3545 
3546         status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN);
3547         if (status != DLADM_STATUS_OK)
3548                 goto done;
3549 
3550         str = strtok(buf, ",");
3551         while (str != NULL) {
3552                 if (cnt == *val_cntp) {
3553                         status = DLADM_STATUS_TOOSMALL;
3554                         goto done;
3555                 }
3556                 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
3557                 str = strtok(NULL, ",");
3558         }
3559 
3560         *val_cntp = cnt;
3561 
3562 done:
3563         dladm_destroy_conf(handle, conf);
3564         return (status);
3565 }
3566 
3567 /*
3568  * Walk persistent private link properties of a link.
3569  */
3570 static dladm_status_t
3571 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid,
3572     void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
3573 {
3574         dladm_status_t          status;
3575         dladm_conf_t            conf;
3576         char                    last_attr[MAXLINKATTRLEN];
3577         char                    attr[MAXLINKATTRLEN];
3578         char                    attrval[MAXLINKATTRVALLEN];
3579         size_t                  attrsz;
3580 
3581         if (linkid == DATALINK_INVALID_LINKID || func == NULL)
3582                 return (DLADM_STATUS_BADARG);
3583 
3584         status = dladm_getsnap_conf(handle, linkid, &conf);
3585         if (status != DLADM_STATUS_OK)
3586                 return (status);
3587 
3588         last_attr[0] = '\0';
3589         while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr,
3590             attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) {
3591                 if (attr[0] == '_') {
3592                         if (func(handle, linkid, attr, arg) ==
3593                             DLADM_WALK_TERMINATE)
3594                                 break;
3595                 }
3596                 (void) strlcpy(last_attr, attr, MAXLINKATTRLEN);
3597         }
3598 
3599         dladm_destroy_conf(handle, conf);
3600         return (DLADM_STATUS_OK);
3601 }
3602 
3603 static link_attr_t *
3604 dladm_name2prop(const char *prop_name)
3605 {
3606         link_attr_t *p;
3607 
3608         for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3609                 if (strcmp(p->pp_name, prop_name) == 0)
3610                         break;
3611         }
3612         return (p);
3613 }
3614 
3615 static link_attr_t *
3616 dladm_id2prop(mac_prop_id_t propid)
3617 {
3618         link_attr_t *p;
3619 
3620         for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3621                 if (p->pp_id == propid)
3622                         break;
3623         }
3624         return (p);
3625 }
3626 
3627 static dld_ioc_macprop_t *
3628 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
3629     const char *prop_name, mac_prop_id_t propid, uint_t flags,
3630     dladm_status_t *status)
3631 {
3632         int dsize;
3633         dld_ioc_macprop_t *dip;
3634 
3635         *status = DLADM_STATUS_OK;
3636         dsize = MAC_PROP_BUFSIZE(valsize);
3637         dip = malloc(dsize);
3638         if (dip == NULL) {
3639                 *status = DLADM_STATUS_NOMEM;
3640                 return (NULL);
3641         }
3642         bzero(dip, dsize);
3643         dip->pr_valsize = valsize;
3644         (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
3645         dip->pr_linkid = linkid;
3646         dip->pr_num = propid;
3647         dip->pr_flags = flags;
3648         return (dip);
3649 }
3650 
3651 static dld_ioc_macprop_t *
3652 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
3653     const char *prop_name, uint_t flags, dladm_status_t *status)
3654 {
3655         link_attr_t *p;
3656 
3657         p = dladm_name2prop(prop_name);
3658         valsize = MAX(p->pp_valsize, valsize);
3659         return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
3660             flags, status));
3661 }
3662 
3663 static dld_ioc_macprop_t *
3664 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
3665     mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
3666 {
3667         link_attr_t *p;
3668 
3669         p = dladm_id2prop(propid);
3670         valsize = MAX(p->pp_valsize, valsize);
3671         return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
3672             flags, status));
3673 }
3674 
3675 /* ARGSUSED */
3676 static dladm_status_t
3677 set_public_prop(dladm_handle_t handle, prop_desc_t *pdp,
3678     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3679     datalink_media_t media)
3680 {
3681         dld_ioc_macprop_t       *dip;
3682         dladm_status_t  status = DLADM_STATUS_OK;
3683         uint8_t         u8;
3684         uint16_t        u16;
3685         uint32_t        u32;
3686         void            *val;
3687 
3688         dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status);
3689         if (dip == NULL)
3690                 return (status);
3691 
3692         if (pdp->pd_flags & PD_CHECK_ALLOC)
3693                 val = (void *)vdp->vd_val;
3694         else {
3695                 /*
3696                  * Currently all 1/2/4-byte size properties are byte/word/int.
3697                  * No need (yet) to distinguish these from arrays of same size.
3698                  */
3699                 switch (dip->pr_valsize) {
3700                 case 1:
3701                         u8 = vdp->vd_val;
3702                         val = &u8;
3703                         break;
3704                 case 2:
3705                         u16 = vdp->vd_val;
3706                         val = &u16;
3707                         break;
3708                 case 4:
3709                         u32 = vdp->vd_val;
3710                         val = &u32;
3711                         break;
3712                 default:
3713                         val = &vdp->vd_val;
3714                         break;
3715                 }
3716         }
3717 
3718         if (val != NULL)
3719                 (void) memcpy(dip->pr_val, val, dip->pr_valsize);
3720         else
3721                 dip->pr_valsize = 0;
3722 
3723         status = i_dladm_macprop(handle, dip, B_TRUE);
3724 
3725 done:
3726         free(dip);
3727         return (status);
3728 }
3729 
3730 dladm_status_t
3731 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set)
3732 {
3733         dladm_status_t status = DLADM_STATUS_OK;
3734 
3735         if (ioctl(dladm_dld_fd(handle),
3736             (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
3737                 status = dladm_errno2status(errno);
3738 
3739         return (status);
3740 }
3741 
3742 static dladm_status_t
3743 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid,
3744     char *prop_name, uint_t flags, uint_t *perm_flags, void *arg, size_t size)
3745 {
3746         dld_ioc_macprop_t       *dip;
3747         dladm_status_t          status;
3748 
3749         dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, &status);
3750         if (dip == NULL)
3751                 return (DLADM_STATUS_NOMEM);
3752 
3753         status = i_dladm_macprop(handle, dip, B_FALSE);
3754         if (status != DLADM_STATUS_OK) {
3755                 free(dip);
3756                 return (status);
3757         }
3758 
3759         if (perm_flags != NULL)
3760                 *perm_flags = dip->pr_perm_flags;
3761 
3762         if (arg != NULL)
3763                 (void) memcpy(arg, dip->pr_val, size);
3764         free(dip);
3765         return (DLADM_STATUS_OK);
3766 }
3767 
3768 /* ARGSUSED */
3769 static dladm_status_t
3770 check_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3771     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3772     val_desc_t **vp, datalink_media_t media)
3773 {
3774         uint_t          val_cnt = *val_cntp;
3775         val_desc_t      *v = *vp;
3776 
3777         if (val_cnt != 1)
3778                 return (DLADM_STATUS_BADVAL);
3779         v->vd_val = strtoul(prop_val[0], NULL, 0);
3780         return (DLADM_STATUS_OK);
3781 }
3782 
3783 /* ARGSUSED */
3784 static dladm_status_t
3785 get_duplex(dladm_handle_t handle, prop_desc_t *pdp,
3786     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3787     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3788 {
3789         link_duplex_t   link_duplex;
3790         dladm_status_t  status;
3791 
3792         if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex",
3793             KSTAT_DATA_UINT32, &link_duplex)) != 0)
3794                 return (status);
3795 
3796         switch (link_duplex) {
3797         case LINK_DUPLEX_FULL:
3798                 (void) strcpy(*prop_val, "full");
3799                 break;
3800         case LINK_DUPLEX_HALF:
3801                 (void) strcpy(*prop_val, "half");
3802                 break;
3803         default:
3804                 (void) strcpy(*prop_val, "unknown");
3805                 break;
3806         }
3807         *val_cnt = 1;
3808         return (DLADM_STATUS_OK);
3809 }
3810 
3811 /* ARGSUSED */
3812 static dladm_status_t
3813 get_speed(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3814     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
3815     uint_t *perm_flags)
3816 {
3817         uint64_t        ifspeed = 0;
3818         dladm_status_t status;
3819 
3820         if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed",
3821             KSTAT_DATA_UINT64, &ifspeed)) != 0)
3822                 return (status);
3823 
3824         if ((ifspeed % 1000000) != 0) {
3825                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3826                     "%llf", ifspeed / (float)1000000); /* Mbps */
3827         } else {
3828                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3829                     "%llu", ifspeed / 1000000); /* Mbps */
3830         }
3831         *val_cnt = 1;
3832         *perm_flags = MAC_PROP_PERM_READ;
3833         return (DLADM_STATUS_OK);
3834 }
3835 
3836 /* ARGSUSED */
3837 static dladm_status_t
3838 get_link_state(dladm_handle_t handle, prop_desc_t *pdp,
3839     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3840     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3841 {
3842         link_state_t            link_state;
3843         dladm_status_t          status;
3844 
3845         status = dladm_get_state(handle, linkid, &link_state);
3846         if (status != DLADM_STATUS_OK)
3847                 return (status);
3848 
3849         switch (link_state) {
3850         case LINK_STATE_UP:
3851                 (void) strcpy(*prop_val, "up");
3852                 break;
3853         case LINK_STATE_DOWN:
3854                 (void) strcpy(*prop_val, "down");
3855                 break;
3856         default:
3857                 (void) strcpy(*prop_val, "unknown");
3858                 break;
3859         }
3860         *val_cnt = 1;
3861         *perm_flags = MAC_PROP_PERM_READ;
3862         return (DLADM_STATUS_OK);
3863 }
3864 
3865 /* ARGSUSED */
3866 static dladm_status_t
3867 get_binary(dladm_handle_t handle, prop_desc_t *pdp,
3868     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3869     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3870 {
3871         dladm_status_t  status;
3872         uint_t          v = 0;
3873 
3874         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3875             perm_flags, &v, sizeof (v));
3876         if (status != DLADM_STATUS_OK)
3877                 return (status);
3878 
3879         (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%d", (uint_t)(v > 0));
3880         *val_cnt = 1;
3881         return (DLADM_STATUS_OK);
3882 }
3883 
3884 /* ARGSUSED */
3885 static dladm_status_t
3886 get_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3887     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3888     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3889 {
3890         dladm_status_t  status;
3891         uint32_t        v = 0;
3892 
3893         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3894             perm_flags, &v, sizeof (v));
3895         if (status != DLADM_STATUS_OK)
3896                 return (status);
3897 
3898         (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
3899         *val_cnt = 1;
3900         return (DLADM_STATUS_OK);
3901 }
3902 
3903 /* ARGSUSED */
3904 static dladm_status_t
3905 get_range(dladm_handle_t handle, prop_desc_t *pdp,
3906     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3907     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3908 {
3909         dld_ioc_macprop_t *dip;
3910         dladm_status_t status = DLADM_STATUS_OK;
3911         size_t  sz;
3912         uint_t  rcount;
3913         mac_propval_range_t *rangep;
3914 
3915         /*
3916          * As caller we don't know number of value ranges, the driver
3917          * supports. To begin with we assume that number to be 1. If the
3918          * buffer size is insufficient, driver returns back with the
3919          * actual count of value ranges. See mac.h for more details.
3920          */
3921         sz = sizeof (mac_propval_range_t);
3922         rcount = 1;
3923 retry:
3924         if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
3925             &status)) == NULL)
3926                 return (status);
3927 
3928         rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
3929         rangep->mpr_count = rcount;
3930 
3931         status = i_dladm_macprop(handle, dip, B_FALSE);
3932         if (status != DLADM_STATUS_OK) {
3933                 if (status == DLADM_STATUS_TOOSMALL) {
3934                         int err;
3935 
3936                         if ((err = i_dladm_range_size(rangep, &sz, &rcount))
3937                             == 0) {
3938                                 free(dip);
3939                                 goto retry;
3940                         } else {
3941                                 status = dladm_errno2status(err);
3942                         }
3943                 }
3944                 free(dip);
3945                 return (status);
3946         }
3947 
3948         if (rangep->mpr_count == 0) {
3949                 *val_cnt = 1;
3950                 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "--");
3951                 goto done;
3952         }
3953 
3954         switch (rangep->mpr_type) {
3955         case MAC_PROPVAL_UINT32: {
3956                 mac_propval_uint32_range_t *ur;
3957                 uint_t  count = rangep->mpr_count, i;
3958 
3959                 ur = &rangep->mpr_range_uint32[0];
3960 
3961                 for (i = 0; i < count; i++, ur++) {
3962                         if (ur->mpur_min == ur->mpur_max) {
3963                                 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
3964                                     "%ld", ur->mpur_min);
3965                         } else {
3966                                 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
3967                                     "%ld-%ld", ur->mpur_min, ur->mpur_max);
3968                         }
3969                 }
3970                 *val_cnt = count;
3971                 break;
3972         }
3973         default:
3974                 status = DLADM_STATUS_BADARG;
3975                 break;
3976         }
3977 done:
3978         free(dip);
3979         return (status);
3980 }
3981 
3982 /* ARGSUSED */
3983 static dladm_status_t
3984 get_tagmode(dladm_handle_t handle, prop_desc_t *pdp,
3985     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3986     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3987 {
3988         link_tagmode_t          mode;
3989         dladm_status_t          status;
3990 
3991         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3992             perm_flags, &mode, sizeof (mode));
3993         if (status != DLADM_STATUS_OK)
3994                 return (status);
3995 
3996         switch (mode) {
3997         case LINK_TAGMODE_NORMAL:
3998                 (void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX);
3999                 break;
4000         case LINK_TAGMODE_VLANONLY:
4001                 (void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX);
4002                 break;
4003         default:
4004                 (void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX);
4005         }
4006         *val_cnt = 1;
4007         return (DLADM_STATUS_OK);
4008 }
4009 
4010 /* ARGSUSED */
4011 static dladm_status_t
4012 get_flowctl(dladm_handle_t handle, prop_desc_t *pdp,
4013     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4014     datalink_media_t media, uint_t flags, uint_t *perm_flags)
4015 {
4016         link_flowctrl_t v;
4017         dladm_status_t  status;
4018 
4019         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4020             perm_flags, &v, sizeof (v));
4021         if (status != DLADM_STATUS_OK)
4022                 return (status);
4023 
4024         switch (v) {
4025         case LINK_FLOWCTRL_NONE:
4026                 (void) sprintf(*prop_val, "no");
4027                 break;
4028         case LINK_FLOWCTRL_RX:
4029                 (void) sprintf(*prop_val, "rx");
4030                 break;
4031         case LINK_FLOWCTRL_TX:
4032                 (void) sprintf(*prop_val, "tx");
4033                 break;
4034         case LINK_FLOWCTRL_BI:
4035                 (void) sprintf(*prop_val, "bi");
4036                 break;
4037         }
4038         *val_cnt = 1;
4039         return (DLADM_STATUS_OK);
4040 }
4041 
4042 
4043 /* ARGSUSED */
4044 static dladm_status_t
4045 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid,
4046     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
4047 
4048 {
4049         int             i, slen;
4050         int             bufsize = 0;
4051         dld_ioc_macprop_t *dip = NULL;
4052         uchar_t         *dp;
4053         link_attr_t *p;
4054         dladm_status_t  status = DLADM_STATUS_OK;
4055 
4056         if ((prop_name == NULL && prop_val != NULL) ||
4057             (prop_val != NULL && val_cnt == 0))
4058                 return (DLADM_STATUS_BADARG);
4059         p = dladm_name2prop(prop_name);
4060         if (p->pp_id != MAC_PROP_PRIVATE)
4061                 return (DLADM_STATUS_BADARG);
4062 
4063         if (!(flags & DLADM_OPT_ACTIVE))
4064                 return (DLADM_STATUS_OK);
4065 
4066         /*
4067          * private properties: all parsing is done in the kernel.
4068          * allocate a enough space for each property + its separator (',').
4069          */
4070         for (i = 0; i < val_cnt; i++) {
4071                 bufsize += strlen(prop_val[i]) + 1;
4072         }
4073 
4074         if (prop_val == NULL) {
4075                 /*
4076                  * getting default value. so use more buffer space.
4077                  */
4078                 bufsize += DLADM_PROP_BUF_CHUNK;
4079         }
4080 
4081         dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
4082             (prop_val != NULL ? 0 : DLD_PROP_DEFAULT), &status);
4083         if (dip == NULL)
4084                 return (status);
4085 
4086         dp = (uchar_t *)dip->pr_val;
4087         slen = 0;
4088 
4089         if (prop_val == NULL) {
4090                 status = i_dladm_macprop(handle, dip, B_FALSE);
4091                 dip->pr_flags = 0;
4092         } else {
4093                 for (i = 0; i < val_cnt; i++) {
4094                         int plen = 0;
4095 
4096                         plen = strlen(prop_val[i]);
4097                         bcopy(prop_val[i], dp, plen);
4098                         slen += plen;
4099                         /*
4100                          * add a "," separator and update dp.
4101                          */
4102                         if (i != (val_cnt -1))
4103                                 dp[slen++] = ',';
4104                         dp += (plen + 1);
4105                 }
4106         }
4107         if (status == DLADM_STATUS_OK)
4108                 status = i_dladm_macprop(handle, dip, B_TRUE);
4109 
4110         free(dip);
4111         return (status);
4112 }
4113 
4114 static dladm_status_t
4115 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid,
4116     const char *prop_name, char **prop_val, uint_t *val_cnt,
4117     dladm_prop_type_t type, uint_t dld_flags)
4118 {
4119         dladm_status_t  status = DLADM_STATUS_OK;
4120         dld_ioc_macprop_t *dip = NULL;
4121         link_attr_t *p;
4122 
4123         if ((prop_name == NULL && prop_val != NULL) ||
4124             (prop_val != NULL && val_cnt == 0))
4125                 return (DLADM_STATUS_BADARG);
4126 
4127         p = dladm_name2prop(prop_name);
4128         if (p->pp_id != MAC_PROP_PRIVATE)
4129                 return (DLADM_STATUS_BADARG);
4130 
4131         /*
4132          * private properties: all parsing is done in the kernel.
4133          */
4134         dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
4135             dld_flags, &status);
4136         if (dip == NULL)
4137                 return (status);
4138 
4139         if ((status = i_dladm_macprop(handle, dip, B_FALSE)) ==
4140             DLADM_STATUS_OK) {
4141                 if (type == DLADM_PROP_VAL_PERM) {
4142                         (void) dladm_perm2str(dip->pr_perm_flags, *prop_val);
4143                 } else if (type == DLADM_PROP_VAL_MODIFIABLE) {
4144                         *prop_val[0] = '\0';
4145                 } else {
4146                         (void) strncpy(*prop_val, dip->pr_val,
4147                             DLADM_PROP_VAL_MAX);
4148                 }
4149                 *val_cnt = 1;
4150         } else if ((status == DLADM_STATUS_NOTSUP) &&
4151             (type == DLADM_PROP_VAL_CURRENT)) {
4152                 status = DLADM_STATUS_NOTFOUND;
4153         }
4154         free(dip);
4155         return (status);
4156 }
4157 
4158 
4159 static dladm_status_t
4160 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp,
4161     datalink_id_t linkid, datalink_media_t media, uint_t flags)
4162 {
4163         dladm_status_t status;
4164         char **prop_vals = NULL, *buf;
4165         size_t bufsize;
4166         uint_t cnt;
4167         int i;
4168         uint_t perm_flags;
4169 
4170         /*
4171          * Allocate buffer needed for prop_vals array. We can have at most
4172          * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
4173          * each entry has max size DLADM_PROP_VAL_MAX
4174          */
4175         bufsize =
4176             (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
4177         buf = malloc(bufsize);
4178         prop_vals = (char **)(void *)buf;
4179         for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
4180                 prop_vals[i] = buf +
4181                     sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4182                     i * DLADM_PROP_VAL_MAX;
4183         }
4184 
4185         /*
4186          * For properties which have pdp->pd_defval.vd_name as a non-empty
4187          * string, the "" itself is used to reset the property (exceptions
4188          * are zone and autopush, which populate vdp->vd_val). So
4189          * libdladm can copy pdp->pd_defval over to the val_desc_t passed
4190          * down on the setprop using the global values in the table. For
4191          * other cases (vd_name is ""), doing reset-linkprop will cause
4192          * libdladm to do a getprop to find the default value and then do
4193          * a setprop to reset the value to default.
4194          */
4195         status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media,
4196             DLD_PROP_DEFAULT, &perm_flags);
4197         if (status == DLADM_STATUS_OK) {
4198                 if (perm_flags == MAC_PROP_PERM_RW) {
4199                         status = i_dladm_set_single_prop(handle, linkid,
4200                             pdp->pd_class, media, pdp, prop_vals, cnt, flags);
4201                 }
4202                 else
4203                         status = DLADM_STATUS_NOTSUP;
4204         }
4205         free(buf);
4206         return (status);
4207 }
4208 
4209 /* ARGSUSED */
4210 static dladm_status_t
4211 get_stp(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid,
4212     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
4213     uint_t *perm_flags)
4214 {
4215         const bridge_public_prop_t *bpp;
4216         dladm_status_t retv;
4217         int val, i;
4218 
4219         if (flags != 0)
4220                 return (DLADM_STATUS_NOTSUP);
4221         *perm_flags = MAC_PROP_PERM_RW;
4222         *val_cnt = 1;
4223         for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++)
4224                 if (strcmp(bpp->bpp_name, pd->pd_name) == 0)
4225                         break;
4226         retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val);
4227         /* If the daemon isn't running, then return the persistent value */
4228         if (retv == DLADM_STATUS_NOTFOUND) {
4229                 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4230                     prop_val, val_cnt) != DLADM_STATUS_OK)
4231                         (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4232                             DLADM_PROP_VAL_MAX);
4233                 return (DLADM_STATUS_OK);
4234         }
4235         if (retv != DLADM_STATUS_OK) {
4236                 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4237                 return (retv);
4238         }
4239         if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') {
4240                 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4241                     DLADM_PROP_VAL_MAX);
4242                 return (DLADM_STATUS_OK);
4243         }
4244         for (i = 0; i < pd->pd_noptval; i++) {
4245                 if (val == pd->pd_optval[i].vd_val) {
4246                         (void) strlcpy(*prop_val, pd->pd_optval[i].vd_name,
4247                             DLADM_PROP_VAL_MAX);
4248                         return (DLADM_STATUS_OK);
4249                 }
4250         }
4251         (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val);
4252         return (DLADM_STATUS_OK);
4253 }
4254 
4255 /* ARGSUSED1 */
4256 static dladm_status_t
4257 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4258     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4259 {
4260         /*
4261          * Special case for mcheck: the daemon resets the value to zero, and we
4262          * don't want the daemon to refresh itself; it leads to deadlock.
4263          */
4264         if (flags & DLADM_OPT_NOREFRESH)
4265                 return (DLADM_STATUS_OK);
4266 
4267         /* Tell the running daemon, if any */
4268         return (dladm_bridge_refresh(handle, linkid));
4269 }
4270 
4271 /*
4272  * This is used only for stp_priority, stp_cost, and stp_mcheck.
4273  */
4274 /* ARGSUSED */
4275 static dladm_status_t
4276 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd,
4277     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4278     val_desc_t **vdpp, datalink_media_t media)
4279 {
4280         char            *cp;
4281         boolean_t       iscost;
4282         uint_t          val_cnt = *val_cntp;
4283         val_desc_t      *vdp = *vdpp;
4284 
4285         if (val_cnt != 1)
4286                 return (DLADM_STATUS_BADVALCNT);
4287 
4288         if (prop_val == NULL) {
4289                 vdp->vd_val = 0;
4290         } else {
4291                 /* Only stp_priority and stp_cost use this function */
4292                 iscost = strcmp(pd->pd_name, "stp_cost") == 0;
4293 
4294                 if (iscost && strcmp(prop_val[0], "auto") == 0) {
4295                         /* Illegal value 0 is allowed to mean "automatic" */
4296                         vdp->vd_val = 0;
4297                 } else {
4298                         errno = 0;
4299                         vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4300                         if (errno != 0 || *cp != '\0')
4301                                 return (DLADM_STATUS_BADVAL);
4302                 }
4303         }
4304 
4305         if (iscost) {
4306                 return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL :
4307                     DLADM_STATUS_OK);
4308         } else {
4309                 if (vdp->vd_val > 255)
4310                         return (DLADM_STATUS_BADVAL);
4311                 /*
4312                  * If the user is setting stp_mcheck non-zero, then (per the
4313                  * IEEE management standards and UNH testing) we need to check
4314                  * whether this link is part of a bridge that is running RSTP.
4315                  * If it's not, then setting the flag is an error.  Note that
4316                  * errors are intentionally discarded here; it's the value
4317                  * that's the problem -- it's not a bad value, merely one that
4318                  * can't be used now.
4319                  */
4320                 if (strcmp(pd->pd_name, "stp_mcheck") == 0 &&
4321                     vdp->vd_val != 0) {
4322                         char bridge[MAXLINKNAMELEN];
4323                         UID_STP_CFG_T cfg;
4324                         dladm_bridge_prot_t brprot;
4325 
4326                         if (dladm_bridge_getlink(handle, linkid, bridge,
4327                             sizeof (bridge)) != DLADM_STATUS_OK ||
4328                             dladm_bridge_get_properties(bridge, &cfg,
4329                             &brprot) != DLADM_STATUS_OK)
4330                                 return (DLADM_STATUS_FAILED);
4331                         if (cfg.force_version <= 1)
4332                                 return (DLADM_STATUS_FAILED);
4333                 }
4334                 return (DLADM_STATUS_OK);
4335         }
4336 }
4337 
4338 /* ARGSUSED */
4339 static dladm_status_t
4340 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd,
4341     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4342     datalink_media_t media, uint_t flags, uint_t *perm_flags)
4343 {
4344         dladm_status_t retv;
4345         uint_t val;
4346 
4347         if (flags != 0)
4348                 return (DLADM_STATUS_NOTSUP);
4349         *perm_flags = MAC_PROP_PERM_RW;
4350         *val_cnt = 1;
4351         retv = dladm_bridge_get_forwarding(handle, linkid, &val);
4352         if (retv == DLADM_STATUS_NOTFOUND) {
4353                 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4354                     prop_val, val_cnt) != DLADM_STATUS_OK)
4355                         (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4356                             DLADM_PROP_VAL_MAX);
4357                 return (DLADM_STATUS_OK);
4358         }
4359         if (retv == DLADM_STATUS_OK)
4360                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val);
4361         else
4362                 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4363         return (retv);
4364 }
4365 
4366 /* ARGSUSED */
4367 static dladm_status_t
4368 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4369     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4370 {
4371         /* Tell the running daemon, if any */
4372         return (dladm_bridge_refresh(handle, linkid));
4373 }
4374 
4375 /* ARGSUSED */
4376 static dladm_status_t
4377 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4378     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4379     datalink_media_t media, uint_t flags, uint_t *perm_flags)
4380 {
4381         dladm_status_t status;
4382         dld_ioc_macprop_t *dip;
4383         uint16_t pvid;
4384 
4385         if (flags != 0)
4386                 return (DLADM_STATUS_NOTSUP);
4387         *perm_flags = MAC_PROP_PERM_RW;
4388         *val_cnt = 1;
4389         dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4390             0, &status);
4391         if (dip == NULL)
4392                 return (status);
4393         status = i_dladm_macprop(handle, dip, B_FALSE);
4394         if (status == DLADM_STATUS_OK) {
4395                 (void) memcpy(&pvid, dip->pr_val, sizeof (pvid));
4396                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid);
4397         } else {
4398                 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4399         }
4400         free(dip);
4401         return (status);
4402 }
4403 
4404 /* ARGSUSED */
4405 static dladm_status_t
4406 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4407     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4408 {
4409         dladm_status_t status;
4410         dld_ioc_macprop_t *dip;
4411         uint16_t pvid;
4412 
4413         dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4414             0, &status);
4415         if (dip == NULL)
4416                 return (status);
4417         pvid = vdp->vd_val;
4418         (void) memcpy(dip->pr_val, &pvid, sizeof (pvid));
4419         status = i_dladm_macprop(handle, dip, B_TRUE);
4420         free(dip);
4421         if (status != DLADM_STATUS_OK)
4422                 return (status);
4423 
4424         /* Tell the running daemon, if any */
4425         return (dladm_bridge_refresh(handle, linkid));
4426 }
4427 
4428 /* ARGSUSED */
4429 static dladm_status_t
4430 check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4431     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4432     val_desc_t **vdpp, datalink_media_t media)
4433 {
4434         char            *cp;
4435         uint_t          val_cnt = *val_cntp;
4436         val_desc_t      *vdp = *vdpp;
4437 
4438         if (val_cnt != 1)
4439                 return (DLADM_STATUS_BADVALCNT);
4440 
4441         if (prop_val == NULL) {
4442                 vdp->vd_val = 1;
4443         } else {
4444                 errno = 0;
4445                 vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4446                 if (errno != 0 || *cp != '\0')
4447                         return (DLADM_STATUS_BADVAL);
4448         }
4449 
4450         return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL :
4451             DLADM_STATUS_OK);
4452 }
4453 
4454 dladm_status_t
4455 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf,
4456     mac_prop_id_t cmd, size_t len, boolean_t set)
4457 {
4458         uint32_t                flags;
4459         dladm_status_t          status;
4460         uint32_t                media;
4461         dld_ioc_macprop_t       *dip;
4462         void                    *dp;
4463 
4464         if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
4465             &media, NULL, 0)) != DLADM_STATUS_OK) {
4466                 return (status);
4467         }
4468 
4469         if (media != DL_WIFI)
4470                 return (DLADM_STATUS_BADARG);
4471 
4472         if (!(flags & DLADM_OPT_ACTIVE))
4473                 return (DLADM_STATUS_TEMPONLY);
4474 
4475         if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
4476                 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
4477 
4478         dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
4479         if (dip == NULL)
4480                 return (DLADM_STATUS_NOMEM);
4481 
4482         dp = (uchar_t *)dip->pr_val;
4483         if (set)
4484                 (void) memcpy(dp, buf, len);
4485 
4486         status = i_dladm_macprop(handle, dip, set);
4487         if (status == DLADM_STATUS_OK) {
4488                 if (!set)
4489                         (void) memcpy(buf, dp, len);
4490         }
4491 
4492         free(dip);
4493         return (status);
4494 }
4495 
4496 dladm_status_t
4497 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
4498 {
4499         return (dladm_parse_args(str, listp, novalues));
4500 }
4501 
4502 /*
4503  * Retrieve the one link property from the database
4504  */
4505 /*ARGSUSED*/
4506 static int
4507 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid,
4508     const char *prop_name, void *arg)
4509 {
4510         dladm_arg_list_t        *proplist = arg;
4511         dladm_arg_info_t        *aip = NULL;
4512 
4513         aip = &proplist->al_info[proplist->al_count];
4514         /*
4515          * it is fine to point to prop_name since prop_name points to the
4516          * prop_table[n].pd_name.
4517          */
4518         aip->ai_name = prop_name;
4519 
4520         (void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
4521             prop_name, aip->ai_val, &aip->ai_count);
4522 
4523         if (aip->ai_count != 0)
4524                 proplist->al_count++;
4525 
4526         return (DLADM_WALK_CONTINUE);
4527 }
4528 
4529 
4530 /*
4531  * Retrieve all link properties for a link from the database and
4532  * return a property list.
4533  */
4534 dladm_status_t
4535 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid,
4536     dladm_arg_list_t **listp)
4537 {
4538         dladm_arg_list_t        *list;
4539         dladm_status_t          status = DLADM_STATUS_OK;
4540 
4541         list = calloc(1, sizeof (dladm_arg_list_t));
4542         if (list == NULL)
4543                 return (dladm_errno2status(errno));
4544 
4545         status = dladm_walk_linkprop(handle, linkid, list,
4546             i_dladm_get_one_prop);
4547 
4548         *listp = list;
4549         return (status);
4550 }
4551 
4552 /*
4553  * Retrieve the named property from a proplist, check the value and
4554  * convert to a kernel structure.
4555  */
4556 static dladm_status_t
4557 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
4558     dladm_arg_list_t *proplist, const char *name, uint_t flags, void *arg)
4559 {
4560         dladm_status_t          status;
4561         dladm_arg_info_t        *aip = NULL;
4562         int                     i, j;
4563 
4564         /* Find named property in proplist */
4565         for (i = 0; i < proplist->al_count; i++) {
4566                 aip = &proplist->al_info[i];
4567                 if (strcasecmp(aip->ai_name, name) == 0)
4568                         break;
4569         }
4570 
4571         /* Property not in list */
4572         if (i == proplist->al_count)
4573                 return (DLADM_STATUS_OK);
4574 
4575         for (i = 0; i < DLADM_MAX_PROPS; i++) {
4576                 prop_desc_t     *pdp = &prop_table[i];
4577                 val_desc_t      *vdp;
4578 
4579                 vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
4580                 if (vdp == NULL)
4581                         return (DLADM_STATUS_NOMEM);
4582 
4583                 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
4584                         continue;
4585 
4586                 if (aip->ai_val == NULL)
4587                         return (DLADM_STATUS_BADARG);
4588 
4589                 /* Check property value */
4590                 if (pdp->pd_check != NULL) {
4591                         status = pdp->pd_check(handle, pdp, 0, aip->ai_val,
4592                             &(aip->ai_count), flags, &vdp, 0);
4593                 } else {
4594                         status = DLADM_STATUS_BADARG;
4595                 }
4596 
4597                 if (status != DLADM_STATUS_OK)
4598                         return (status);
4599 
4600                 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
4601                         resource_prop_t *rpp = &rsrc_prop_table[j];
4602 
4603                         if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
4604                                 continue;
4605 
4606                         /* Extract kernel structure */
4607                         if (rpp->rp_extract != NULL) {
4608                                 status = rpp->rp_extract(vdp,
4609                                     aip->ai_count, arg);
4610                         } else {
4611                                 status = DLADM_STATUS_BADARG;
4612                         }
4613                         break;
4614                 }
4615 
4616                 if (status != DLADM_STATUS_OK)
4617                         return (status);
4618 
4619                 break;
4620         }
4621         return (status);
4622 }
4623 
4624 /*
4625  * Extract properties from a proplist and convert to mac_resource_props_t.
4626  */
4627 dladm_status_t
4628 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
4629     mac_resource_props_t *mrp, uint_t flags)
4630 {
4631         dladm_status_t  status;
4632         int             i;
4633 
4634         for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
4635                 status = i_dladm_link_proplist_extract_one(handle,
4636                     proplist, rsrc_prop_table[i].rp_name, flags, mrp);
4637                 if (status != DLADM_STATUS_OK)
4638                         return (status);
4639         }
4640         return (status);
4641 }
4642 
4643 static const char *
4644 dladm_perm2str(uint_t perm, char *buf)
4645 {
4646         (void) snprintf(buf, DLADM_STRSIZE, "%c%c",
4647             ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-',
4648             ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-');
4649         return (buf);
4650 }
4651 
4652 dladm_status_t
4653 dladm_get_state(dladm_handle_t handle, datalink_id_t linkid,
4654     link_state_t *state)
4655 {
4656         uint_t                  perms;
4657 
4658         return (i_dladm_get_public_prop(handle, linkid, "state", 0,
4659             &perms, state, sizeof (*state)));
4660 }
4661 
4662 boolean_t
4663 dladm_attr_is_linkprop(const char *name)
4664 {
4665         /* non-property attribute names */
4666         const char *nonprop[] = {
4667                 /* dlmgmtd core attributes */
4668                 "name",
4669                 "class",
4670                 "media",
4671                 FPHYMAJ,
4672                 FPHYINST,
4673                 FDEVNAME,
4674 
4675                 /* other attributes for vlan, aggr, etc */
4676                 DLADM_ATTR_NAMES
4677         };
4678         boolean_t       is_nonprop = B_FALSE;
4679         int             i;
4680 
4681         for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) {
4682                 if (strcmp(name, nonprop[i]) == 0) {
4683                         is_nonprop = B_TRUE;
4684                         break;
4685                 }
4686         }
4687 
4688         return (!is_nonprop);
4689 }
4690 
4691 dladm_status_t
4692 dladm_linkprop_is_set(dladm_handle_t handle, datalink_id_t linkid,
4693     dladm_prop_type_t type, const char *prop_name, boolean_t *is_set)
4694 {
4695         char            *buf, **propvals;
4696         uint_t          valcnt = DLADM_MAX_PROP_VALCNT;
4697         int             i;
4698         dladm_status_t  status = DLADM_STATUS_OK;
4699         size_t          bufsize;
4700 
4701         *is_set = B_FALSE;
4702 
4703         bufsize = (sizeof (char *) + DLADM_PROP_VAL_MAX) *
4704             DLADM_MAX_PROP_VALCNT;
4705         if ((buf = calloc(1, bufsize)) == NULL)
4706                 return (DLADM_STATUS_NOMEM);
4707 
4708         propvals = (char **)(void *)buf;
4709         for (i = 0; i < valcnt; i++) {
4710                 propvals[i] = buf +
4711                     sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4712                     i * DLADM_PROP_VAL_MAX;
4713         }
4714 
4715         if (dladm_get_linkprop(handle, linkid, type, prop_name, propvals,
4716             &valcnt) != DLADM_STATUS_OK) {
4717                 goto done;
4718         }
4719 
4720         /*
4721          * valcnt is always set to 1 by get_pool(), hence we need to check
4722          * for a non-null string to see if it is set. For protection,
4723          * secondary-macs and allowed-ips, we can check either the *propval
4724          * or the valcnt.
4725          */
4726         if ((strcmp(prop_name, "pool") == 0 ||
4727             strcmp(prop_name, "protection") == 0 ||
4728             strcmp(prop_name, "secondary-macs") == 0 ||
4729             strcmp(prop_name, "allowed-ips") == 0) &&
4730             (strlen(*propvals) != 0)) {
4731                 *is_set = B_TRUE;
4732         } else if ((strcmp(prop_name, "cpus") == 0) && (valcnt != 0)) {
4733                 *is_set = B_TRUE;
4734         } else if ((strcmp(prop_name, "_softmac") == 0) && (valcnt != 0) &&
4735             (strcmp(propvals[0], "true") == 0)) {
4736                 *is_set = B_TRUE;
4737         }
4738 
4739 done:
4740         if (buf != NULL)
4741                 free(buf);
4742         return (status);
4743 }
4744 
4745 /* ARGSUSED */
4746 static dladm_status_t
4747 get_linkmode_prop(dladm_handle_t handle, prop_desc_t *pdp,
4748     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4749     datalink_media_t media, uint_t flags, uint_t *perm_flags)
4750 {
4751         char                    *s;
4752         uint32_t                v;
4753         dladm_status_t          status;
4754 
4755         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4756             perm_flags, &v, sizeof (v));
4757         if (status != DLADM_STATUS_OK)
4758                 return (status);
4759 
4760         switch (v) {
4761         case DLADM_PART_CM_MODE:
4762                 s = "cm";
4763                 break;
4764         case DLADM_PART_UD_MODE:
4765                 s = "ud";
4766                 break;
4767         default:
4768                 s = "";
4769                 break;
4770         }
4771         (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", s);
4772 
4773         *val_cnt = 1;
4774         return (DLADM_STATUS_OK);
4775 }