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 
1500 static int
1501 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
1502 {
1503         char                    root[MAXPATHLEN];
1504         zone_get_devroot_t      real_zone_get_devroot;
1505         void                    *dlhandle;
1506         void                    *sym;
1507         int                     ret;
1508 
1509         if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
1510                 return (-1);
1511 
1512         if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
1513                 (void) dlclose(dlhandle);
1514                 return (-1);
1515         }
1516 
1517         real_zone_get_devroot = (zone_get_devroot_t)sym;
1518 
1519         if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
1520                 (void) snprintf(dev, devlen, "%s%s", root, "/dev");
1521         (void) dlclose(dlhandle);
1522         return (ret);
1523 }
1524 
1525 static dladm_status_t
1526 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid,
1527     datalink_id_t linkid, boolean_t add)
1528 {
1529         char            path[MAXPATHLEN];
1530         char            name[MAXLINKNAMELEN];
1531         di_prof_t       prof = NULL;
1532         char            zone_name[ZONENAME_MAX];
1533         dladm_status_t  status;
1534         int             ret;
1535 
1536         if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
1537                 return (dladm_errno2status(errno));
1538         if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
1539                 return (dladm_errno2status(errno));
1540         if (di_prof_init(path, &prof) != 0)
1541                 return (dladm_errno2status(errno));
1542 
1543         status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN);
1544         if (status != DLADM_STATUS_OK)
1545                 goto cleanup;
1546 
1547         if (add)
1548                 ret = di_prof_add_dev(prof, name);
1549         else
1550                 ret = di_prof_add_exclude(prof, name);
1551 
1552         if (ret != 0) {
1553                 status = dladm_errno2status(errno);
1554                 goto cleanup;
1555         }
1556 
1557         if (di_prof_commit(prof) != 0)
1558                 status = dladm_errno2status(errno);
1559 cleanup:
1560         if (prof)
1561                 di_prof_fini(prof);
1562 
1563         return (status);
1564 }
1565 
1566 /* ARGSUSED */
1567 static dladm_status_t
1568 set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1569     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1570 {
1571         dladm_status_t          status = DLADM_STATUS_OK;
1572         zoneid_t                zid_old, zid_new;
1573         dld_ioc_zid_t           *dzp;
1574 
1575         if (val_cnt != 1)
1576                 return (DLADM_STATUS_BADVALCNT);
1577 
1578         dzp = (dld_ioc_zid_t *)vdp->vd_val;
1579 
1580         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1581             NULL, &zid_old, sizeof (zid_old));
1582         if (status != DLADM_STATUS_OK)
1583                 return (status);
1584 
1585         zid_new = dzp->diz_zid;
1586         if (zid_new == zid_old)
1587                 return (DLADM_STATUS_OK);
1588 
1589         if ((status = set_public_prop(handle, pdp, linkid, vdp, val_cnt,
1590             flags, media)) != DLADM_STATUS_OK)
1591                 return (status);
1592 
1593         /*
1594          * It is okay to fail to update the /dev entry (some vanity-named
1595          * links do not have a /dev entry).
1596          */
1597         if (zid_old != GLOBAL_ZONEID) {
1598                 (void) i_dladm_update_deventry(handle, zid_old, linkid,
1599                     B_FALSE);
1600         }
1601         if (zid_new != GLOBAL_ZONEID)
1602                 (void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE);
1603 
1604         return (DLADM_STATUS_OK);
1605 }
1606 
1607 /* ARGSUSED */
1608 static dladm_status_t
1609 check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1610     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1611     datalink_media_t media)
1612 {
1613         char            *zone_name;
1614         zoneid_t        zoneid;
1615         dladm_status_t  status = DLADM_STATUS_OK;
1616         dld_ioc_zid_t   *dzp;
1617         uint_t          val_cnt = *val_cntp;
1618         val_desc_t      *vdp = *vdpp;
1619 
1620         if (val_cnt != 1)
1621                 return (DLADM_STATUS_BADVALCNT);
1622 
1623         dzp = malloc(sizeof (dld_ioc_zid_t));
1624         if (dzp == NULL)
1625                 return (DLADM_STATUS_NOMEM);
1626 
1627         zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME;
1628         if ((zoneid = getzoneidbyname(zone_name)) == -1) {
1629                 status = DLADM_STATUS_BADVAL;
1630                 goto done;
1631         }
1632 
1633         if (zoneid != GLOBAL_ZONEID) {
1634                 ushort_t        flags;
1635 
1636                 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
1637                     sizeof (flags)) < 0) {
1638                         status = dladm_errno2status(errno);
1639                         goto done;
1640                 }
1641 
1642                 if (!(flags & ZF_NET_EXCL)) {
1643                         status = DLADM_STATUS_BADVAL;
1644                         goto done;
1645                 }
1646         }
1647 
1648         (void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
1649 
1650         dzp->diz_zid = zoneid;
1651         dzp->diz_linkid = linkid;
1652 
1653         vdp->vd_val = (uintptr_t)dzp;
1654         return (DLADM_STATUS_OK);
1655 done:
1656         free(dzp);
1657         return (status);
1658 }
1659 
1660 /* ARGSUSED */
1661 static dladm_status_t
1662 get_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1663     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1664     uint_t flags, uint_t *perm_flags)
1665 {
1666         mac_resource_props_t    mrp;
1667         dladm_status_t          status;
1668 
1669         status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
1670             perm_flags, &mrp, sizeof (mrp));
1671         if (status != DLADM_STATUS_OK)
1672                 return (status);
1673 
1674         if ((mrp.mrp_mask & MRP_MAXBW) == 0) {
1675                 *val_cnt = 0;
1676                 return (DLADM_STATUS_OK);
1677         }
1678 
1679         (void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]);
1680         *val_cnt = 1;
1681         return (DLADM_STATUS_OK);
1682 }
1683 
1684 /* ARGSUSED */
1685 static dladm_status_t
1686 check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1687     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1688     datalink_media_t media)
1689 {
1690         uint64_t        *maxbw;
1691         dladm_status_t  status = DLADM_STATUS_OK;
1692         uint_t          val_cnt = *val_cntp;
1693         val_desc_t      *vdp = *vdpp;
1694 
1695         if (val_cnt != 1)
1696                 return (DLADM_STATUS_BADVALCNT);
1697 
1698         maxbw = malloc(sizeof (uint64_t));
1699         if (maxbw == NULL)
1700                 return (DLADM_STATUS_NOMEM);
1701 
1702         status = dladm_str2bw(*prop_val, maxbw);
1703         if (status != DLADM_STATUS_OK) {
1704                 free(maxbw);
1705                 return (status);
1706         }
1707 
1708         if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
1709                 free(maxbw);
1710                 return (DLADM_STATUS_MINMAXBW);
1711         }
1712 
1713         vdp->vd_val = (uintptr_t)maxbw;
1714         return (DLADM_STATUS_OK);
1715 }
1716 
1717 /* ARGSUSED */
1718 dladm_status_t
1719 extract_maxbw(val_desc_t *vdp, uint_t cnt, void *arg)
1720 {
1721         mac_resource_props_t *mrp = arg;
1722 
1723         if (vdp->vd_val == RESET_VAL) {
1724                 mrp->mrp_maxbw = MRP_MAXBW_RESETVAL;
1725         } else {
1726                 bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
1727         }
1728         mrp->mrp_mask |= MRP_MAXBW;
1729 
1730         return (DLADM_STATUS_OK);
1731 }
1732 
1733 /* ARGSUSED */
1734 static dladm_status_t
1735 get_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1736     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1737     uint_t flags, uint_t *perm_flags)
1738 {
1739         dladm_status_t          status;
1740         mac_resource_props_t    mrp;
1741         mac_propval_range_t     *pv_range;
1742         int                     err;
1743 
1744         if (strcmp(pdp->pd_name, "cpus-effective") == 0) {
1745                 status = i_dladm_get_public_prop(handle, linkid,
1746                     "resource-effective", flags, perm_flags, &mrp,
1747                     sizeof (mrp));
1748         } else {
1749                 status = i_dladm_get_public_prop(handle, linkid,
1750                     "resource", flags, perm_flags, &mrp, sizeof (mrp));
1751         }
1752 
1753         if (status != DLADM_STATUS_OK)
1754                 return (status);
1755 
1756         if (mrp.mrp_ncpus > *val_cnt)
1757                 return (DLADM_STATUS_TOOSMALL);
1758 
1759         if (mrp.mrp_ncpus == 0) {
1760                 *val_cnt = 0;
1761                 return (DLADM_STATUS_OK);
1762         }
1763 
1764         /* Sort CPU list and convert it to a mac_propval_range */
1765         status = dladm_list2range(mrp.mrp_cpu, mrp.mrp_ncpus,
1766             MAC_PROPVAL_UINT32, &pv_range);
1767         if (status != DLADM_STATUS_OK)
1768                 return (status);
1769 
1770         /* Write CPU ranges and individual CPUs */
1771         err = dladm_range2strs(pv_range, prop_val);
1772         if (err != 0) {
1773                 free(pv_range);
1774                 return (dladm_errno2status(err));
1775         }
1776 
1777         *val_cnt = pv_range->mpr_count;
1778         free(pv_range);
1779 
1780         return (DLADM_STATUS_OK);
1781 }
1782 
1783 /* ARGSUSED */
1784 static dladm_status_t
1785 check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1786     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1787     datalink_media_t media)
1788 {
1789         int                     i, j, rc;
1790         long                    nproc = sysconf(_SC_NPROCESSORS_CONF);
1791         mac_resource_props_t    mrp;
1792         mac_propval_range_t     *pv_range;
1793         uint_t                  perm_flags;
1794         uint32_t                ncpus;
1795         uint32_t                *cpus = mrp.mrp_cpu;
1796         val_desc_t              *vdp = *vdpp;
1797         val_desc_t              *newvdp;
1798         uint_t                  val_cnt = *val_cntp;
1799         dladm_status_t          status = DLADM_STATUS_OK;
1800 
1801         /* Get the current pool property */
1802         status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1803             &perm_flags, &mrp, sizeof (mrp));
1804 
1805         if (status == DLADM_STATUS_OK) {
1806                 /* Can't set cpus if a pool is set */
1807                 if (strlen(mrp.mrp_pool) != 0)
1808                         return (DLADM_STATUS_POOLCPU);
1809         }
1810 
1811         /* Read ranges and convert to mac_propval_range */
1812         status = dladm_strs2range(prop_val, val_cnt, MAC_PROPVAL_UINT32,
1813             &pv_range);
1814         if (status != DLADM_STATUS_OK)
1815                 goto done1;
1816 
1817         /* Convert mac_propval_range to a single CPU list */
1818         ncpus = MRP_NCPUS;
1819         status = dladm_range2list(pv_range, cpus, &ncpus);
1820         if (status != DLADM_STATUS_OK)
1821                 goto done1;
1822 
1823         /*
1824          * If a range of CPUs was entered, update value count and reallocate
1825          * the array of val_desc_t's.  The array allocated was sized for
1826          * indvidual elements, but needs to be reallocated to accomodate the
1827          * expanded list of CPUs.
1828          */
1829         if (val_cnt < ncpus) {
1830                 newvdp = calloc(*val_cntp, sizeof (val_desc_t));
1831                 if (newvdp == NULL) {
1832                         status = DLADM_STATUS_NOMEM;
1833                         goto done1;
1834                 }
1835                 vdp = newvdp;
1836         }
1837 
1838         /* Check if all CPUs in the list are online */
1839         for (i = 0; i < ncpus; i++) {
1840                 if (cpus[i] >= nproc) {
1841                         status = DLADM_STATUS_BADCPUID;
1842                         goto done2;
1843                 }
1844 
1845                 rc = p_online(cpus[i], P_STATUS);
1846                 if (rc < 1) {
1847                         status = DLADM_STATUS_CPUERR;
1848                         goto done2;
1849                 }
1850 
1851                 if (rc != P_ONLINE) {
1852                         status = DLADM_STATUS_CPUNOTONLINE;
1853                         goto done2;
1854                 }
1855 
1856                 vdp[i].vd_val = (uintptr_t)cpus[i];
1857         }
1858 
1859         /* Check for duplicate CPUs */
1860         for (i = 0; i < *val_cntp; i++) {
1861                 for (j = 0; j < *val_cntp; j++) {
1862                         if (i != j && vdp[i].vd_val == vdp[j].vd_val) {
1863                                 status = DLADM_STATUS_BADVAL;
1864                                 goto done2;
1865                         }
1866                 }
1867         }
1868 
1869         /* Update *val_cntp and *vdpp if everything was OK */
1870         if (val_cnt < ncpus) {
1871                 *val_cntp = ncpus;
1872                 free(*vdpp);
1873                 *vdpp = newvdp;
1874         }
1875 
1876         status = DLADM_STATUS_OK;
1877         goto done1;
1878 
1879 done2:
1880         free(newvdp);
1881 done1:
1882         free(pv_range);
1883         return (status);
1884 }
1885 
1886 /* ARGSUSED */
1887 dladm_status_t
1888 extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg)
1889 {
1890         mac_resource_props_t    *mrp = arg;
1891         int                     i;
1892 
1893         if (vdp[0].vd_val == RESET_VAL) {
1894                 bzero(&mrp->mrp_cpus, sizeof (mac_cpus_t));
1895                 mrp->mrp_mask |= MRP_CPUS;
1896                 return (DLADM_STATUS_OK);
1897         }
1898 
1899         for (i = 0; i < cnt; i++)
1900                 mrp->mrp_cpu[i] = (uint32_t)vdp[i].vd_val;
1901 
1902         mrp->mrp_ncpus = cnt;
1903         mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC);
1904         mrp->mrp_fanout_mode = MCM_CPUS;
1905         mrp->mrp_rx_intr_cpu = -1;
1906 
1907         return (DLADM_STATUS_OK);
1908 }
1909 
1910 /*
1911  * Get the pool datalink property from the kernel.  This is used
1912  * for both the user specified pool and effective pool properties.
1913  */
1914 /* ARGSUSED */
1915 static dladm_status_t
1916 get_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1917     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1918     uint_t flags, uint_t *perm_flags)
1919 {
1920         mac_resource_props_t    mrp;
1921         dladm_status_t          status;
1922 
1923         if (strcmp(pdp->pd_name, "pool-effective") == 0) {
1924                 status = i_dladm_get_public_prop(handle, linkid,
1925                     "resource-effective", flags, perm_flags, &mrp,
1926                     sizeof (mrp));
1927         } else {
1928                 status = i_dladm_get_public_prop(handle, linkid,
1929                     "resource", flags, perm_flags, &mrp, sizeof (mrp));
1930         }
1931 
1932         if (status != DLADM_STATUS_OK)
1933                 return (status);
1934 
1935         if (strlen(mrp.mrp_pool) == 0) {
1936                 (*prop_val)[0] = '\0';
1937         } else {
1938                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
1939                     "%s", mrp.mrp_pool);
1940         }
1941         *val_cnt = 1;
1942 
1943         return (DLADM_STATUS_OK);
1944 }
1945 
1946 /* ARGSUSED */
1947 static dladm_status_t
1948 check_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1949     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1950     datalink_media_t media)
1951 {
1952         pool_conf_t             *poolconf;
1953         pool_t                  *pool;
1954         mac_resource_props_t    mrp;
1955         dladm_status_t          status;
1956         uint_t                  perm_flags;
1957         char                    *poolname;
1958         val_desc_t              *vdp = *vdpp;
1959 
1960         /* Get the current cpus property */
1961         status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1962             &perm_flags, &mrp, sizeof (mrp));
1963 
1964         if (status == DLADM_STATUS_OK) {
1965                 /* Can't set pool if cpus are set */
1966                 if (mrp.mrp_ncpus != 0)
1967                         return (DLADM_STATUS_POOLCPU);
1968         }
1969 
1970         poolname = malloc(sizeof (mrp.mrp_pool));
1971         if (poolname == NULL)
1972                 return (DLADM_STATUS_NOMEM);
1973 
1974         /* Check for pool's availability if not booting */
1975         if ((flags & DLADM_OPT_BOOT) == 0) {
1976 
1977                 /* Allocate and open pool configuration */
1978                 if ((poolconf = pool_conf_alloc()) == NULL)
1979                         return (DLADM_STATUS_BADVAL);
1980 
1981                 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY)
1982                     != PO_SUCCESS) {
1983                         pool_conf_free(poolconf);
1984                         return (DLADM_STATUS_BADVAL);
1985                 }
1986 
1987                 /* Look for pool name */
1988                 if ((pool = pool_get_pool(poolconf, *prop_val)) == NULL) {
1989                         pool_conf_free(poolconf);
1990                         return (DLADM_STATUS_BADVAL);
1991                 }
1992 
1993                 pool_conf_free(poolconf);
1994                 free(pool);
1995         }
1996 
1997         (void) strlcpy(poolname, *prop_val, sizeof (mrp.mrp_pool));
1998         vdp->vd_val = (uintptr_t)poolname;
1999 
2000         return (DLADM_STATUS_OK);
2001 }
2002 
2003 /* ARGSUSED */
2004 dladm_status_t
2005 extract_pool(val_desc_t *vdp, uint_t cnt, void *arg)
2006 {
2007         mac_resource_props_t    *mrp = (mac_resource_props_t *)arg;
2008 
2009         if (vdp->vd_val == RESET_VAL) {
2010                 bzero(&mrp->mrp_pool, sizeof (mrp->mrp_pool));
2011                 mrp->mrp_mask |= MRP_POOL;
2012                 return (DLADM_STATUS_OK);
2013         }
2014 
2015         (void) strlcpy(mrp->mrp_pool, (char *)vdp->vd_val,
2016             sizeof (mrp->mrp_pool));
2017         mrp->mrp_mask |= MRP_POOL;
2018         /*
2019          * Use MCM_CPUS since the fanout count is not user specified
2020          * and will be determined by the cpu list generated from the
2021          * pool.
2022          */
2023         mrp->mrp_fanout_mode = MCM_CPUS;
2024 
2025         return (DLADM_STATUS_OK);
2026 }
2027 
2028 /* ARGSUSED */
2029 static dladm_status_t
2030 get_priority(dladm_handle_t handle, prop_desc_t *pdp,
2031     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2032     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2033 {
2034         mac_resource_props_t    mrp;
2035         mac_priority_level_t    pri;
2036         dladm_status_t          status;
2037 
2038         status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2039             perm_flags, &mrp, sizeof (mrp));
2040         if (status != DLADM_STATUS_OK)
2041                 return (status);
2042 
2043         pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH :
2044             mrp.mrp_priority;
2045 
2046         (void) dladm_pri2str(pri, prop_val[0]);
2047         *val_cnt = 1;
2048         return (DLADM_STATUS_OK);
2049 }
2050 
2051 /* ARGSUSED */
2052 dladm_status_t
2053 extract_priority(val_desc_t *vdp, uint_t cnt, void *arg)
2054 {
2055         mac_resource_props_t *mrp = arg;
2056 
2057         if (cnt != 1)
2058                 return (DLADM_STATUS_BADVAL);
2059 
2060         mrp->mrp_priority = (mac_priority_level_t)vdp->vd_val;
2061         mrp->mrp_mask |= MRP_PRIORITY;
2062 
2063         return (DLADM_STATUS_OK);
2064 }
2065 
2066 /*
2067  * Determines the size of the structure that needs to be sent to drivers
2068  * for retrieving the property range values.
2069  */
2070 static int
2071 i_dladm_range_size(mac_propval_range_t *r, size_t *sz, uint_t *rcount)
2072 {
2073         uint_t count = r->mpr_count;
2074 
2075         *sz = sizeof (mac_propval_range_t);
2076         *rcount = count;
2077         --count;
2078 
2079         switch (r->mpr_type) {
2080         case MAC_PROPVAL_UINT32:
2081                 *sz += (count * sizeof (mac_propval_uint32_range_t));
2082                 return (0);
2083         default:
2084                 break;
2085         }
2086         *sz = 0;
2087         *rcount = 0;
2088         return (EINVAL);
2089 }
2090 
2091 
2092 /* ARGSUSED */
2093 static dladm_status_t
2094 check_rings(dladm_handle_t handle, prop_desc_t *pdp,
2095     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2096     val_desc_t **vp, datalink_media_t media)
2097 {
2098         uint_t          val_cnt = *val_cntp;
2099         val_desc_t      *v = *vp;
2100 
2101         if (val_cnt != 1)
2102                 return (DLADM_STATUS_BADVAL);
2103         if (strncasecmp(prop_val[0], "hw", strlen("hw")) == 0) {
2104                 v->vd_val = UNSPEC_VAL;
2105         } else if (strncasecmp(prop_val[0], "sw", strlen("sw")) == 0) {
2106                 v->vd_val = 0;
2107         } else {
2108                 v->vd_val = strtoul(prop_val[0], NULL, 0);
2109                 if (v->vd_val == 0)
2110                         return (DLADM_STATUS_BADVAL);
2111         }
2112         return (DLADM_STATUS_OK);
2113 }
2114 
2115 /* ARGSUSED */
2116 static dladm_status_t
2117 get_rings_range(dladm_handle_t handle, prop_desc_t *pdp,
2118     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2119     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2120 {
2121         dld_ioc_macprop_t *dip;
2122         dladm_status_t status = DLADM_STATUS_OK;
2123         mac_propval_range_t *rangep;
2124         size_t  sz;
2125         mac_propval_uint32_range_t *ur;
2126 
2127         sz = sizeof (mac_propval_range_t);
2128 
2129         if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
2130             &status)) == NULL)
2131                 return (status);
2132 
2133         status = i_dladm_macprop(handle, dip, B_FALSE);
2134         if (status != DLADM_STATUS_OK)
2135                 return (status);
2136 
2137         rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
2138         *val_cnt = 1;
2139         ur = &rangep->mpr_range_uint32[0];
2140         /* This is the case where the dev doesn't have any rings/groups */
2141         if (rangep->mpr_count == 0) {
2142                 (*prop_val)[0] = '\0';
2143         /*
2144          * This is the case where the dev supports rings, but static
2145          * grouping.
2146          */
2147         } else if (ur->mpur_min == ur->mpur_max &&
2148             ur->mpur_max == 0) {
2149                 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw");
2150         /*
2151          * This is the case where the dev supports rings and dynamic
2152          * grouping, but has only one value (say 2 rings and 2 groups).
2153          */
2154         } else if (ur->mpur_min == ur->mpur_max) {
2155                 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw,%d",
2156                     ur->mpur_min);
2157         /*
2158          * This is the case where the dev supports rings and dynamic
2159          * grouping and has a range of rings.
2160          */
2161         } else {
2162                 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX,
2163                     "sw,hw,<%ld-%ld>", ur->mpur_min, ur->mpur_max);
2164         }
2165         free(dip);
2166         return (status);
2167 }
2168 
2169 
2170 /* ARGSUSED */
2171 static dladm_status_t
2172 get_rxrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2173     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2174     uint_t flags, uint_t *perm_flags)
2175 {
2176         mac_resource_props_t    mrp;
2177         dladm_status_t          status;
2178         uint32_t                nrings = 0;
2179 
2180         /*
2181          * Get the number of (effective-)rings from the resource property.
2182          */
2183         if (strcmp(pdp->pd_name, "rxrings-effective") == 0) {
2184                 status = i_dladm_get_public_prop(handle, linkid,
2185                     "resource-effective", flags, perm_flags, &mrp,
2186                     sizeof (mrp));
2187         } else {
2188                 /*
2189                  * Get the permissions from the "rxrings" property.
2190                  */
2191                 status = i_dladm_get_public_prop(handle, linkid, "rxrings",
2192                     flags, perm_flags, NULL, 0);
2193                 if (status != DLADM_STATUS_OK)
2194                         return (status);
2195 
2196                 status = i_dladm_get_public_prop(handle, linkid,
2197                     "resource", flags, NULL, &mrp, sizeof (mrp));
2198         }
2199 
2200         if (status != DLADM_STATUS_OK)
2201                 return (status);
2202 
2203         if ((mrp.mrp_mask & MRP_RX_RINGS) == 0) {
2204                 *val_cnt = 0;
2205                 return (DLADM_STATUS_OK);
2206         }
2207         nrings = mrp.mrp_nrxrings;
2208         *val_cnt = 1;
2209         if (mrp.mrp_mask & MRP_RXRINGS_UNSPEC)
2210                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2211         else if (nrings == 0)
2212                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2213         else
2214                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2215         return (DLADM_STATUS_OK);
2216 }
2217 
2218 /* ARGSUSED */
2219 dladm_status_t
2220 extract_rxrings(val_desc_t *vdp, uint_t cnt, void *arg)
2221 {
2222         mac_resource_props_t    *mrp = (mac_resource_props_t *)arg;
2223 
2224         mrp->mrp_nrxrings = 0;
2225         if (vdp->vd_val == RESET_VAL)
2226                 mrp->mrp_mask = MRP_RINGS_RESET;
2227         else if (vdp->vd_val == UNSPEC_VAL)
2228                 mrp->mrp_mask = MRP_RXRINGS_UNSPEC;
2229         else
2230                 mrp->mrp_nrxrings = vdp->vd_val;
2231         mrp->mrp_mask |= MRP_RX_RINGS;
2232 
2233         return (DLADM_STATUS_OK);
2234 }
2235 
2236 /* ARGSUSED */
2237 static dladm_status_t
2238 get_txrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2239     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2240     uint_t flags, uint_t *perm_flags)
2241 {
2242         mac_resource_props_t    mrp;
2243         dladm_status_t          status;
2244         uint32_t                nrings = 0;
2245 
2246 
2247         /*
2248          * Get the number of (effective-)rings from the resource property.
2249          */
2250         if (strcmp(pdp->pd_name, "txrings-effective") == 0) {
2251                 status = i_dladm_get_public_prop(handle, linkid,
2252                     "resource-effective", flags, perm_flags, &mrp,
2253                     sizeof (mrp));
2254         } else {
2255                 /*
2256                  * Get the permissions from the "txrings" property.
2257                  */
2258                 status = i_dladm_get_public_prop(handle, linkid, "txrings",
2259                     flags, perm_flags, NULL, 0);
2260                 if (status != DLADM_STATUS_OK)
2261                         return (status);
2262 
2263                 /*
2264                  * Get the number of rings from the "resource" property.
2265                  */
2266                 status = i_dladm_get_public_prop(handle, linkid, "resource",
2267                     flags, NULL, &mrp, sizeof (mrp));
2268         }
2269 
2270         if (status != DLADM_STATUS_OK)
2271                 return (status);
2272 
2273         if ((mrp.mrp_mask & MRP_TX_RINGS) == 0) {
2274                 *val_cnt = 0;
2275                 return (DLADM_STATUS_OK);
2276         }
2277         nrings = mrp.mrp_ntxrings;
2278         *val_cnt = 1;
2279         if (mrp.mrp_mask & MRP_TXRINGS_UNSPEC)
2280                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2281         else if (nrings == 0)
2282                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2283         else
2284                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2285         return (DLADM_STATUS_OK);
2286 }
2287 
2288 /* ARGSUSED */
2289 dladm_status_t
2290 extract_txrings(val_desc_t *vdp, uint_t cnt, void *arg)
2291 {
2292         mac_resource_props_t    *mrp = (mac_resource_props_t *)arg;
2293 
2294         mrp->mrp_ntxrings = 0;
2295         if (vdp->vd_val == RESET_VAL)
2296                 mrp->mrp_mask = MRP_RINGS_RESET;
2297         else if (vdp->vd_val == UNSPEC_VAL)
2298                 mrp->mrp_mask = MRP_TXRINGS_UNSPEC;
2299         else
2300                 mrp->mrp_ntxrings = vdp->vd_val;
2301         mrp->mrp_mask |= MRP_TX_RINGS;
2302 
2303         return (DLADM_STATUS_OK);
2304 }
2305 
2306 /* ARGSUSED */
2307 static dladm_status_t
2308 get_cntavail(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2309     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
2310     uint_t *perm_flags)
2311 {
2312         if (flags & DLD_PROP_DEFAULT)
2313                 return (DLADM_STATUS_NOTDEFINED);
2314 
2315         return (get_uint32(handle, pdp, linkid, prop_val, val_cnt, media,
2316             flags, perm_flags));
2317 }
2318 
2319 /* ARGSUSED */
2320 static dladm_status_t
2321 set_resource(dladm_handle_t handle, prop_desc_t *pdp,
2322     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt,
2323     uint_t flags, datalink_media_t media)
2324 {
2325         mac_resource_props_t    mrp;
2326         dladm_status_t          status = DLADM_STATUS_OK;
2327         dld_ioc_macprop_t       *dip;
2328         int                     i;
2329 
2330         bzero(&mrp, sizeof (mac_resource_props_t));
2331         dip = i_dladm_buf_alloc_by_name(0, linkid, "resource",
2332             flags, &status);
2333 
2334         if (dip == NULL)
2335                 return (status);
2336 
2337         for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
2338                 resource_prop_t *rp = &rsrc_prop_table[i];
2339 
2340                 if (strcmp(pdp->pd_name, rp->rp_name) != 0)
2341                         continue;
2342 
2343                 status = rp->rp_extract(vdp, val_cnt, &mrp);
2344                 if (status != DLADM_STATUS_OK)
2345                         goto done;
2346 
2347                 break;
2348         }
2349 
2350         (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
2351         status = i_dladm_macprop(handle, dip, B_TRUE);
2352 
2353 done:
2354         free(dip);
2355         return (status);
2356 }
2357 
2358 /* ARGSUSED */
2359 static dladm_status_t
2360 get_protection(dladm_handle_t handle, prop_desc_t *pdp,
2361     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2362     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2363 {
2364         mac_resource_props_t    mrp;
2365         mac_protect_t           *p;
2366         dladm_status_t          status;
2367         uint32_t                i, cnt = 0, setbits[32];
2368 
2369         status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2370             perm_flags, &mrp, sizeof (mrp));
2371         if (status != DLADM_STATUS_OK)
2372                 return (status);
2373 
2374         p = &mrp.mrp_protect;
2375         if ((mrp.mrp_mask & MRP_PROTECT) == 0) {
2376                 *val_cnt = 0;
2377                 return (DLADM_STATUS_OK);
2378         }
2379         dladm_find_setbits32(p->mp_types, setbits, &cnt);
2380         if (cnt > *val_cnt)
2381                 return (DLADM_STATUS_BADVALCNT);
2382 
2383         for (i = 0; i < cnt; i++)
2384                 (void) dladm_protect2str(setbits[i], prop_val[i]);
2385 
2386         *val_cnt = cnt;
2387         return (DLADM_STATUS_OK);
2388 }
2389 
2390 /* ARGSUSED */
2391 static dladm_status_t
2392 get_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2393     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2394     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2395 {
2396         mac_resource_props_t    mrp;
2397         mac_protect_t           *p;
2398         dladm_status_t          status;
2399         int                     i;
2400 
2401         status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2402             perm_flags, &mrp, sizeof (mrp));
2403         if (status != DLADM_STATUS_OK)
2404                 return (status);
2405 
2406         p = &mrp.mrp_protect;
2407         if (p->mp_ipaddrcnt == 0) {
2408                 *val_cnt = 0;
2409                 return (DLADM_STATUS_OK);
2410         }
2411         if (p->mp_ipaddrcnt > *val_cnt)
2412                 return (DLADM_STATUS_BADVALCNT);
2413 
2414         for (i = 0; i < p->mp_ipaddrcnt; i++) {
2415                 int len;
2416                 if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) {
2417                         ipaddr_t        v4addr;
2418 
2419                         v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr);
2420                         (void) dladm_ipv4addr2str(&v4addr, prop_val[i]);
2421                 } else {
2422                         (void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr,
2423                             prop_val[i]);
2424                 }
2425                 len = strlen(prop_val[i]);
2426                 (void) sprintf(prop_val[i] + len, "/%d",
2427                     p->mp_ipaddrs[i].ip_netmask);
2428         }
2429         *val_cnt = p->mp_ipaddrcnt;
2430         return (DLADM_STATUS_OK);
2431 }
2432 
2433 dladm_status_t
2434 extract_protection(val_desc_t *vdp, uint_t cnt, void *arg)
2435 {
2436         mac_resource_props_t    *mrp = arg;
2437         uint32_t                types = 0;
2438         int                     i;
2439 
2440         for (i = 0; i < cnt; i++)
2441                 types |= (uint32_t)vdp[i].vd_val;
2442 
2443         mrp->mrp_protect.mp_types = types;
2444         mrp->mrp_mask |= MRP_PROTECT;
2445         return (DLADM_STATUS_OK);
2446 }
2447 
2448 dladm_status_t
2449 extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg)
2450 {
2451         mac_resource_props_t    *mrp = arg;
2452         mac_protect_t           *p = &mrp->mrp_protect;
2453         int                     i;
2454 
2455         if (vdp->vd_val == 0) {
2456                 cnt = (uint_t)-1;
2457         } else {
2458                 for (i = 0; i < cnt; i++) {
2459                         bcopy((void *)vdp[i].vd_val, &p->mp_ipaddrs[i],
2460                             sizeof (mac_ipaddr_t));
2461                 }
2462         }
2463         p->mp_ipaddrcnt = cnt;
2464         mrp->mrp_mask |= MRP_PROTECT;
2465         return (DLADM_STATUS_OK);
2466 }
2467 
2468 static dladm_status_t
2469 check_single_ip(char *buf, mac_ipaddr_t *addr)
2470 {
2471         dladm_status_t  status;
2472         ipaddr_t        v4addr;
2473         in6_addr_t      v6addr;
2474         boolean_t       isv4 = B_TRUE;
2475         char            *p;
2476         uint32_t        mask = 0;
2477 
2478         /*
2479          * If the IP address is in CIDR format, parse the bits component
2480          * seperately. An address in this style will be used to indicate an
2481          * entire subnet, so it must be a network number with no host address.
2482          */
2483         if ((p = strchr(buf, '/')) != NULL) {
2484                 char *end = NULL;
2485 
2486                 *p++ = '\0';
2487                 if (!isdigit(*p))
2488                         return (DLADM_STATUS_INVALID_IP);
2489                 mask = strtol(p, &end, 10);
2490                 if (end != NULL && *end != '\0')
2491                         return (DLADM_STATUS_INVALID_IP);
2492                 if (mask > 128|| mask < 1)
2493                         return (DLADM_STATUS_INVALID_IP);
2494         }
2495 
2496         status = dladm_str2ipv4addr(buf, &v4addr);
2497         if (status == DLADM_STATUS_INVALID_IP) {
2498                 status = dladm_str2ipv6addr(buf, &v6addr);
2499                 if (status == DLADM_STATUS_OK)
2500                         isv4 = B_FALSE;
2501         }
2502         if (status != DLADM_STATUS_OK)
2503                 return (status);
2504 
2505         if (isv4) {
2506                 if (v4addr == INADDR_ANY)
2507                         return (DLADM_STATUS_INVALID_IP);
2508 
2509                 IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr);
2510                 addr->ip_version = IPV4_VERSION;
2511                 if (p != NULL) {
2512                         uint32_t smask;
2513 
2514                         /*
2515                          * Validate the netmask is in the proper range for v4
2516                          */
2517                         if (mask > 32 || mask < 1)
2518                                 return (DLADM_STATUS_INVALID_IP);
2519 
2520                         /*
2521                          * We have a CIDR style address, confirm that only the
2522                          * network number is set.
2523                          */
2524                         smask = 0xFFFFFFFFu << (32 - mask);
2525                         if (htonl(v4addr) & ~smask)
2526                                 return (DLADM_STATUS_INVALID_IP);
2527                 } else {
2528                         mask = 32;
2529                 }
2530                 addr->ip_netmask = mask;
2531         } else {
2532                 if (IN6_IS_ADDR_UNSPECIFIED(&v6addr))
2533                         return (DLADM_STATUS_INVALID_IP);
2534 
2535                 if (IN6_IS_ADDR_V4MAPPED_ANY(&v6addr))
2536                         return (DLADM_STATUS_INVALID_IP);
2537 
2538                 if (p != NULL) {
2539                         int i, off, high;
2540 
2541                         /*
2542                          * Note that the address in our buffer is stored in
2543                          * network byte order.
2544                          */
2545                         off = 0;
2546                         for (i = 3; i >= 0; i--) {
2547                                 high = ffsl(ntohl(v6addr._S6_un._S6_u32[i]));
2548                                 if (high != 0)
2549                                         break;
2550                                 off += 32;
2551                         }
2552                         off += high;
2553                         if (128 - off >= mask)
2554                                 return (DLADM_STATUS_INVALID_IP);
2555                 } else {
2556                         mask = 128;
2557                 }
2558 
2559                 addr->ip_addr = v6addr;
2560                 addr->ip_version = IPV6_VERSION;
2561                 addr->ip_netmask = mask;
2562         }
2563         return (DLADM_STATUS_OK);
2564 }
2565 
2566 /* ARGSUSED */
2567 static dladm_status_t
2568 check_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2569     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2570     val_desc_t **vdpp, datalink_media_t media)
2571 {
2572         dladm_status_t  status;
2573         mac_ipaddr_t    *addr;
2574         int             i;
2575         uint_t          val_cnt = *val_cntp;
2576         val_desc_t      *vdp = *vdpp;
2577 
2578         if (val_cnt > MPT_MAXIPADDR)
2579                 return (DLADM_STATUS_BADVALCNT);
2580 
2581         for (i = 0; i < val_cnt; i++) {
2582                 if ((addr = calloc(1, sizeof (mac_ipaddr_t))) == NULL) {
2583                         status = DLADM_STATUS_NOMEM;
2584                         goto fail;
2585                 }
2586                 vdp[i].vd_val = (uintptr_t)addr;
2587 
2588                 status = check_single_ip(prop_val[i], addr);
2589                 if (status != DLADM_STATUS_OK)
2590                         goto fail;
2591         }
2592         return (DLADM_STATUS_OK);
2593 
2594 fail:
2595         for (i = 0; i < val_cnt; i++) {
2596                 free((void *)vdp[i].vd_val);
2597                 vdp[i].vd_val = NULL;
2598         }
2599         return (status);
2600 }
2601 
2602 static void
2603 dladm_cid2str(mac_dhcpcid_t *cid, char *buf)
2604 {
2605         char    tmp_buf[DLADM_STRSIZE];
2606         uint_t  hexlen;
2607 
2608         switch (cid->dc_form) {
2609         case CIDFORM_TYPED: {
2610                 uint16_t        duidtype, hwtype;
2611                 uint32_t        timestamp, ennum;
2612                 char            *lladdr;
2613 
2614                 if (cid->dc_len < sizeof (duidtype))
2615                         goto fail;
2616 
2617                 bcopy(cid->dc_id, &duidtype, sizeof (duidtype));
2618                 duidtype = ntohs(duidtype);
2619                 switch (duidtype) {
2620                 case DHCPV6_DUID_LLT: {
2621                         duid_llt_t      llt;
2622 
2623                         if (cid->dc_len < sizeof (llt))
2624                                 goto fail;
2625 
2626                         bcopy(cid->dc_id, &llt, sizeof (llt));
2627                         hwtype = ntohs(llt.dllt_hwtype);
2628                         timestamp = ntohl(llt.dllt_time);
2629                         lladdr = _link_ntoa(cid->dc_id + sizeof (llt),
2630                             NULL, cid->dc_len - sizeof (llt), IFT_OTHER);
2631                         if (lladdr == NULL)
2632                                 goto fail;
2633 
2634                         (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%d.%s",
2635                             duidtype, hwtype, timestamp, lladdr);
2636                         free(lladdr);
2637                         break;
2638                 }
2639                 case DHCPV6_DUID_EN: {
2640                         duid_en_t       en;
2641 
2642                         if (cid->dc_len < sizeof (en))
2643                                 goto fail;
2644 
2645                         bcopy(cid->dc_id, &en, sizeof (en));
2646                         ennum = DHCPV6_GET_ENTNUM(&en);
2647                         hexlen = sizeof (tmp_buf);
2648                         if (octet_to_hexascii(cid->dc_id + sizeof (en),
2649                             cid->dc_len - sizeof (en), tmp_buf, &hexlen) != 0)
2650                                 goto fail;
2651 
2652                         (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2653                             duidtype, ennum, tmp_buf);
2654                         break;
2655                 }
2656                 case DHCPV6_DUID_LL: {
2657                         duid_ll_t       ll;
2658 
2659                         if (cid->dc_len < sizeof (ll))
2660                                 goto fail;
2661 
2662                         bcopy(cid->dc_id, &ll, sizeof (ll));
2663                         hwtype = ntohs(ll.dll_hwtype);
2664                         lladdr = _link_ntoa(cid->dc_id + sizeof (ll),
2665                             NULL, cid->dc_len - sizeof (ll), IFT_OTHER);
2666                         if (lladdr == NULL)
2667                                 goto fail;
2668 
2669                         (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2670                             duidtype, hwtype, lladdr);
2671                         free(lladdr);
2672                         break;
2673                 }
2674                 default: {
2675                         hexlen = sizeof (tmp_buf);
2676                         if (octet_to_hexascii(cid->dc_id + sizeof (duidtype),
2677                             cid->dc_len - sizeof (duidtype),
2678                             tmp_buf, &hexlen) != 0)
2679                                 goto fail;
2680 
2681                         (void) snprintf(buf, DLADM_STRSIZE, "%d.%s",
2682                             duidtype, tmp_buf);
2683                 }
2684                 }
2685                 break;
2686         }
2687         case CIDFORM_HEX: {
2688                 hexlen = sizeof (tmp_buf);
2689                 if (octet_to_hexascii(cid->dc_id, cid->dc_len,
2690                     tmp_buf, &hexlen) != 0)
2691                         goto fail;
2692 
2693                 (void) snprintf(buf, DLADM_STRSIZE, "0x%s", tmp_buf);
2694                 break;
2695         }
2696         case CIDFORM_STR: {
2697                 int     i;
2698 
2699                 for (i = 0; i < cid->dc_len; i++) {
2700                         if (!isprint(cid->dc_id[i]))
2701                                 goto fail;
2702                 }
2703                 (void) snprintf(buf, DLADM_STRSIZE, "%s", cid->dc_id);
2704                 break;
2705         }
2706         default:
2707                 goto fail;
2708         }
2709         return;
2710 
2711 fail:
2712         (void) snprintf(buf, DLADM_STRSIZE, "<unknown>");
2713 }
2714 
2715 static dladm_status_t
2716 dladm_str2cid(char *buf, mac_dhcpcid_t *cid)
2717 {
2718         char    *ptr = buf;
2719         char    tmp_buf[DLADM_STRSIZE];
2720         uint_t  hexlen, cidlen;
2721 
2722         bzero(cid, sizeof (*cid));
2723         if (isdigit(*ptr) &&
2724             ptr[strspn(ptr, "0123456789")] == '.') {
2725                 char    *cp;
2726                 ulong_t duidtype;
2727                 ulong_t subtype;
2728                 ulong_t timestamp;
2729                 uchar_t *lladdr;
2730                 int     addrlen;
2731 
2732                 errno = 0;
2733                 duidtype = strtoul(ptr, &cp, 0);
2734                 if (ptr == cp || errno != 0 || *cp != '.' ||
2735                     duidtype > USHRT_MAX)
2736                         return (DLADM_STATUS_BADARG);
2737                 ptr = cp + 1;
2738 
2739                 if (duidtype != 0 && duidtype <= DHCPV6_DUID_LL) {
2740                         errno = 0;
2741                         subtype = strtoul(ptr, &cp, 0);
2742                         if (ptr == cp || errno != 0 || *cp != '.')
2743                                 return (DLADM_STATUS_BADARG);
2744                         ptr = cp + 1;
2745                 }
2746                 switch (duidtype) {
2747                 case DHCPV6_DUID_LLT: {
2748                         duid_llt_t      llt;
2749 
2750                         errno = 0;
2751                         timestamp = strtoul(ptr, &cp, 0);
2752                         if (ptr == cp || errno != 0 || *cp != '.')
2753                                 return (DLADM_STATUS_BADARG);
2754 
2755                         ptr = cp + 1;
2756                         lladdr = _link_aton(ptr, &addrlen);
2757                         if (lladdr == NULL)
2758                                 return (DLADM_STATUS_BADARG);
2759 
2760                         cidlen = sizeof (llt) + addrlen;
2761                         if (cidlen > sizeof (cid->dc_id)) {
2762                                 free(lladdr);
2763                                 return (DLADM_STATUS_TOOSMALL);
2764                         }
2765                         llt.dllt_dutype = htons(duidtype);
2766                         llt.dllt_hwtype = htons(subtype);
2767                         llt.dllt_time = htonl(timestamp);
2768                         bcopy(&llt, cid->dc_id, sizeof (llt));
2769                         bcopy(lladdr, cid->dc_id + sizeof (llt), addrlen);
2770                         free(lladdr);
2771                         break;
2772                 }
2773                 case DHCPV6_DUID_LL: {
2774                         duid_ll_t       ll;
2775 
2776                         lladdr = _link_aton(ptr, &addrlen);
2777                         if (lladdr == NULL)
2778                                 return (DLADM_STATUS_BADARG);
2779 
2780                         cidlen = sizeof (ll) + addrlen;
2781                         if (cidlen > sizeof (cid->dc_id)) {
2782                                 free(lladdr);
2783                                 return (DLADM_STATUS_TOOSMALL);
2784                         }
2785                         ll.dll_dutype = htons(duidtype);
2786                         ll.dll_hwtype = htons(subtype);
2787                         bcopy(&ll, cid->dc_id, sizeof (ll));
2788                         bcopy(lladdr, cid->dc_id + sizeof (ll), addrlen);
2789                         free(lladdr);
2790                         break;
2791                 }
2792                 default: {
2793                         hexlen = sizeof (tmp_buf);
2794                         if (hexascii_to_octet(ptr, strlen(ptr),
2795                             tmp_buf, &hexlen) != 0)
2796                                 return (DLADM_STATUS_BADARG);
2797 
2798                         if (duidtype == DHCPV6_DUID_EN) {
2799                                 duid_en_t       en;
2800 
2801                                 en.den_dutype = htons(duidtype);
2802                                 DHCPV6_SET_ENTNUM(&en, subtype);
2803 
2804                                 cidlen = sizeof (en) + hexlen;
2805                                 if (cidlen > sizeof (cid->dc_id))
2806                                         return (DLADM_STATUS_TOOSMALL);
2807 
2808                                 bcopy(&en, cid->dc_id, sizeof (en));
2809                                 bcopy(tmp_buf, cid->dc_id + sizeof (en),
2810                                     hexlen);
2811                         } else {
2812                                 uint16_t        dutype = htons(duidtype);
2813 
2814                                 cidlen = sizeof (dutype) + hexlen;
2815                                 if (cidlen > sizeof (cid->dc_id))
2816                                         return (DLADM_STATUS_TOOSMALL);
2817 
2818                                 bcopy(&dutype, cid->dc_id, sizeof (dutype));
2819                                 bcopy(tmp_buf, cid->dc_id + sizeof (dutype),
2820                                     hexlen);
2821                         }
2822                         break;
2823                 }
2824                 }
2825                 cid->dc_form = CIDFORM_TYPED;
2826         } else if (strncasecmp("0x", ptr, 2) == 0 && ptr[2] != '\0') {
2827                 ptr += 2;
2828                 hexlen = sizeof (tmp_buf);
2829                 if (hexascii_to_octet(ptr, strlen(ptr), tmp_buf,
2830                     &hexlen) != 0) {
2831                         return (DLADM_STATUS_BADARG);
2832                 }
2833                 cidlen = hexlen;
2834                 if (cidlen > sizeof (cid->dc_id))
2835                         return (DLADM_STATUS_TOOSMALL);
2836 
2837                 bcopy(tmp_buf, cid->dc_id, cidlen);
2838                 cid->dc_form = CIDFORM_HEX;
2839         } else {
2840                 cidlen = strlen(ptr);
2841                 if (cidlen > sizeof (cid->dc_id))
2842                         return (DLADM_STATUS_TOOSMALL);
2843 
2844                 bcopy(ptr, cid->dc_id, cidlen);
2845                 cid->dc_form = CIDFORM_STR;
2846         }
2847         cid->dc_len = cidlen;
2848         return (DLADM_STATUS_OK);
2849 }
2850 
2851 /* ARGSUSED */
2852 static dladm_status_t
2853 get_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2854     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2855     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2856 {
2857         mac_resource_props_t    mrp;
2858         mac_protect_t           *p;
2859         dladm_status_t          status;
2860         int                     i;
2861 
2862         status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2863             perm_flags, &mrp, sizeof (mrp));
2864         if (status != DLADM_STATUS_OK)
2865                 return (status);
2866 
2867         p = &mrp.mrp_protect;
2868         if (p->mp_cidcnt == 0) {
2869                 *val_cnt = 0;
2870                 return (DLADM_STATUS_OK);
2871         }
2872         if (p->mp_cidcnt > *val_cnt)
2873                 return (DLADM_STATUS_BADVALCNT);
2874 
2875         for (i = 0; i < p->mp_cidcnt; i++) {
2876                 mac_dhcpcid_t   *cid = &p->mp_cids[i];
2877 
2878                 dladm_cid2str(cid, prop_val[i]);
2879         }
2880         *val_cnt = p->mp_cidcnt;
2881         return (DLADM_STATUS_OK);
2882 }
2883 
2884 dladm_status_t
2885 extract_allowedcids(val_desc_t *vdp, uint_t cnt, void *arg)
2886 {
2887         mac_resource_props_t    *mrp = arg;
2888         mac_protect_t           *p = &mrp->mrp_protect;
2889         int                     i;
2890 
2891         if (vdp->vd_val == 0) {
2892                 cnt = (uint_t)-1;
2893         } else {
2894                 for (i = 0; i < cnt; i++) {
2895                         bcopy((void *)vdp[i].vd_val, &p->mp_cids[i],
2896                             sizeof (mac_dhcpcid_t));
2897                 }
2898         }
2899         p->mp_cidcnt = cnt;
2900         mrp->mrp_mask |= MRP_PROTECT;
2901         return (DLADM_STATUS_OK);
2902 }
2903 
2904 /* ARGSUSED */
2905 static dladm_status_t
2906 check_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2907     datalink_id_t linkid, char **prop_val, uint_t *val_cntp,
2908     uint_t flags, val_desc_t **vdpp, datalink_media_t media)
2909 {
2910         dladm_status_t  status;
2911         mac_dhcpcid_t   *cid;
2912         int             i;
2913         uint_t          val_cnt = *val_cntp;
2914         val_desc_t      *vdp = *vdpp;
2915 
2916         if (val_cnt > MPT_MAXCID)
2917                 return (DLADM_STATUS_BADVALCNT);
2918 
2919         for (i = 0; i < val_cnt; i++) {
2920                 if ((cid = calloc(1, sizeof (mac_dhcpcid_t))) == NULL) {
2921                         status = DLADM_STATUS_NOMEM;
2922                         goto fail;
2923                 }
2924                 vdp[i].vd_val = (uintptr_t)cid;
2925 
2926                 status = dladm_str2cid(prop_val[i], cid);
2927                 if (status != DLADM_STATUS_OK)
2928                         goto fail;
2929         }
2930         return (DLADM_STATUS_OK);
2931 
2932 fail:
2933         for (i = 0; i < val_cnt; i++) {
2934                 free((void *)vdp[i].vd_val);
2935                 vdp[i].vd_val = NULL;
2936         }
2937         return (status);
2938 }
2939 
2940 /* ARGSUSED */
2941 static dladm_status_t
2942 get_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
2943     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2944     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2945 {
2946         mac_secondary_addr_t    sa;
2947         dladm_status_t          status;
2948         int                     i;
2949 
2950         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2951             perm_flags, &sa, sizeof (sa));
2952         if (status != DLADM_STATUS_OK)
2953                 return (status);
2954 
2955         if (sa.ms_addrcnt > *val_cnt)
2956                 return (DLADM_STATUS_BADVALCNT);
2957 
2958         for (i = 0; i < sa.ms_addrcnt; i++) {
2959                 if (dladm_aggr_macaddr2str(
2960                     (const unsigned char *)&sa.ms_addrs[i], prop_val[i]) ==
2961                     NULL) {
2962                         *val_cnt = i;
2963                         return (DLADM_STATUS_NOMEM);
2964                 }
2965         }
2966         *val_cnt = sa.ms_addrcnt;
2967         return (DLADM_STATUS_OK);
2968 }
2969 
2970 /* ARGSUSED */
2971 static dladm_status_t
2972 check_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
2973     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2974     val_desc_t **vdpp, datalink_media_t media)
2975 {
2976         dladm_status_t  status;
2977         uchar_t         *addr;
2978         uint_t          len = 0;
2979         int             i;
2980         uint_t          val_cnt = *val_cntp;
2981         val_desc_t      *vdp = *vdpp;
2982 
2983         if (val_cnt >= MPT_MAXMACADDR)
2984                 return (DLADM_STATUS_BADVALCNT);
2985 
2986         for (i = 0; i < val_cnt; i++) {
2987                 addr = _link_aton(prop_val[i], (int *)&len);
2988                 if (addr == NULL) {
2989                         if (len == (uint_t)-1)
2990                                 status = DLADM_STATUS_MACADDRINVAL;
2991                         else
2992                                 status = DLADM_STATUS_NOMEM;
2993                         goto fail;
2994                 }
2995 
2996                 vdp[i].vd_val = (uintptr_t)addr;
2997         }
2998         return (DLADM_STATUS_OK);
2999 
3000 fail:
3001         for (i = 0; i < val_cnt; i++) {
3002                 free((void *)vdp[i].vd_val);
3003                 vdp[i].vd_val = NULL;
3004         }
3005         return (status);
3006 }
3007 
3008 /* ARGSUSED */
3009 static dladm_status_t
3010 set_secondary_macs(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
3011     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3012 {
3013         dladm_status_t status;
3014         dld_ioc_macprop_t *dip;
3015         int i;
3016         mac_secondary_addr_t msa;
3017 
3018         dip = i_dladm_buf_alloc_by_name(0, linkid, "secondary-macs", 0,
3019             &status);
3020         if (dip == NULL)
3021                 return (status);
3022 
3023         if (vdp->vd_val == 0) {
3024                 val_cnt = (uint_t)-1;
3025         } else {
3026                 for (i = 0; i < val_cnt; i++) {
3027                         bcopy((void *)vdp[i].vd_val, msa.ms_addrs[i],
3028                             MAXMACADDRLEN);
3029                 }
3030         }
3031         msa.ms_addrcnt = val_cnt;
3032         bcopy(&msa, dip->pr_val, dip->pr_valsize);
3033 
3034         status = i_dladm_macprop(handle, dip, B_TRUE);
3035 
3036         free(dip);
3037         return (status);
3038 }
3039 
3040 /* ARGSUSED */
3041 static dladm_status_t
3042 get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3043     char **prop_val, uint_t *val_cnt, datalink_media_t media,
3044     uint_t flags, uint_t *perm_flags)
3045 {
3046         struct          dlautopush dlap;
3047         int             i, len;
3048         dladm_status_t  status;
3049 
3050         if (flags & DLD_PROP_DEFAULT)
3051                 return (DLADM_STATUS_NOTDEFINED);
3052 
3053         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3054             perm_flags, &dlap, sizeof (dlap));
3055         if (status != DLADM_STATUS_OK)
3056                 return (status);
3057 
3058         if (dlap.dap_npush == 0) {
3059                 *val_cnt = 0;
3060                 return (DLADM_STATUS_OK);
3061         }
3062         for (i = 0, len = 0; i < dlap.dap_npush; i++) {
3063                 if (i != 0) {
3064                         (void) snprintf(*prop_val + len,
3065                             DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
3066                         len += 1;
3067                 }
3068                 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
3069                     "%s", dlap.dap_aplist[i]);
3070                 len += strlen(dlap.dap_aplist[i]);
3071                 if (dlap.dap_anchor - 1 == i) {
3072                         (void) snprintf(*prop_val + len,
3073                             DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
3074                             AP_ANCHOR);
3075                         len += (strlen(AP_ANCHOR) + 1);
3076                 }
3077         }
3078         *val_cnt = 1;
3079         return (DLADM_STATUS_OK);
3080 }
3081 
3082 /*
3083  * Add the specified module to the dlautopush structure; returns a
3084  * DLADM_STATUS_* code.
3085  */
3086 dladm_status_t
3087 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
3088 {
3089         if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
3090                 return (DLADM_STATUS_BADVAL);
3091 
3092         if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
3093                 /*
3094                  * We don't allow multiple anchors, and the anchor must
3095                  * be after at least one module.
3096                  */
3097                 if (dlap->dap_anchor != 0)
3098                         return (DLADM_STATUS_BADVAL);
3099                 if (dlap->dap_npush == 0)
3100                         return (DLADM_STATUS_BADVAL);
3101 
3102                 dlap->dap_anchor = dlap->dap_npush;
3103                 return (DLADM_STATUS_OK);
3104         }
3105         if (dlap->dap_npush >= MAXAPUSH)
3106                 return (DLADM_STATUS_BADVALCNT);
3107 
3108         (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
3109             FMNAMESZ + 1);
3110 
3111         return (DLADM_STATUS_OK);
3112 }
3113 
3114 /*
3115  * Currently, both '.' and ' '(space) can be used as the delimiters between
3116  * autopush modules. The former is used in dladm set-linkprop, and the
3117  * latter is used in the autopush(1M) file.
3118  */
3119 /* ARGSUSED */
3120 static dladm_status_t
3121 check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3122     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3123     datalink_media_t media)
3124 {
3125         char                    *module;
3126         struct dlautopush       *dlap;
3127         dladm_status_t          status;
3128         char                    val[DLADM_PROP_VAL_MAX];
3129         char                    delimiters[4];
3130         uint_t                  val_cnt = *val_cntp;
3131         val_desc_t              *vdp = *vdpp;
3132 
3133         if (val_cnt != 1)
3134                 return (DLADM_STATUS_BADVALCNT);
3135 
3136         if (prop_val != NULL) {
3137                 dlap = malloc(sizeof (struct dlautopush));
3138                 if (dlap == NULL)
3139                         return (DLADM_STATUS_NOMEM);
3140 
3141                 (void) memset(dlap, 0, sizeof (struct dlautopush));
3142                 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
3143                 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
3144                 module = strtok(val, delimiters);
3145                 while (module != NULL) {
3146                         status = i_dladm_add_ap_module(module, dlap);
3147                         if (status != DLADM_STATUS_OK)
3148                                 return (status);
3149                         module = strtok(NULL, delimiters);
3150                 }
3151 
3152                 vdp->vd_val = (uintptr_t)dlap;
3153         } else {
3154                 vdp->vd_val = 0;
3155         }
3156         return (DLADM_STATUS_OK);
3157 }
3158 
3159 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
3160 
3161 /* ARGSUSED */
3162 static dladm_status_t
3163 get_rate_common(dladm_handle_t handle, prop_desc_t *pdp,
3164     datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id,
3165     uint_t *perm_flags)
3166 {
3167         wl_rates_t      *wrp;
3168         uint_t          i;
3169         dladm_status_t  status = DLADM_STATUS_OK;
3170 
3171         wrp = malloc(WLDP_BUFSIZE);
3172         if (wrp == NULL)
3173                 return (DLADM_STATUS_NOMEM);
3174 
3175         status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE,
3176             B_FALSE);
3177         if (status != DLADM_STATUS_OK)
3178                 goto done;
3179 
3180         if (wrp->wl_rates_num > *val_cnt) {
3181                 status = DLADM_STATUS_TOOSMALL;
3182                 goto done;
3183         }
3184 
3185         if (wrp->wl_rates_rates[0] == 0) {
3186                 prop_val[0][0] = '\0';
3187                 *val_cnt = 1;
3188                 goto done;
3189         }
3190 
3191         for (i = 0; i < wrp->wl_rates_num; i++) {
3192                 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
3193                     wrp->wl_rates_rates[i] % 2,
3194                     (float)wrp->wl_rates_rates[i] / 2);
3195         }
3196         *val_cnt = wrp->wl_rates_num;
3197         *perm_flags = MAC_PROP_PERM_RW;
3198 
3199 done:
3200         free(wrp);
3201         return (status);
3202 }
3203 
3204 static dladm_status_t
3205 get_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3206     char **prop_val, uint_t *val_cnt, datalink_media_t media,
3207     uint_t flags, uint_t *perm_flags)
3208 {
3209         if (media != DL_WIFI) {
3210                 return (get_speed(handle, pdp, linkid, prop_val,
3211                     val_cnt, media, flags, perm_flags));
3212         }
3213 
3214         return (get_rate_common(handle, pdp, linkid, prop_val, val_cnt,
3215             MAC_PROP_WL_DESIRED_RATES, perm_flags));
3216 }
3217 
3218 /* ARGSUSED */
3219 static dladm_status_t
3220 get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3221     char **prop_val, uint_t *val_cnt, datalink_media_t media,
3222     uint_t flags, uint_t *perm_flags)
3223 {
3224         switch (media) {
3225         case DL_ETHER:
3226                 /*
3227                  * Speed for ethernet links is unbounded. E.g., 802.11b
3228                  * links can have a speed of 5.5 Gbps.
3229                  */
3230                 return (DLADM_STATUS_NOTSUP);
3231 
3232         case DL_WIFI:
3233                 return (get_rate_common(handle, pdp, linkid, prop_val,
3234                     val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags));
3235         default:
3236                 return (DLADM_STATUS_BADARG);
3237         }
3238 }
3239 
3240 static dladm_status_t
3241 set_wlan_rate(dladm_handle_t handle, datalink_id_t linkid,
3242     dladm_wlan_rates_t *rates)
3243 {
3244         int             i;
3245         uint_t          len;
3246         wl_rates_t      *wrp;
3247         dladm_status_t  status = DLADM_STATUS_OK;
3248 
3249         wrp = malloc(WLDP_BUFSIZE);
3250         if (wrp == NULL)
3251                 return (DLADM_STATUS_NOMEM);
3252 
3253         bzero(wrp, WLDP_BUFSIZE);
3254         for (i = 0; i < rates->wr_cnt; i++)
3255                 wrp->wl_rates_rates[i] = rates->wr_rates[i];
3256         wrp->wl_rates_num = rates->wr_cnt;
3257 
3258         len = offsetof(wl_rates_t, wl_rates_rates) +
3259             (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
3260         status = i_dladm_wlan_param(handle, linkid, wrp,
3261             MAC_PROP_WL_DESIRED_RATES, len, B_TRUE);
3262 
3263         free(wrp);
3264         return (status);
3265 }
3266 
3267 /* ARGSUSED */
3268 static dladm_status_t
3269 set_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3270     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3271 {
3272         dladm_wlan_rates_t      rates;
3273         dladm_status_t          status;
3274 
3275         /*
3276          * can currently set rate on WIFI links only.
3277          */
3278         if (media != DL_WIFI)
3279                 return (DLADM_STATUS_PROPRDONLY);
3280 
3281         if (val_cnt != 1)
3282                 return (DLADM_STATUS_BADVALCNT);
3283 
3284         rates.wr_cnt = 1;
3285         rates.wr_rates[0] = vdp[0].vd_val;
3286 
3287         status = set_wlan_rate(handle, linkid, &rates);
3288 
3289         return (status);
3290 }
3291 
3292 /* ARGSUSED */
3293 static dladm_status_t
3294 check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3295     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3296     datalink_media_t media)
3297 {
3298         int             i;
3299         uint_t          modval_cnt = MAX_SUPPORT_RATES;
3300         char            *buf, **modval;
3301         dladm_status_t  status;
3302         uint_t          perm_flags;
3303         uint_t          val_cnt = *val_cntp;
3304         val_desc_t      *vdp = *vdpp;
3305 
3306         if (val_cnt != 1)
3307                 return (DLADM_STATUS_BADVALCNT);
3308 
3309         buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
3310             MAX_SUPPORT_RATES);
3311         if (buf == NULL) {
3312                 status = DLADM_STATUS_NOMEM;
3313                 goto done;
3314         }
3315 
3316         modval = (char **)(void *)buf;
3317         for (i = 0; i < MAX_SUPPORT_RATES; i++) {
3318                 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
3319                     i * DLADM_STRSIZE;
3320         }
3321 
3322         status = get_rate_mod(handle, NULL, linkid, modval, &modval_cnt,
3323             media, 0, &perm_flags);
3324         if (status != DLADM_STATUS_OK)
3325                 goto done;
3326 
3327         for (i = 0; i < modval_cnt; i++) {
3328                 if (strcasecmp(*prop_val, modval[i]) == 0) {
3329                         vdp->vd_val = (uintptr_t)(uint_t)
3330                             (atof(*prop_val) * 2);
3331                         status = DLADM_STATUS_OK;
3332                         break;
3333                 }
3334         }
3335         if (i == modval_cnt)
3336                 status = DLADM_STATUS_BADVAL;
3337 done:
3338         free(buf);
3339         return (status);
3340 }
3341 
3342 static dladm_status_t
3343 get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf,
3344     int buflen)
3345 {
3346         return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
3347             buflen, B_FALSE));
3348 }
3349 
3350 /* ARGSUSED */
3351 static dladm_status_t
3352 get_channel(dladm_handle_t handle, prop_desc_t *pdp,
3353     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3354     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3355 {
3356         uint32_t        channel;
3357         char            buf[WLDP_BUFSIZE];
3358         dladm_status_t  status;
3359         wl_phy_conf_t   wl_phy_conf;
3360 
3361         if ((status = get_phyconf(handle, linkid, buf, sizeof (buf)))
3362             != DLADM_STATUS_OK)
3363                 return (status);
3364 
3365         (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
3366         if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel))
3367                 return (DLADM_STATUS_NOTFOUND);
3368 
3369         (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
3370         *val_cnt = 1;
3371         *perm_flags = MAC_PROP_PERM_READ;
3372         return (DLADM_STATUS_OK);
3373 }
3374 
3375 /* ARGSUSED */
3376 static dladm_status_t
3377 get_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3378     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3379     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3380 {
3381         wl_ps_mode_t    mode;
3382         const char      *s;
3383         char            buf[WLDP_BUFSIZE];
3384         dladm_status_t  status;
3385 
3386         if ((status = i_dladm_wlan_param(handle, linkid, buf,
3387             MAC_PROP_WL_POWER_MODE, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3388                 return (status);
3389 
3390         (void) memcpy(&mode, buf, sizeof (mode));
3391         switch (mode.wl_ps_mode) {
3392         case WL_PM_AM:
3393                 s = "off";
3394                 break;
3395         case WL_PM_MPS:
3396                 s = "max";
3397                 break;
3398         case WL_PM_FAST:
3399                 s = "fast";
3400                 break;
3401         default:
3402                 return (DLADM_STATUS_NOTFOUND);
3403         }
3404         (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3405         *val_cnt = 1;
3406         *perm_flags = MAC_PROP_PERM_RW;
3407         return (DLADM_STATUS_OK);
3408 }
3409 
3410 /* ARGSUSED */
3411 static dladm_status_t
3412 set_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3413     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3414     datalink_media_t media)
3415 {
3416         dladm_wlan_powermode_t  powermode = vdp->vd_val;
3417         wl_ps_mode_t            ps_mode;
3418 
3419         if (val_cnt != 1)
3420                 return (DLADM_STATUS_BADVALCNT);
3421 
3422         (void) memset(&ps_mode, 0xff, sizeof (ps_mode));
3423 
3424         switch (powermode) {
3425         case DLADM_WLAN_PM_OFF:
3426                 ps_mode.wl_ps_mode = WL_PM_AM;
3427                 break;
3428         case DLADM_WLAN_PM_MAX:
3429                 ps_mode.wl_ps_mode = WL_PM_MPS;
3430                 break;
3431         case DLADM_WLAN_PM_FAST:
3432                 ps_mode.wl_ps_mode = WL_PM_FAST;
3433                 break;
3434         default:
3435                 return (DLADM_STATUS_NOTSUP);
3436         }
3437         return (i_dladm_wlan_param(handle, linkid, &ps_mode,
3438             MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE));
3439 }
3440 
3441 /* ARGSUSED */
3442 static dladm_status_t
3443 get_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3444     char **prop_val, uint_t *val_cnt, datalink_media_t media,
3445     uint_t flags, uint_t *perm_flags)
3446 {
3447         wl_radio_t      radio;
3448         const char      *s;
3449         char            buf[WLDP_BUFSIZE];
3450         dladm_status_t  status;
3451 
3452         if ((status = i_dladm_wlan_param(handle, linkid, buf,
3453             MAC_PROP_WL_RADIO, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3454                 return (status);
3455 
3456         (void) memcpy(&radio, buf, sizeof (radio));
3457         switch (radio) {
3458         case B_TRUE:
3459                 s = "on";
3460                 break;
3461         case B_FALSE:
3462                 s = "off";
3463                 break;
3464         default:
3465                 return (DLADM_STATUS_NOTFOUND);
3466         }
3467         (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3468         *val_cnt = 1;
3469         *perm_flags = MAC_PROP_PERM_RW;
3470         return (DLADM_STATUS_OK);
3471 }
3472 
3473 /* ARGSUSED */
3474 static dladm_status_t
3475 set_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3476     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3477 {
3478         dladm_wlan_radio_t      radio = vdp->vd_val;
3479         wl_radio_t              r;
3480 
3481         if (val_cnt != 1)
3482                 return (DLADM_STATUS_BADVALCNT);
3483 
3484         switch (radio) {
3485         case DLADM_WLAN_RADIO_ON:
3486                 r = B_TRUE;
3487                 break;
3488         case DLADM_WLAN_RADIO_OFF:
3489                 r = B_FALSE;
3490                 break;
3491         default:
3492                 return (DLADM_STATUS_NOTSUP);
3493         }
3494         return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO,
3495             sizeof (r), B_TRUE));
3496 }
3497 
3498 /* ARGSUSED */
3499 static dladm_status_t
3500 check_hoplimit(dladm_handle_t handle, prop_desc_t *pdp,
3501     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3502     val_desc_t **vdpp, datalink_media_t media)
3503 {
3504         int32_t         hlim;
3505         char            *ep;
3506         uint_t          val_cnt = *val_cntp;
3507         val_desc_t      *vdp = *vdpp;
3508 
3509         if (val_cnt != 1)
3510                 return (DLADM_STATUS_BADVALCNT);
3511 
3512         errno = 0;
3513         hlim = strtol(*prop_val, &ep, 10);
3514         if (errno != 0 || ep == *prop_val || hlim < 1 ||
3515             hlim > (int32_t)UINT8_MAX)
3516                 return (DLADM_STATUS_BADVAL);
3517         vdp->vd_val = hlim;
3518         return (DLADM_STATUS_OK);
3519 }
3520 
3521 /* ARGSUSED */
3522 static dladm_status_t
3523 check_encaplim(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3524     char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3525     datalink_media_t media)
3526 {
3527         int32_t         elim;
3528         char            *ep;
3529         uint_t          val_cnt = *val_cntp;
3530         val_desc_t      *vdp = *vdpp;
3531 
3532         if (media != DL_IPV6)
3533                 return (DLADM_STATUS_BADARG);
3534 
3535         if (val_cnt != 1)
3536                 return (DLADM_STATUS_BADVALCNT);
3537 
3538         errno = 0;
3539         elim = strtol(*prop_val, &ep, 10);
3540         if (errno != 0 || ep == *prop_val || elim < 0 ||
3541             elim > (int32_t)UINT8_MAX)
3542                 return (DLADM_STATUS_BADVAL);
3543         vdp->vd_val = elim;
3544         return (DLADM_STATUS_OK);
3545 }
3546 
3547 static dladm_status_t
3548 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3549     const char *prop_name, char **prop_val, uint_t val_cnt)
3550 {
3551         char            buf[MAXLINELEN];
3552         int             i;
3553         dladm_conf_t    conf;
3554         dladm_status_t  status;
3555 
3556         status = dladm_open_conf(handle, linkid, &conf);
3557         if (status != DLADM_STATUS_OK)
3558                 return (status);
3559 
3560         /*
3561          * reset case.
3562          */
3563         if (val_cnt == 0) {
3564                 status = dladm_unset_conf_field(handle, conf, prop_name);
3565                 if (status == DLADM_STATUS_OK)
3566                         status = dladm_write_conf(handle, conf);
3567                 goto done;
3568         }
3569 
3570         buf[0] = '\0';
3571         for (i = 0; i < val_cnt; i++) {
3572                 (void) strlcat(buf, prop_val[i], MAXLINELEN);
3573                 if (i != val_cnt - 1)
3574                         (void) strlcat(buf, ",", MAXLINELEN);
3575         }
3576 
3577         status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR,
3578             buf);
3579         if (status == DLADM_STATUS_OK)
3580                 status = dladm_write_conf(handle, conf);
3581 
3582 done:
3583         dladm_destroy_conf(handle, conf);
3584         return (status);
3585 }
3586 
3587 static dladm_status_t
3588 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3589     const char *prop_name, char **prop_val, uint_t *val_cntp)
3590 {
3591         char            buf[MAXLINELEN], *str;
3592         uint_t          cnt = 0;
3593         dladm_conf_t    conf;
3594         dladm_status_t  status;
3595 
3596         status = dladm_getsnap_conf(handle, linkid, &conf);
3597         if (status != DLADM_STATUS_OK)
3598                 return (status);
3599 
3600         status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN);
3601         if (status != DLADM_STATUS_OK)
3602                 goto done;
3603 
3604         str = strtok(buf, ",");
3605         while (str != NULL) {
3606                 if (cnt == *val_cntp) {
3607                         status = DLADM_STATUS_TOOSMALL;
3608                         goto done;
3609                 }
3610                 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
3611                 str = strtok(NULL, ",");
3612         }
3613 
3614         *val_cntp = cnt;
3615 
3616 done:
3617         dladm_destroy_conf(handle, conf);
3618         return (status);
3619 }
3620 
3621 /*
3622  * Walk persistent private link properties of a link.
3623  */
3624 static dladm_status_t
3625 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid,
3626     void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
3627 {
3628         dladm_status_t          status;
3629         dladm_conf_t            conf;
3630         char                    last_attr[MAXLINKATTRLEN];
3631         char                    attr[MAXLINKATTRLEN];
3632         char                    attrval[MAXLINKATTRVALLEN];
3633         size_t                  attrsz;
3634 
3635         if (linkid == DATALINK_INVALID_LINKID || func == NULL)
3636                 return (DLADM_STATUS_BADARG);
3637 
3638         status = dladm_getsnap_conf(handle, linkid, &conf);
3639         if (status != DLADM_STATUS_OK)
3640                 return (status);
3641 
3642         last_attr[0] = '\0';
3643         while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr,
3644             attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) {
3645                 if (attr[0] == '_') {
3646                         if (func(handle, linkid, attr, arg) ==
3647                             DLADM_WALK_TERMINATE)
3648                                 break;
3649                 }
3650                 (void) strlcpy(last_attr, attr, MAXLINKATTRLEN);
3651         }
3652 
3653         dladm_destroy_conf(handle, conf);
3654         return (DLADM_STATUS_OK);
3655 }
3656 
3657 static link_attr_t *
3658 dladm_name2prop(const char *prop_name)
3659 {
3660         link_attr_t *p;
3661 
3662         for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3663                 if (strcmp(p->pp_name, prop_name) == 0)
3664                         break;
3665         }
3666         return (p);
3667 }
3668 
3669 static link_attr_t *
3670 dladm_id2prop(mac_prop_id_t propid)
3671 {
3672         link_attr_t *p;
3673 
3674         for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3675                 if (p->pp_id == propid)
3676                         break;
3677         }
3678         return (p);
3679 }
3680 
3681 static dld_ioc_macprop_t *
3682 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
3683     const char *prop_name, mac_prop_id_t propid, uint_t flags,
3684     dladm_status_t *status)
3685 {
3686         int dsize;
3687         dld_ioc_macprop_t *dip;
3688 
3689         *status = DLADM_STATUS_OK;
3690         dsize = MAC_PROP_BUFSIZE(valsize);
3691         dip = malloc(dsize);
3692         if (dip == NULL) {
3693                 *status = DLADM_STATUS_NOMEM;
3694                 return (NULL);
3695         }
3696         bzero(dip, dsize);
3697         dip->pr_valsize = valsize;
3698         (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
3699         dip->pr_linkid = linkid;
3700         dip->pr_num = propid;
3701         dip->pr_flags = flags;
3702         return (dip);
3703 }
3704 
3705 static dld_ioc_macprop_t *
3706 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
3707     const char *prop_name, uint_t flags, dladm_status_t *status)
3708 {
3709         link_attr_t *p;
3710 
3711         p = dladm_name2prop(prop_name);
3712         valsize = MAX(p->pp_valsize, valsize);
3713         return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
3714             flags, status));
3715 }
3716 
3717 static dld_ioc_macprop_t *
3718 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
3719     mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
3720 {
3721         link_attr_t *p;
3722 
3723         p = dladm_id2prop(propid);
3724         valsize = MAX(p->pp_valsize, valsize);
3725         return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
3726             flags, status));
3727 }
3728 
3729 /* ARGSUSED */
3730 static dladm_status_t
3731 set_public_prop(dladm_handle_t handle, prop_desc_t *pdp,
3732     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3733     datalink_media_t media)
3734 {
3735         dld_ioc_macprop_t       *dip;
3736         dladm_status_t  status = DLADM_STATUS_OK;
3737         uint8_t         u8;
3738         uint16_t        u16;
3739         uint32_t        u32;
3740         void            *val;
3741 
3742         dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status);
3743         if (dip == NULL)
3744                 return (status);
3745 
3746         if (pdp->pd_flags & PD_CHECK_ALLOC)
3747                 val = (void *)vdp->vd_val;
3748         else {
3749                 /*
3750                  * Currently all 1/2/4-byte size properties are byte/word/int.
3751                  * No need (yet) to distinguish these from arrays of same size.
3752                  */
3753                 switch (dip->pr_valsize) {
3754                 case 1:
3755                         u8 = vdp->vd_val;
3756                         val = &u8;
3757                         break;
3758                 case 2:
3759                         u16 = vdp->vd_val;
3760                         val = &u16;
3761                         break;
3762                 case 4:
3763                         u32 = vdp->vd_val;
3764                         val = &u32;
3765                         break;
3766                 default:
3767                         val = &vdp->vd_val;
3768                         break;
3769                 }
3770         }
3771 
3772         if (val != NULL)
3773                 (void) memcpy(dip->pr_val, val, dip->pr_valsize);
3774         else
3775                 dip->pr_valsize = 0;
3776 
3777         status = i_dladm_macprop(handle, dip, B_TRUE);
3778 
3779 done:
3780         free(dip);
3781         return (status);
3782 }
3783 
3784 dladm_status_t
3785 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set)
3786 {
3787         dladm_status_t status = DLADM_STATUS_OK;
3788 
3789         if (ioctl(dladm_dld_fd(handle),
3790             (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
3791                 status = dladm_errno2status(errno);
3792 
3793         return (status);
3794 }
3795 
3796 static dladm_status_t
3797 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid,
3798     char *prop_name, uint_t flags, uint_t *perm_flags, void *arg, size_t size)
3799 {
3800         dld_ioc_macprop_t       *dip;
3801         dladm_status_t          status;
3802 
3803         dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, &status);
3804         if (dip == NULL)
3805                 return (DLADM_STATUS_NOMEM);
3806 
3807         status = i_dladm_macprop(handle, dip, B_FALSE);
3808         if (status != DLADM_STATUS_OK) {
3809                 free(dip);
3810                 return (status);
3811         }
3812 
3813         if (perm_flags != NULL)
3814                 *perm_flags = dip->pr_perm_flags;
3815 
3816         if (arg != NULL)
3817                 (void) memcpy(arg, dip->pr_val, size);
3818         free(dip);
3819         return (DLADM_STATUS_OK);
3820 }
3821 
3822 /* ARGSUSED */
3823 static dladm_status_t
3824 check_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3825     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3826     val_desc_t **vp, datalink_media_t media)
3827 {
3828         uint_t          val_cnt = *val_cntp;
3829         val_desc_t      *v = *vp;
3830 
3831         if (val_cnt != 1)
3832                 return (DLADM_STATUS_BADVAL);
3833         v->vd_val = strtoul(prop_val[0], NULL, 0);
3834         return (DLADM_STATUS_OK);
3835 }
3836 
3837 /* ARGSUSED */
3838 static dladm_status_t
3839 get_duplex(dladm_handle_t handle, prop_desc_t *pdp,
3840     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3841     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3842 {
3843         link_duplex_t   link_duplex;
3844         dladm_status_t  status;
3845 
3846         if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex",
3847             KSTAT_DATA_UINT32, &link_duplex)) != 0)
3848                 return (status);
3849 
3850         switch (link_duplex) {
3851         case LINK_DUPLEX_FULL:
3852                 (void) strcpy(*prop_val, "full");
3853                 break;
3854         case LINK_DUPLEX_HALF:
3855                 (void) strcpy(*prop_val, "half");
3856                 break;
3857         default:
3858                 (void) strcpy(*prop_val, "unknown");
3859                 break;
3860         }
3861         *val_cnt = 1;
3862         return (DLADM_STATUS_OK);
3863 }
3864 
3865 /* ARGSUSED */
3866 static dladm_status_t
3867 get_speed(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3868     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
3869     uint_t *perm_flags)
3870 {
3871         uint64_t        ifspeed = 0;
3872         dladm_status_t status;
3873 
3874         if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed",
3875             KSTAT_DATA_UINT64, &ifspeed)) != 0)
3876                 return (status);
3877 
3878         if ((ifspeed % 1000000) != 0) {
3879                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3880                     "%llf", ifspeed / (float)1000000); /* Mbps */
3881         } else {
3882                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3883                     "%llu", ifspeed / 1000000); /* Mbps */
3884         }
3885         *val_cnt = 1;
3886         *perm_flags = MAC_PROP_PERM_READ;
3887         return (DLADM_STATUS_OK);
3888 }
3889 
3890 /* ARGSUSED */
3891 static dladm_status_t
3892 get_link_state(dladm_handle_t handle, prop_desc_t *pdp,
3893     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3894     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3895 {
3896         link_state_t            link_state;
3897         dladm_status_t          status;
3898 
3899         status = dladm_get_state(handle, linkid, &link_state);
3900         if (status != DLADM_STATUS_OK)
3901                 return (status);
3902 
3903         switch (link_state) {
3904         case LINK_STATE_UP:
3905                 (void) strcpy(*prop_val, "up");
3906                 break;
3907         case LINK_STATE_DOWN:
3908                 (void) strcpy(*prop_val, "down");
3909                 break;
3910         default:
3911                 (void) strcpy(*prop_val, "unknown");
3912                 break;
3913         }
3914         *val_cnt = 1;
3915         *perm_flags = MAC_PROP_PERM_READ;
3916         return (DLADM_STATUS_OK);
3917 }
3918 
3919 /* ARGSUSED */
3920 static dladm_status_t
3921 get_binary(dladm_handle_t handle, prop_desc_t *pdp,
3922     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3923     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3924 {
3925         dladm_status_t  status;
3926         uint_t          v = 0;
3927 
3928         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3929             perm_flags, &v, sizeof (v));
3930         if (status != DLADM_STATUS_OK)
3931                 return (status);
3932 
3933         (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%d", (uint_t)(v > 0));
3934         *val_cnt = 1;
3935         return (DLADM_STATUS_OK);
3936 }
3937 
3938 /* ARGSUSED */
3939 static dladm_status_t
3940 get_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3941     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3942     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3943 {
3944         dladm_status_t  status;
3945         uint32_t        v = 0;
3946 
3947         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3948             perm_flags, &v, sizeof (v));
3949         if (status != DLADM_STATUS_OK)
3950                 return (status);
3951 
3952         (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
3953         *val_cnt = 1;
3954         return (DLADM_STATUS_OK);
3955 }
3956 
3957 /* ARGSUSED */
3958 static dladm_status_t
3959 get_range(dladm_handle_t handle, prop_desc_t *pdp,
3960     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3961     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3962 {
3963         dld_ioc_macprop_t *dip;
3964         dladm_status_t status = DLADM_STATUS_OK;
3965         size_t  sz;
3966         uint_t  rcount;
3967         mac_propval_range_t *rangep;
3968 
3969         /*
3970          * As caller we don't know number of value ranges, the driver
3971          * supports. To begin with we assume that number to be 1. If the
3972          * buffer size is insufficient, driver returns back with the
3973          * actual count of value ranges. See mac.h for more details.
3974          */
3975         sz = sizeof (mac_propval_range_t);
3976         rcount = 1;
3977 retry:
3978         if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
3979             &status)) == NULL)
3980                 return (status);
3981 
3982         rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
3983         rangep->mpr_count = rcount;
3984 
3985         status = i_dladm_macprop(handle, dip, B_FALSE);
3986         if (status != DLADM_STATUS_OK) {
3987                 if (status == DLADM_STATUS_TOOSMALL) {
3988                         int err;
3989 
3990                         if ((err = i_dladm_range_size(rangep, &sz, &rcount))
3991                             == 0) {
3992                                 free(dip);
3993                                 goto retry;
3994                         } else {
3995                                 status = dladm_errno2status(err);
3996                         }
3997                 }
3998                 free(dip);
3999                 return (status);
4000         }
4001 
4002         if (rangep->mpr_count == 0) {
4003                 *val_cnt = 1;
4004                 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "--");
4005                 goto done;
4006         }
4007 
4008         switch (rangep->mpr_type) {
4009         case MAC_PROPVAL_UINT32: {
4010                 mac_propval_uint32_range_t *ur;
4011                 uint_t  count = rangep->mpr_count, i;
4012 
4013                 ur = &rangep->mpr_range_uint32[0];
4014 
4015                 for (i = 0; i < count; i++, ur++) {
4016                         if (ur->mpur_min == ur->mpur_max) {
4017                                 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
4018                                     "%ld", ur->mpur_min);
4019                         } else {
4020                                 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
4021                                     "%ld-%ld", ur->mpur_min, ur->mpur_max);
4022                         }
4023                 }
4024                 *val_cnt = count;
4025                 break;
4026         }
4027         default:
4028                 status = DLADM_STATUS_BADARG;
4029                 break;
4030         }
4031 done:
4032         free(dip);
4033         return (status);
4034 }
4035 
4036 /* ARGSUSED */
4037 static dladm_status_t
4038 get_tagmode(dladm_handle_t handle, prop_desc_t *pdp,
4039     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4040     datalink_media_t media, uint_t flags, uint_t *perm_flags)
4041 {
4042         link_tagmode_t          mode;
4043         dladm_status_t          status;
4044 
4045         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4046             perm_flags, &mode, sizeof (mode));
4047         if (status != DLADM_STATUS_OK)
4048                 return (status);
4049 
4050         switch (mode) {
4051         case LINK_TAGMODE_NORMAL:
4052                 (void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX);
4053                 break;
4054         case LINK_TAGMODE_VLANONLY:
4055                 (void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX);
4056                 break;
4057         default:
4058                 (void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX);
4059         }
4060         *val_cnt = 1;
4061         return (DLADM_STATUS_OK);
4062 }
4063 
4064 /* ARGSUSED */
4065 static dladm_status_t
4066 get_flowctl(dladm_handle_t handle, prop_desc_t *pdp,
4067     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4068     datalink_media_t media, uint_t flags, uint_t *perm_flags)
4069 {
4070         link_flowctrl_t v;
4071         dladm_status_t  status;
4072 
4073         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4074             perm_flags, &v, sizeof (v));
4075         if (status != DLADM_STATUS_OK)
4076                 return (status);
4077 
4078         switch (v) {
4079         case LINK_FLOWCTRL_NONE:
4080                 (void) sprintf(*prop_val, "no");
4081                 break;
4082         case LINK_FLOWCTRL_RX:
4083                 (void) sprintf(*prop_val, "rx");
4084                 break;
4085         case LINK_FLOWCTRL_TX:
4086                 (void) sprintf(*prop_val, "tx");
4087                 break;
4088         case LINK_FLOWCTRL_BI:
4089                 (void) sprintf(*prop_val, "bi");
4090                 break;
4091         }
4092         *val_cnt = 1;
4093         return (DLADM_STATUS_OK);
4094 }
4095 
4096 
4097 /* ARGSUSED */
4098 static dladm_status_t
4099 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid,
4100     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
4101 
4102 {
4103         int             i, slen;
4104         int             bufsize = 0;
4105         dld_ioc_macprop_t *dip = NULL;
4106         uchar_t         *dp;
4107         link_attr_t *p;
4108         dladm_status_t  status = DLADM_STATUS_OK;
4109 
4110         if ((prop_name == NULL && prop_val != NULL) ||
4111             (prop_val != NULL && val_cnt == 0))
4112                 return (DLADM_STATUS_BADARG);
4113         p = dladm_name2prop(prop_name);
4114         if (p->pp_id != MAC_PROP_PRIVATE)
4115                 return (DLADM_STATUS_BADARG);
4116 
4117         if (!(flags & DLADM_OPT_ACTIVE))
4118                 return (DLADM_STATUS_OK);
4119 
4120         /*
4121          * private properties: all parsing is done in the kernel.
4122          * allocate a enough space for each property + its separator (',').
4123          */
4124         for (i = 0; i < val_cnt; i++) {
4125                 bufsize += strlen(prop_val[i]) + 1;
4126         }
4127 
4128         if (prop_val == NULL) {
4129                 /*
4130                  * getting default value. so use more buffer space.
4131                  */
4132                 bufsize += DLADM_PROP_BUF_CHUNK;
4133         }
4134 
4135         dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
4136             (prop_val != NULL ? 0 : DLD_PROP_DEFAULT), &status);
4137         if (dip == NULL)
4138                 return (status);
4139 
4140         dp = (uchar_t *)dip->pr_val;
4141         slen = 0;
4142 
4143         if (prop_val == NULL) {
4144                 status = i_dladm_macprop(handle, dip, B_FALSE);
4145                 dip->pr_flags = 0;
4146         } else {
4147                 for (i = 0; i < val_cnt; i++) {
4148                         int plen = 0;
4149 
4150                         plen = strlen(prop_val[i]);
4151                         bcopy(prop_val[i], dp, plen);
4152                         slen += plen;
4153                         /*
4154                          * add a "," separator and update dp.
4155                          */
4156                         if (i != (val_cnt -1))
4157                                 dp[slen++] = ',';
4158                         dp += (plen + 1);
4159                 }
4160         }
4161         if (status == DLADM_STATUS_OK)
4162                 status = i_dladm_macprop(handle, dip, B_TRUE);
4163 
4164         free(dip);
4165         return (status);
4166 }
4167 
4168 static dladm_status_t
4169 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid,
4170     const char *prop_name, char **prop_val, uint_t *val_cnt,
4171     dladm_prop_type_t type, uint_t dld_flags)
4172 {
4173         dladm_status_t  status = DLADM_STATUS_OK;
4174         dld_ioc_macprop_t *dip = NULL;
4175         link_attr_t *p;
4176 
4177         if ((prop_name == NULL && prop_val != NULL) ||
4178             (prop_val != NULL && val_cnt == 0))
4179                 return (DLADM_STATUS_BADARG);
4180 
4181         p = dladm_name2prop(prop_name);
4182         if (p->pp_id != MAC_PROP_PRIVATE)
4183                 return (DLADM_STATUS_BADARG);
4184 
4185         /*
4186          * private properties: all parsing is done in the kernel.
4187          */
4188         dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
4189             dld_flags, &status);
4190         if (dip == NULL)
4191                 return (status);
4192 
4193         if ((status = i_dladm_macprop(handle, dip, B_FALSE)) ==
4194             DLADM_STATUS_OK) {
4195                 if (type == DLADM_PROP_VAL_PERM) {
4196                         (void) dladm_perm2str(dip->pr_perm_flags, *prop_val);
4197                 } else if (type == DLADM_PROP_VAL_MODIFIABLE) {
4198                         *prop_val[0] = '\0';
4199                 } else {
4200                         (void) strncpy(*prop_val, dip->pr_val,
4201                             DLADM_PROP_VAL_MAX);
4202                 }
4203                 *val_cnt = 1;
4204         } else if ((status == DLADM_STATUS_NOTSUP) &&
4205             (type == DLADM_PROP_VAL_CURRENT)) {
4206                 status = DLADM_STATUS_NOTFOUND;
4207         }
4208         free(dip);
4209         return (status);
4210 }
4211 
4212 
4213 static dladm_status_t
4214 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp,
4215     datalink_id_t linkid, datalink_media_t media, uint_t flags)
4216 {
4217         dladm_status_t status;
4218         char **prop_vals = NULL, *buf;
4219         size_t bufsize;
4220         uint_t cnt;
4221         int i;
4222         uint_t perm_flags;
4223 
4224         /*
4225          * Allocate buffer needed for prop_vals array. We can have at most
4226          * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
4227          * each entry has max size DLADM_PROP_VAL_MAX
4228          */
4229         bufsize =
4230             (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
4231         buf = malloc(bufsize);
4232         prop_vals = (char **)(void *)buf;
4233         for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
4234                 prop_vals[i] = buf +
4235                     sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4236                     i * DLADM_PROP_VAL_MAX;
4237         }
4238 
4239         /*
4240          * For properties which have pdp->pd_defval.vd_name as a non-empty
4241          * string, the "" itself is used to reset the property (exceptions
4242          * are zone and autopush, which populate vdp->vd_val). So
4243          * libdladm can copy pdp->pd_defval over to the val_desc_t passed
4244          * down on the setprop using the global values in the table. For
4245          * other cases (vd_name is ""), doing reset-linkprop will cause
4246          * libdladm to do a getprop to find the default value and then do
4247          * a setprop to reset the value to default.
4248          */
4249         status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media,
4250             DLD_PROP_DEFAULT, &perm_flags);
4251         if (status == DLADM_STATUS_OK) {
4252                 if (perm_flags == MAC_PROP_PERM_RW) {
4253                         status = i_dladm_set_single_prop(handle, linkid,
4254                             pdp->pd_class, media, pdp, prop_vals, cnt, flags);
4255                 }
4256                 else
4257                         status = DLADM_STATUS_NOTSUP;
4258         }
4259         free(buf);
4260         return (status);
4261 }
4262 
4263 /* ARGSUSED */
4264 static dladm_status_t
4265 get_stp(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid,
4266     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
4267     uint_t *perm_flags)
4268 {
4269         const bridge_public_prop_t *bpp;
4270         dladm_status_t retv;
4271         int val, i;
4272 
4273         if (flags != 0)
4274                 return (DLADM_STATUS_NOTSUP);
4275         *perm_flags = MAC_PROP_PERM_RW;
4276         *val_cnt = 1;
4277         for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++)
4278                 if (strcmp(bpp->bpp_name, pd->pd_name) == 0)
4279                         break;
4280         retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val);
4281         /* If the daemon isn't running, then return the persistent value */
4282         if (retv == DLADM_STATUS_NOTFOUND) {
4283                 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4284                     prop_val, val_cnt) != DLADM_STATUS_OK)
4285                         (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4286                             DLADM_PROP_VAL_MAX);
4287                 return (DLADM_STATUS_OK);
4288         }
4289         if (retv != DLADM_STATUS_OK) {
4290                 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4291                 return (retv);
4292         }
4293         if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') {
4294                 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4295                     DLADM_PROP_VAL_MAX);
4296                 return (DLADM_STATUS_OK);
4297         }
4298         for (i = 0; i < pd->pd_noptval; i++) {
4299                 if (val == pd->pd_optval[i].vd_val) {
4300                         (void) strlcpy(*prop_val, pd->pd_optval[i].vd_name,
4301                             DLADM_PROP_VAL_MAX);
4302                         return (DLADM_STATUS_OK);
4303                 }
4304         }
4305         (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val);
4306         return (DLADM_STATUS_OK);
4307 }
4308 
4309 /* ARGSUSED1 */
4310 static dladm_status_t
4311 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4312     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4313 {
4314         /*
4315          * Special case for mcheck: the daemon resets the value to zero, and we
4316          * don't want the daemon to refresh itself; it leads to deadlock.
4317          */
4318         if (flags & DLADM_OPT_NOREFRESH)
4319                 return (DLADM_STATUS_OK);
4320 
4321         /* Tell the running daemon, if any */
4322         return (dladm_bridge_refresh(handle, linkid));
4323 }
4324 
4325 /*
4326  * This is used only for stp_priority, stp_cost, and stp_mcheck.
4327  */
4328 /* ARGSUSED */
4329 static dladm_status_t
4330 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd,
4331     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4332     val_desc_t **vdpp, datalink_media_t media)
4333 {
4334         char            *cp;
4335         boolean_t       iscost;
4336         uint_t          val_cnt = *val_cntp;
4337         val_desc_t      *vdp = *vdpp;
4338 
4339         if (val_cnt != 1)
4340                 return (DLADM_STATUS_BADVALCNT);
4341 
4342         if (prop_val == NULL) {
4343                 vdp->vd_val = 0;
4344         } else {
4345                 /* Only stp_priority and stp_cost use this function */
4346                 iscost = strcmp(pd->pd_name, "stp_cost") == 0;
4347 
4348                 if (iscost && strcmp(prop_val[0], "auto") == 0) {
4349                         /* Illegal value 0 is allowed to mean "automatic" */
4350                         vdp->vd_val = 0;
4351                 } else {
4352                         errno = 0;
4353                         vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4354                         if (errno != 0 || *cp != '\0')
4355                                 return (DLADM_STATUS_BADVAL);
4356                 }
4357         }
4358 
4359         if (iscost) {
4360                 return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL :
4361                     DLADM_STATUS_OK);
4362         } else {
4363                 if (vdp->vd_val > 255)
4364                         return (DLADM_STATUS_BADVAL);
4365                 /*
4366                  * If the user is setting stp_mcheck non-zero, then (per the
4367                  * IEEE management standards and UNH testing) we need to check
4368                  * whether this link is part of a bridge that is running RSTP.
4369                  * If it's not, then setting the flag is an error.  Note that
4370                  * errors are intentionally discarded here; it's the value
4371                  * that's the problem -- it's not a bad value, merely one that
4372                  * can't be used now.
4373                  */
4374                 if (strcmp(pd->pd_name, "stp_mcheck") == 0 &&
4375                     vdp->vd_val != 0) {
4376                         char bridge[MAXLINKNAMELEN];
4377                         UID_STP_CFG_T cfg;
4378                         dladm_bridge_prot_t brprot;
4379 
4380                         if (dladm_bridge_getlink(handle, linkid, bridge,
4381                             sizeof (bridge)) != DLADM_STATUS_OK ||
4382                             dladm_bridge_get_properties(bridge, &cfg,
4383                             &brprot) != DLADM_STATUS_OK)
4384                                 return (DLADM_STATUS_FAILED);
4385                         if (cfg.force_version <= 1)
4386                                 return (DLADM_STATUS_FAILED);
4387                 }
4388                 return (DLADM_STATUS_OK);
4389         }
4390 }
4391 
4392 /* ARGSUSED */
4393 static dladm_status_t
4394 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd,
4395     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4396     datalink_media_t media, uint_t flags, uint_t *perm_flags)
4397 {
4398         dladm_status_t retv;
4399         uint_t val;
4400 
4401         if (flags != 0)
4402                 return (DLADM_STATUS_NOTSUP);
4403         *perm_flags = MAC_PROP_PERM_RW;
4404         *val_cnt = 1;
4405         retv = dladm_bridge_get_forwarding(handle, linkid, &val);
4406         if (retv == DLADM_STATUS_NOTFOUND) {
4407                 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4408                     prop_val, val_cnt) != DLADM_STATUS_OK)
4409                         (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4410                             DLADM_PROP_VAL_MAX);
4411                 return (DLADM_STATUS_OK);
4412         }
4413         if (retv == DLADM_STATUS_OK)
4414                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val);
4415         else
4416                 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4417         return (retv);
4418 }
4419 
4420 /* ARGSUSED */
4421 static dladm_status_t
4422 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4423     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4424 {
4425         /* Tell the running daemon, if any */
4426         return (dladm_bridge_refresh(handle, linkid));
4427 }
4428 
4429 /* ARGSUSED */
4430 static dladm_status_t
4431 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4432     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4433     datalink_media_t media, uint_t flags, uint_t *perm_flags)
4434 {
4435         dladm_status_t status;
4436         dld_ioc_macprop_t *dip;
4437         uint16_t pvid;
4438 
4439         if (flags != 0)
4440                 return (DLADM_STATUS_NOTSUP);
4441         *perm_flags = MAC_PROP_PERM_RW;
4442         *val_cnt = 1;
4443         dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4444             0, &status);
4445         if (dip == NULL)
4446                 return (status);
4447         status = i_dladm_macprop(handle, dip, B_FALSE);
4448         if (status == DLADM_STATUS_OK) {
4449                 (void) memcpy(&pvid, dip->pr_val, sizeof (pvid));
4450                 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid);
4451         } else {
4452                 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4453         }
4454         free(dip);
4455         return (status);
4456 }
4457 
4458 /* ARGSUSED */
4459 static dladm_status_t
4460 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4461     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4462 {
4463         dladm_status_t status;
4464         dld_ioc_macprop_t *dip;
4465         uint16_t pvid;
4466 
4467         dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4468             0, &status);
4469         if (dip == NULL)
4470                 return (status);
4471         pvid = vdp->vd_val;
4472         (void) memcpy(dip->pr_val, &pvid, sizeof (pvid));
4473         status = i_dladm_macprop(handle, dip, B_TRUE);
4474         free(dip);
4475         if (status != DLADM_STATUS_OK)
4476                 return (status);
4477 
4478         /* Tell the running daemon, if any */
4479         return (dladm_bridge_refresh(handle, linkid));
4480 }
4481 
4482 /* ARGSUSED */
4483 static dladm_status_t
4484 check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4485     datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4486     val_desc_t **vdpp, datalink_media_t media)
4487 {
4488         char            *cp;
4489         uint_t          val_cnt = *val_cntp;
4490         val_desc_t      *vdp = *vdpp;
4491 
4492         if (val_cnt != 1)
4493                 return (DLADM_STATUS_BADVALCNT);
4494 
4495         if (prop_val == NULL) {
4496                 vdp->vd_val = 1;
4497         } else {
4498                 errno = 0;
4499                 vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4500                 if (errno != 0 || *cp != '\0')
4501                         return (DLADM_STATUS_BADVAL);
4502         }
4503 
4504         return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL :
4505             DLADM_STATUS_OK);
4506 }
4507 
4508 dladm_status_t
4509 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf,
4510     mac_prop_id_t cmd, size_t len, boolean_t set)
4511 {
4512         uint32_t                flags;
4513         dladm_status_t          status;
4514         uint32_t                media;
4515         dld_ioc_macprop_t       *dip;
4516         void                    *dp;
4517 
4518         if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
4519             &media, NULL, 0)) != DLADM_STATUS_OK) {
4520                 return (status);
4521         }
4522 
4523         if (media != DL_WIFI)
4524                 return (DLADM_STATUS_BADARG);
4525 
4526         if (!(flags & DLADM_OPT_ACTIVE))
4527                 return (DLADM_STATUS_TEMPONLY);
4528 
4529         if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
4530                 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
4531 
4532         dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
4533         if (dip == NULL)
4534                 return (DLADM_STATUS_NOMEM);
4535 
4536         dp = (uchar_t *)dip->pr_val;
4537         if (set)
4538                 (void) memcpy(dp, buf, len);
4539 
4540         status = i_dladm_macprop(handle, dip, set);
4541         if (status == DLADM_STATUS_OK) {
4542                 if (!set)
4543                         (void) memcpy(buf, dp, len);
4544         }
4545 
4546         free(dip);
4547         return (status);
4548 }
4549 
4550 dladm_status_t
4551 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
4552 {
4553         return (dladm_parse_args(str, listp, novalues));
4554 }
4555 
4556 /*
4557  * Retrieve the one link property from the database
4558  */
4559 /*ARGSUSED*/
4560 static int
4561 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid,
4562     const char *prop_name, void *arg)
4563 {
4564         dladm_arg_list_t        *proplist = arg;
4565         dladm_arg_info_t        *aip = NULL;
4566 
4567         aip = &proplist->al_info[proplist->al_count];
4568         /*
4569          * it is fine to point to prop_name since prop_name points to the
4570          * prop_table[n].pd_name.
4571          */
4572         aip->ai_name = prop_name;
4573 
4574         (void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
4575             prop_name, aip->ai_val, &aip->ai_count);
4576 
4577         if (aip->ai_count != 0)
4578                 proplist->al_count++;
4579 
4580         return (DLADM_WALK_CONTINUE);
4581 }
4582 
4583 
4584 /*
4585  * Retrieve all link properties for a link from the database and
4586  * return a property list.
4587  */
4588 dladm_status_t
4589 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid,
4590     dladm_arg_list_t **listp)
4591 {
4592         dladm_arg_list_t        *list;
4593         dladm_status_t          status = DLADM_STATUS_OK;
4594 
4595         list = calloc(1, sizeof (dladm_arg_list_t));
4596         if (list == NULL)
4597                 return (dladm_errno2status(errno));
4598 
4599         status = dladm_walk_linkprop(handle, linkid, list,
4600             i_dladm_get_one_prop);
4601 
4602         *listp = list;
4603         return (status);
4604 }
4605 
4606 /*
4607  * Retrieve the named property from a proplist, check the value and
4608  * convert to a kernel structure.
4609  */
4610 static dladm_status_t
4611 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
4612     dladm_arg_list_t *proplist, const char *name, uint_t flags, void *arg)
4613 {
4614         dladm_status_t          status;
4615         dladm_arg_info_t        *aip = NULL;
4616         int                     i, j;
4617 
4618         /* Find named property in proplist */
4619         for (i = 0; i < proplist->al_count; i++) {
4620                 aip = &proplist->al_info[i];
4621                 if (strcasecmp(aip->ai_name, name) == 0)
4622                         break;
4623         }
4624 
4625         /* Property not in list */
4626         if (i == proplist->al_count)
4627                 return (DLADM_STATUS_OK);
4628 
4629         for (i = 0; i < DLADM_MAX_PROPS; i++) {
4630                 prop_desc_t     *pdp = &prop_table[i];
4631                 val_desc_t      *vdp;
4632 
4633                 vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
4634                 if (vdp == NULL)
4635                         return (DLADM_STATUS_NOMEM);
4636 
4637                 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
4638                         continue;
4639 
4640                 if (aip->ai_val == NULL)
4641                         return (DLADM_STATUS_BADARG);
4642 
4643                 /* Check property value */
4644                 if (pdp->pd_check != NULL) {
4645                         status = pdp->pd_check(handle, pdp, 0, aip->ai_val,
4646                             &(aip->ai_count), flags, &vdp, 0);
4647                 } else {
4648                         status = DLADM_STATUS_BADARG;
4649                 }
4650 
4651                 if (status != DLADM_STATUS_OK)
4652                         return (status);
4653 
4654                 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
4655                         resource_prop_t *rpp = &rsrc_prop_table[j];
4656 
4657                         if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
4658                                 continue;
4659 
4660                         /* Extract kernel structure */
4661                         if (rpp->rp_extract != NULL) {
4662                                 status = rpp->rp_extract(vdp,
4663                                     aip->ai_count, arg);
4664                         } else {
4665                                 status = DLADM_STATUS_BADARG;
4666                         }
4667                         break;
4668                 }
4669 
4670                 if (status != DLADM_STATUS_OK)
4671                         return (status);
4672 
4673                 break;
4674         }
4675         return (status);
4676 }
4677 
4678 /*
4679  * Extract properties from a proplist and convert to mac_resource_props_t.
4680  */
4681 dladm_status_t
4682 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
4683     mac_resource_props_t *mrp, uint_t flags)
4684 {
4685         dladm_status_t  status;
4686         int             i;
4687 
4688         for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
4689                 status = i_dladm_link_proplist_extract_one(handle,
4690                     proplist, rsrc_prop_table[i].rp_name, flags, mrp);
4691                 if (status != DLADM_STATUS_OK)
4692                         return (status);
4693         }
4694         return (status);
4695 }
4696 
4697 static const char *
4698 dladm_perm2str(uint_t perm, char *buf)
4699 {
4700         (void) snprintf(buf, DLADM_STRSIZE, "%c%c",
4701             ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-',
4702             ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-');
4703         return (buf);
4704 }
4705 
4706 dladm_status_t
4707 dladm_get_state(dladm_handle_t handle, datalink_id_t linkid,
4708     link_state_t *state)
4709 {
4710         uint_t                  perms;
4711 
4712         return (i_dladm_get_public_prop(handle, linkid, "state", 0,
4713             &perms, state, sizeof (*state)));
4714 }
4715 
4716 boolean_t
4717 dladm_attr_is_linkprop(const char *name)
4718 {
4719         /* non-property attribute names */
4720         const char *nonprop[] = {
4721                 /* dlmgmtd core attributes */
4722                 "name",
4723                 "class",
4724                 "media",
4725                 FPHYMAJ,
4726                 FPHYINST,
4727                 FDEVNAME,
4728 
4729                 /* other attributes for vlan, aggr, etc */
4730                 DLADM_ATTR_NAMES
4731         };
4732         boolean_t       is_nonprop = B_FALSE;
4733         int             i;
4734 
4735         for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) {
4736                 if (strcmp(name, nonprop[i]) == 0) {
4737                         is_nonprop = B_TRUE;
4738                         break;
4739                 }
4740         }
4741 
4742         return (!is_nonprop);
4743 }
4744 
4745 dladm_status_t
4746 dladm_linkprop_is_set(dladm_handle_t handle, datalink_id_t linkid,
4747     dladm_prop_type_t type, const char *prop_name, boolean_t *is_set)
4748 {
4749         char            *buf, **propvals;
4750         uint_t          valcnt = DLADM_MAX_PROP_VALCNT;
4751         int             i;
4752         dladm_status_t  status = DLADM_STATUS_OK;
4753         size_t          bufsize;
4754 
4755         *is_set = B_FALSE;
4756 
4757         bufsize = (sizeof (char *) + DLADM_PROP_VAL_MAX) *
4758             DLADM_MAX_PROP_VALCNT;
4759         if ((buf = calloc(1, bufsize)) == NULL)
4760                 return (DLADM_STATUS_NOMEM);
4761 
4762         propvals = (char **)(void *)buf;
4763         for (i = 0; i < valcnt; i++) {
4764                 propvals[i] = buf +
4765                     sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4766                     i * DLADM_PROP_VAL_MAX;
4767         }
4768 
4769         if (dladm_get_linkprop(handle, linkid, type, prop_name, propvals,
4770             &valcnt) != DLADM_STATUS_OK) {
4771                 goto done;
4772         }
4773 
4774         /*
4775          * valcnt is always set to 1 by get_pool(), hence we need to check
4776          * for a non-null string to see if it is set. For protection,
4777          * secondary-macs and allowed-ips, we can check either the *propval
4778          * or the valcnt.
4779          */
4780         if ((strcmp(prop_name, "pool") == 0 ||
4781             strcmp(prop_name, "protection") == 0 ||
4782             strcmp(prop_name, "secondary-macs") == 0 ||
4783             strcmp(prop_name, "allowed-ips") == 0) &&
4784             (strlen(*propvals) != 0)) {
4785                 *is_set = B_TRUE;
4786         } else if ((strcmp(prop_name, "cpus") == 0) && (valcnt != 0)) {
4787                 *is_set = B_TRUE;
4788         } else if ((strcmp(prop_name, "_softmac") == 0) && (valcnt != 0) &&
4789             (strcmp(propvals[0], "true") == 0)) {
4790                 *is_set = B_TRUE;
4791         }
4792 
4793 done:
4794         if (buf != NULL)
4795                 free(buf);
4796         return (status);
4797 }
4798 
4799 /* ARGSUSED */
4800 static dladm_status_t
4801 get_linkmode_prop(dladm_handle_t handle, prop_desc_t *pdp,
4802     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4803     datalink_media_t media, uint_t flags, uint_t *perm_flags)
4804 {
4805         char                    *s;
4806         uint32_t                v;
4807         dladm_status_t          status;
4808 
4809         status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4810             perm_flags, &v, sizeof (v));
4811         if (status != DLADM_STATUS_OK)
4812                 return (status);
4813 
4814         switch (v) {
4815         case DLADM_PART_CM_MODE:
4816                 s = "cm";
4817                 break;
4818         case DLADM_PART_UD_MODE:
4819                 s = "ud";
4820                 break;
4821         default:
4822                 s = "";
4823                 break;
4824         }
4825         (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", s);
4826 
4827         *val_cnt = 1;
4828         return (DLADM_STATUS_OK);
4829 }