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