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