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