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