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