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