1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdlib.h> 27 #include <strings.h> 28 #include <errno.h> 29 #include <ctype.h> 30 #include <stddef.h> 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <sys/dld.h> 34 #include <sys/zone.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include <libdevinfo.h> 38 #include <zone.h> 39 #include <libdllink.h> 40 #include <libdladm_impl.h> 41 #include <libdlwlan_impl.h> 42 #include <libdlwlan.h> 43 #include <libdlvlan.h> 44 #include <libdlvnic.h> 45 #include <libintl.h> 46 #include <dlfcn.h> 47 #include <link.h> 48 #include <inet/wifi_ioctl.h> 49 #include <libdladm.h> 50 #include <libdlstat.h> 51 #include <sys/param.h> 52 #include <sys/debug.h> 53 #include <sys/dld.h> 54 #include <sys/mac_flow.h> 55 #include <inttypes.h> 56 #include <sys/ethernet.h> 57 #include <inet/iptun.h> 58 #include <net/wpa.h> 59 #include <sys/sysmacros.h> 60 #include <sys/vlan.h> 61 #include <libdlbridge.h> 62 #include <stp_in.h> 63 64 /* 65 * The linkprop get() callback. 66 * - pd: pointer to the prop_desc_t 67 * - propstrp: a property string array to keep the returned property. 68 * Caller allocated. 69 * - cntp: number of returned properties. 70 * Caller also uses it to indicate how many it expects. 71 */ 72 struct prop_desc; 73 typedef struct prop_desc prop_desc_t; 74 75 typedef dladm_status_t pd_getf_t(dladm_handle_t, prop_desc_t *pdp, 76 datalink_id_t, char **propstp, uint_t *cntp, 77 datalink_media_t, uint_t, uint_t *); 78 79 /* 80 * The linkprop set() callback. 81 * - propval: a val_desc_t array which keeps the property values to be set. 82 * - cnt: number of properties to be set. 83 * - flags: additional flags passed down the system call. 84 * 85 * pd_set takes val_desc_t given by pd_check(), translates it into 86 * a format suitable for kernel consumption. This may require allocation 87 * of ioctl buffers etc. pd_set() may call another common routine (used 88 * by all other pd_sets) which invokes the ioctl. 89 */ 90 typedef dladm_status_t pd_setf_t(dladm_handle_t, prop_desc_t *, datalink_id_t, 91 val_desc_t *propval, uint_t cnt, uint_t flags, 92 datalink_media_t); 93 94 /* 95 * The linkprop check() callback. 96 * - propstrp: property string array which keeps the property to be checked. 97 * - cnt: number of properties. 98 * - propval: return value; the property values of the given property strings. 99 * 100 * pd_check checks that the input values are valid. It does so by 101 * iteraring through the pd_modval list for the property. If 102 * the modifiable values cannot be expressed as a list, a pd_check 103 * specific to this property can be used. If the input values are 104 * verified to be valid, pd_check allocates a val_desc_t and fills it 105 * with either a val_desc_t found on the pd_modval list or something 106 * generated on the fly. 107 */ 108 typedef dladm_status_t pd_checkf_t(dladm_handle_t, prop_desc_t *pdp, 109 datalink_id_t, char **propstrp, uint_t cnt, 110 val_desc_t *propval, datalink_media_t); 111 112 typedef struct link_attr_s { 113 mac_prop_id_t pp_id; 114 size_t pp_valsize; 115 char *pp_name; 116 } link_attr_t; 117 118 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t, 119 const char *, uint_t, dladm_status_t *); 120 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t, 121 mac_prop_id_t, uint_t, dladm_status_t *); 122 static dld_ioc_macprop_t *i_dladm_get_public_prop(dladm_handle_t, datalink_id_t, 123 char *, uint_t, dladm_status_t *, uint_t *); 124 125 static dladm_status_t i_dladm_set_private_prop(dladm_handle_t, datalink_id_t, 126 const char *, char **, uint_t, uint_t); 127 static dladm_status_t i_dladm_get_priv_prop(dladm_handle_t, datalink_id_t, 128 const char *, char **, uint_t *, dladm_prop_type_t, 129 uint_t); 130 static link_attr_t *dladm_name2prop(const char *); 131 static link_attr_t *dladm_id2prop(mac_prop_id_t); 132 133 static pd_getf_t do_get_zone, do_get_autopush, do_get_rate_mod, 134 do_get_rate_prop, do_get_channel_prop, 135 do_get_powermode_prop, do_get_radio_prop, 136 i_dladm_duplex_get, i_dladm_status_get, 137 i_dladm_binary_get, i_dladm_uint32_get, 138 i_dladm_flowctl_get, i_dladm_maxbw_get, 139 i_dladm_cpus_get, i_dladm_priority_get, 140 i_dladm_tagmode_get, i_dladm_range_get, 141 get_stp_prop, get_bridge_forward, 142 get_bridge_pvid; 143 144 static pd_setf_t do_set_zone, do_set_rate_prop, 145 do_set_powermode_prop, do_set_radio_prop, 146 i_dladm_set_public_prop, do_set_res, do_set_cpus, 147 set_stp_prop, set_bridge_forward, set_bridge_pvid; 148 149 static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate, 150 do_check_hoplimit, do_check_encaplim, 151 i_dladm_uint32_check, do_check_maxbw, do_check_cpus, 152 do_check_priority, check_stp_prop, check_bridge_pvid; 153 154 static dladm_status_t i_dladm_speed_get(dladm_handle_t, prop_desc_t *, 155 datalink_id_t, char **, uint_t *, uint_t, uint_t *); 156 static dladm_status_t i_dladm_macprop(dladm_handle_t, void *, boolean_t); 157 static const char *dladm_perm2str(uint_t, char *); 158 159 struct prop_desc { 160 /* 161 * link property name 162 */ 163 char *pd_name; 164 165 /* 166 * default property value, can be set to { "", NULL } 167 */ 168 val_desc_t pd_defval; 169 170 /* 171 * list of optional property values, can be NULL. 172 * 173 * This is set to non-NULL if there is a list of possible property 174 * values. pd_optval would point to the array of possible values. 175 */ 176 val_desc_t *pd_optval; 177 178 /* 179 * count of the above optional property values. 0 if pd_optval is NULL. 180 */ 181 uint_t pd_noptval; 182 183 /* 184 * callback to set link property; set to NULL if this property is 185 * read-only and may be called before or after permanent update; see 186 * flags. 187 */ 188 pd_setf_t *pd_set; 189 190 /* 191 * callback to get modifiable link property 192 */ 193 pd_getf_t *pd_getmod; 194 195 /* 196 * callback to get current link property 197 */ 198 pd_getf_t *pd_get; 199 200 /* 201 * callback to validate link property value, set to NULL if pd_optval 202 * is not NULL. In that case, validate the value by comparing it with 203 * the pd_optval. Return a val_desc_t array pointer if the value is 204 * valid. 205 */ 206 pd_checkf_t *pd_check; 207 208 uint_t pd_flags; 209 #define PD_TEMPONLY 0x1 /* property is temporary only */ 210 #define PD_CHECK_ALLOC 0x2 /* alloc vd_val as part of pd_check */ 211 #define PD_AFTER_PERM 0x4 /* pd_set after db update; no temporary */ 212 /* 213 * indicate link classes this property applies to. 214 */ 215 datalink_class_t pd_class; 216 217 /* 218 * indicate link media type this property applies to. 219 */ 220 datalink_media_t pd_dmedia; 221 }; 222 223 #define MAC_PROP_BUFSIZE(v) sizeof (dld_ioc_macprop_t) + (v) - 1 224 225 /* 226 * Supported link properties enumerated in the prop_table[] array are 227 * computed using the callback functions in that array. To compute the 228 * property value, multiple distinct system calls may be needed (e.g., 229 * for wifi speed, we need to issue system calls to get desired/supported 230 * rates). The link_attr[] table enumerates the interfaces to the kernel, 231 * and the type/size of the data passed in the user-kernel interface. 232 */ 233 static link_attr_t link_attr[] = { 234 { MAC_PROP_DUPLEX, sizeof (link_duplex_t), "duplex"}, 235 236 { MAC_PROP_SPEED, sizeof (uint64_t), "speed"}, 237 238 { MAC_PROP_STATUS, sizeof (link_state_t), "state"}, 239 240 { MAC_PROP_AUTONEG, sizeof (uint8_t), "adv_autoneg_cap"}, 241 242 { MAC_PROP_MTU, sizeof (uint32_t), "mtu"}, 243 244 { MAC_PROP_FLOWCTRL, sizeof (link_flowctrl_t), "flowctrl"}, 245 246 { MAC_PROP_ZONE, sizeof (dld_ioc_zid_t), "zone"}, 247 248 { MAC_PROP_AUTOPUSH, sizeof (struct dlautopush), "autopush"}, 249 250 { MAC_PROP_ADV_10GFDX_CAP, sizeof (uint8_t), "adv_10gfdx_cap"}, 251 252 { MAC_PROP_EN_10GFDX_CAP, sizeof (uint8_t), "en_10gfdx_cap"}, 253 254 { MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t), "adv_1000fdx_cap"}, 255 256 { MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t), "en_1000fdx_cap"}, 257 258 { MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t), "adv_1000hdx_cap"}, 259 260 { MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t), "en_1000hdx_cap"}, 261 262 { MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t), "adv_100fdx_cap"}, 263 264 { MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t), "en_100fdx_cap"}, 265 266 { MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t), "adv_100hdx_cap"}, 267 268 { MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t), "en_100hdx_cap"}, 269 270 { MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t), "adv_10fdx_cap"}, 271 272 { MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t), "en_10fdx_cap"}, 273 274 { MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t), "adv_10hdx_cap"}, 275 276 { MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t), "en_10hdx_cap"}, 277 278 { MAC_PROP_WL_ESSID, sizeof (wl_linkstatus_t), "essid"}, 279 280 { MAC_PROP_WL_BSSID, sizeof (wl_bssid_t), "bssid"}, 281 282 { MAC_PROP_WL_BSSTYPE, sizeof (wl_bss_type_t), "bsstype"}, 283 284 { MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"}, 285 286 /* wl_rates_t has variable length */ 287 { MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"}, 288 289 /* wl_rates_t has variable length */ 290 { MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"}, 291 292 { MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"}, 293 294 { MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"}, 295 296 { MAC_PROP_WL_RSSI, sizeof (wl_rssi_t), "signal"}, 297 298 { MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"}, 299 300 { MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"}, 301 302 { MAC_PROP_WL_WPA, sizeof (wl_wpa_t), "wpa"}, 303 304 /* wl_wpa_ess_t has variable length */ 305 { MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"}, 306 307 { MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"}, 308 309 { MAC_PROP_WL_RADIO, sizeof (dladm_wlan_radio_t), "wl_radio"}, 310 311 { MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t), "wl_ess_list"}, 312 313 { MAC_PROP_WL_KEY_TAB, sizeof (wl_wep_key_tab_t), "wl_wep_key"}, 314 315 { MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"}, 316 317 /* wl_wpa_ie_t has variable length */ 318 { MAC_PROP_WL_SETOPTIE, sizeof (wl_wpa_ie_t), "set_ie"}, 319 320 { MAC_PROP_WL_DELKEY, sizeof (wl_del_key_t), "wpa_del_key"}, 321 322 { MAC_PROP_WL_KEY, sizeof (wl_key_t), "wl_key"}, 323 324 { MAC_PROP_WL_MLME, sizeof (wl_mlme_t), "mlme"}, 325 326 { MAC_PROP_MAXBW, sizeof (mac_resource_props_t), "maxbw"}, 327 328 { MAC_PROP_PRIO, sizeof (mac_resource_props_t), "priority"}, 329 330 { MAC_PROP_BIND_CPU, sizeof (mac_resource_props_t), "cpus"}, 331 332 { MAC_PROP_TAGMODE, sizeof (link_tagmode_t), "tagmode"}, 333 334 { MAC_PROP_IPTUN_HOPLIMIT, sizeof (uint32_t), "hoplimit"}, 335 336 { MAC_PROP_IPTUN_ENCAPLIMIT, sizeof (uint32_t), "encaplimit"}, 337 338 { MAC_PROP_PVID, sizeof (uint16_t), "default_tag"}, 339 340 { MAC_PROP_LLIMIT, sizeof (uint32_t), "learn_limit"}, 341 342 { MAC_PROP_LDECAY, sizeof (uint32_t), "learn_decay"}, 343 344 { MAC_PROP_PRIVATE, 0, "driver-private"} 345 346 }; 347 348 typedef struct bridge_public_prop_s { 349 const char *bpp_name; 350 int bpp_code; 351 } bridge_public_prop_t; 352 353 static const bridge_public_prop_t bridge_prop[] = { 354 { "stp", PT_CFG_NON_STP }, 355 { "stp_priority", PT_CFG_PRIO }, 356 { "stp_cost", PT_CFG_COST }, 357 { "stp_edge", PT_CFG_EDGE }, 358 { "stp_p2p", PT_CFG_P2P }, 359 { "stp_mcheck", PT_CFG_MCHECK }, 360 { NULL, 0 } 361 }; 362 363 static val_desc_t link_duplex_vals[] = { 364 { "half", LINK_DUPLEX_HALF }, 365 { "full", LINK_DUPLEX_HALF } 366 }; 367 static val_desc_t link_status_vals[] = { 368 { "up", LINK_STATE_UP }, 369 { "down", LINK_STATE_DOWN } 370 }; 371 static val_desc_t link_01_vals[] = { 372 { "1", 1 }, 373 { "0", 0 } 374 }; 375 static val_desc_t link_flow_vals[] = { 376 { "no", LINK_FLOWCTRL_NONE }, 377 { "tx", LINK_FLOWCTRL_TX }, 378 { "rx", LINK_FLOWCTRL_RX }, 379 { "bi", LINK_FLOWCTRL_BI } 380 }; 381 static val_desc_t link_priority_vals[] = { 382 { "low", MPL_LOW }, 383 { "medium", MPL_MEDIUM }, 384 { "high", MPL_HIGH } 385 }; 386 387 static val_desc_t link_tagmode_vals[] = { 388 { "normal", LINK_TAGMODE_NORMAL }, 389 { "vlanonly", LINK_TAGMODE_VLANONLY } 390 }; 391 392 static val_desc_t dladm_wlan_radio_vals[] = { 393 { "on", DLADM_WLAN_RADIO_ON }, 394 { "off", DLADM_WLAN_RADIO_OFF } 395 }; 396 397 static val_desc_t dladm_wlan_powermode_vals[] = { 398 { "off", DLADM_WLAN_PM_OFF }, 399 { "fast", DLADM_WLAN_PM_FAST }, 400 { "max", DLADM_WLAN_PM_MAX } 401 }; 402 403 static val_desc_t stp_p2p_vals[] = { 404 { "true", P2P_FORCE_TRUE }, 405 { "false", P2P_FORCE_FALSE }, 406 { "auto", P2P_AUTO } 407 }; 408 409 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) 410 #define RESET_VAL ((uintptr_t)-1) 411 412 static prop_desc_t prop_table[] = { 413 { "channel", { NULL, 0 }, 414 NULL, 0, NULL, NULL, 415 do_get_channel_prop, NULL, 0, 416 DATALINK_CLASS_PHYS, DL_WIFI }, 417 418 { "powermode", { "off", DLADM_WLAN_PM_OFF }, 419 dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals), 420 do_set_powermode_prop, NULL, 421 do_get_powermode_prop, NULL, 0, 422 DATALINK_CLASS_PHYS, DL_WIFI }, 423 424 { "radio", { "on", DLADM_WLAN_RADIO_ON }, 425 dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals), 426 do_set_radio_prop, NULL, 427 do_get_radio_prop, NULL, 0, 428 DATALINK_CLASS_PHYS, DL_WIFI }, 429 430 { "speed", { "", 0 }, NULL, 0, 431 do_set_rate_prop, do_get_rate_mod, 432 do_get_rate_prop, do_check_rate, 0, 433 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE }, 434 435 { "autopush", { "", 0 }, NULL, 0, 436 i_dladm_set_public_prop, NULL, 437 do_get_autopush, do_check_autopush, PD_CHECK_ALLOC, 438 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 439 440 { "zone", { "", 0 }, NULL, 0, 441 do_set_zone, NULL, 442 do_get_zone, do_check_zone, PD_TEMPONLY|PD_CHECK_ALLOC, 443 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 444 445 { "duplex", { "", 0 }, 446 link_duplex_vals, VALCNT(link_duplex_vals), 447 NULL, NULL, i_dladm_duplex_get, NULL, 448 0, DATALINK_CLASS_PHYS, DL_ETHER }, 449 450 { "state", { "up", LINK_STATE_UP }, 451 link_status_vals, VALCNT(link_status_vals), 452 NULL, NULL, i_dladm_status_get, NULL, 453 0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 454 455 { "adv_autoneg_cap", { "", 0 }, 456 link_01_vals, VALCNT(link_01_vals), 457 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 458 0, DATALINK_CLASS_PHYS, DL_ETHER }, 459 460 { "mtu", { "", 0 }, NULL, 0, 461 i_dladm_set_public_prop, i_dladm_range_get, 462 i_dladm_uint32_get, i_dladm_uint32_check, 0, DATALINK_CLASS_ALL, 463 DATALINK_ANY_MEDIATYPE }, 464 465 { "flowctrl", { "", 0 }, 466 link_flow_vals, VALCNT(link_flow_vals), 467 i_dladm_set_public_prop, NULL, i_dladm_flowctl_get, NULL, 468 0, DATALINK_CLASS_PHYS, DL_ETHER }, 469 470 { "adv_10gfdx_cap", { "", 0 }, 471 link_01_vals, VALCNT(link_01_vals), 472 NULL, NULL, i_dladm_binary_get, NULL, 473 0, DATALINK_CLASS_PHYS, DL_ETHER }, 474 475 { "en_10gfdx_cap", { "", 0 }, 476 link_01_vals, VALCNT(link_01_vals), 477 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 478 0, DATALINK_CLASS_PHYS, DL_ETHER }, 479 480 { "adv_1000fdx_cap", { "", 0 }, 481 link_01_vals, VALCNT(link_01_vals), 482 NULL, NULL, i_dladm_binary_get, NULL, 483 0, DATALINK_CLASS_PHYS, DL_ETHER }, 484 485 { "en_1000fdx_cap", { "", 0 }, 486 link_01_vals, VALCNT(link_01_vals), 487 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 488 0, DATALINK_CLASS_PHYS, DL_ETHER }, 489 490 { "adv_1000hdx_cap", { "", 0 }, 491 link_01_vals, VALCNT(link_01_vals), 492 NULL, NULL, i_dladm_binary_get, NULL, 493 0, DATALINK_CLASS_PHYS, DL_ETHER }, 494 495 { "en_1000hdx_cap", { "", 0 }, 496 link_01_vals, VALCNT(link_01_vals), 497 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 498 0, DATALINK_CLASS_PHYS, DL_ETHER }, 499 500 { "adv_100fdx_cap", { "", 0 }, 501 link_01_vals, VALCNT(link_01_vals), 502 NULL, NULL, i_dladm_binary_get, NULL, 503 0, DATALINK_CLASS_PHYS, DL_ETHER }, 504 505 { "en_100fdx_cap", { "", 0 }, 506 link_01_vals, VALCNT(link_01_vals), 507 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 508 0, DATALINK_CLASS_PHYS, DL_ETHER }, 509 510 { "adv_100hdx_cap", { "", 0 }, 511 link_01_vals, VALCNT(link_01_vals), 512 NULL, NULL, i_dladm_binary_get, NULL, 513 0, DATALINK_CLASS_PHYS, DL_ETHER }, 514 515 { "en_100hdx_cap", { "", 0 }, 516 link_01_vals, VALCNT(link_01_vals), 517 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 518 0, DATALINK_CLASS_PHYS, DL_ETHER }, 519 520 { "adv_10fdx_cap", { "", 0 }, 521 link_01_vals, VALCNT(link_01_vals), 522 NULL, NULL, i_dladm_binary_get, NULL, 523 0, DATALINK_CLASS_PHYS, DL_ETHER }, 524 525 { "en_10fdx_cap", { "", 0 }, 526 link_01_vals, VALCNT(link_01_vals), 527 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 528 0, DATALINK_CLASS_PHYS, DL_ETHER }, 529 530 { "adv_10hdx_cap", { "", 0 }, 531 link_01_vals, VALCNT(link_01_vals), 532 NULL, NULL, i_dladm_binary_get, NULL, 533 0, DATALINK_CLASS_PHYS, DL_ETHER }, 534 535 { "en_10hdx_cap", { "", 0 }, 536 link_01_vals, VALCNT(link_01_vals), 537 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 538 0, DATALINK_CLASS_PHYS, DL_ETHER }, 539 540 { "maxbw", { "--", RESET_VAL }, NULL, 0, 541 do_set_res, NULL, 542 i_dladm_maxbw_get, do_check_maxbw, PD_CHECK_ALLOC, 543 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 544 545 { "cpus", { "--", RESET_VAL }, NULL, 0, 546 do_set_cpus, NULL, 547 i_dladm_cpus_get, do_check_cpus, 0, 548 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 549 550 { "priority", { "high", RESET_VAL }, 551 link_priority_vals, VALCNT(link_priority_vals), do_set_res, NULL, 552 i_dladm_priority_get, do_check_priority, PD_CHECK_ALLOC, 553 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 554 555 { "tagmode", { "vlanonly", LINK_TAGMODE_VLANONLY }, 556 link_tagmode_vals, VALCNT(link_tagmode_vals), 557 i_dladm_set_public_prop, NULL, i_dladm_tagmode_get, 558 NULL, 0, 559 DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | DATALINK_CLASS_VNIC, 560 DL_ETHER }, 561 562 { "hoplimit", { "", 0 }, NULL, 0, 563 i_dladm_set_public_prop, i_dladm_range_get, i_dladm_uint32_get, 564 do_check_hoplimit, 0, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE}, 565 566 { "encaplimit", { "", 0 }, NULL, 0, 567 i_dladm_set_public_prop, i_dladm_range_get, i_dladm_uint32_get, 568 do_check_encaplim, 0, DATALINK_CLASS_IPTUN, DL_IPV6}, 569 570 { "forward", { "1", 1 }, 571 link_01_vals, VALCNT(link_01_vals), 572 set_bridge_forward, NULL, get_bridge_forward, NULL, PD_AFTER_PERM, 573 DATALINK_CLASS_ALL & ~DATALINK_CLASS_VNIC, DL_ETHER }, 574 575 { "default_tag", { "1", 1 }, NULL, 0, 576 set_bridge_pvid, NULL, get_bridge_pvid, check_bridge_pvid, 577 0, DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 578 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 579 580 { "learn_limit", { "1000", 1000 }, NULL, 0, 581 i_dladm_set_public_prop, NULL, i_dladm_uint32_get, 582 i_dladm_uint32_check, 0, 583 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 584 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 585 586 { "learn_decay", { "200", 200 }, NULL, 0, 587 i_dladm_set_public_prop, NULL, i_dladm_uint32_get, 588 i_dladm_uint32_check, 0, 589 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 590 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 591 592 { "stp", { "1", 1 }, 593 link_01_vals, VALCNT(link_01_vals), 594 set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM, 595 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 596 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 597 598 { "stp_priority", { "128", 128 }, NULL, 0, 599 set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM, 600 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 601 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 602 603 { "stp_cost", { "auto", 0 }, NULL, 0, 604 set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM, 605 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 606 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 607 608 { "stp_edge", { "1", 1 }, 609 link_01_vals, VALCNT(link_01_vals), 610 set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM, 611 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 612 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 613 614 { "stp_p2p", { "auto", P2P_AUTO }, 615 stp_p2p_vals, VALCNT(stp_p2p_vals), 616 set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM, 617 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 618 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 619 620 { "stp_mcheck", { "0", 0 }, 621 link_01_vals, VALCNT(link_01_vals), 622 set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM, 623 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 624 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 625 }; 626 627 #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) 628 629 static resource_prop_t rsrc_prop_table[] = { 630 {"maxbw", do_extract_maxbw}, 631 {"priority", do_extract_priority}, 632 {"cpus", do_extract_cpus} 633 }; 634 #define DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \ 635 sizeof (resource_prop_t)) 636 637 /* 638 * when retrieving private properties, we pass down a buffer with 639 * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value. 640 */ 641 #define DLADM_PROP_BUF_CHUNK 1024 642 643 static dladm_status_t i_dladm_set_linkprop_db(dladm_handle_t, datalink_id_t, 644 const char *, char **, uint_t); 645 static dladm_status_t i_dladm_get_linkprop_db(dladm_handle_t, datalink_id_t, 646 const char *, char **, uint_t *); 647 static dladm_status_t i_dladm_walk_linkprop_priv_db(dladm_handle_t, 648 datalink_id_t, void *, int (*)(dladm_handle_t, 649 datalink_id_t, const char *, void *)); 650 static dladm_status_t i_dladm_set_single_prop(dladm_handle_t, datalink_id_t, 651 datalink_class_t, uint32_t, prop_desc_t *, char **, 652 uint_t, uint_t); 653 static dladm_status_t i_dladm_set_linkprop(dladm_handle_t, datalink_id_t, 654 const char *, char **, uint_t, uint_t); 655 static dladm_status_t i_dladm_getset_defval(dladm_handle_t, prop_desc_t *, 656 datalink_id_t, datalink_media_t, uint_t); 657 658 /* 659 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all 660 * rates to be retrieved. However, we cannot increase it at this 661 * time because it will break binary compatibility with unbundled 662 * WiFi drivers and utilities. So for now we define an additional 663 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. 664 */ 665 #define MAX_SUPPORT_RATES 64 666 667 #define AP_ANCHOR "[anchor]" 668 #define AP_DELIMITER '.' 669 670 static dladm_status_t 671 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, 672 val_desc_t *vdp) 673 { 674 int i, j; 675 dladm_status_t status = DLADM_STATUS_OK; 676 677 for (j = 0; j < val_cnt; j++) { 678 for (i = 0; i < pdp->pd_noptval; i++) { 679 if (strcasecmp(*prop_val, 680 pdp->pd_optval[i].vd_name) == 0) { 681 break; 682 } 683 } 684 if (i == pdp->pd_noptval) { 685 status = DLADM_STATUS_BADVAL; 686 goto done; 687 } 688 (void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t)); 689 } 690 691 done: 692 return (status); 693 } 694 695 static dladm_status_t 696 i_dladm_set_single_prop(dladm_handle_t handle, datalink_id_t linkid, 697 datalink_class_t class, uint32_t media, prop_desc_t *pdp, char **prop_val, 698 uint_t val_cnt, uint_t flags) 699 { 700 dladm_status_t status = DLADM_STATUS_OK; 701 val_desc_t *vdp = NULL; 702 boolean_t needfree = B_FALSE; 703 uint_t cnt, i; 704 705 if (!(pdp->pd_class & class)) 706 return (DLADM_STATUS_BADARG); 707 708 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 709 return (DLADM_STATUS_BADARG); 710 711 if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY)) 712 return (DLADM_STATUS_TEMPONLY); 713 714 if (!(flags & DLADM_OPT_ACTIVE)) 715 return (DLADM_STATUS_OK); 716 717 if (pdp->pd_set == NULL) 718 return (DLADM_STATUS_PROPRDONLY); 719 720 if (prop_val != NULL) { 721 vdp = malloc(sizeof (val_desc_t) * val_cnt); 722 if (vdp == NULL) 723 return (DLADM_STATUS_NOMEM); 724 725 if (pdp->pd_check != NULL) { 726 needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0); 727 status = pdp->pd_check(handle, pdp, linkid, prop_val, 728 val_cnt, vdp, media); 729 } else if (pdp->pd_optval != NULL) { 730 status = do_check_prop(pdp, prop_val, val_cnt, vdp); 731 } else { 732 status = DLADM_STATUS_BADARG; 733 } 734 735 if (status != DLADM_STATUS_OK) 736 goto done; 737 738 cnt = val_cnt; 739 } else { 740 boolean_t defval = B_FALSE; 741 742 if (pdp->pd_defval.vd_name == NULL) 743 return (DLADM_STATUS_NOTSUP); 744 745 cnt = 1; 746 defval = (strlen(pdp->pd_defval.vd_name) > 0); 747 if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || defval) { 748 if ((vdp = malloc(sizeof (val_desc_t))) == NULL) 749 return (DLADM_STATUS_NOMEM); 750 751 if (defval) { 752 (void) memcpy(vdp, &pdp->pd_defval, 753 sizeof (val_desc_t)); 754 } else if (pdp->pd_check != NULL) { 755 status = pdp->pd_check(handle, pdp, linkid, 756 prop_val, cnt, vdp, media); 757 if (status != DLADM_STATUS_OK) 758 goto done; 759 } 760 } else { 761 status = i_dladm_getset_defval(handle, pdp, linkid, 762 media, flags); 763 return (status); 764 } 765 } 766 if (pdp->pd_flags & PD_AFTER_PERM) 767 status = (flags & DLADM_OPT_PERSIST) ? DLADM_STATUS_OK : 768 DLADM_STATUS_PERMONLY; 769 else 770 status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags, 771 media); 772 if (needfree) { 773 for (i = 0; i < cnt; i++) 774 free((void *)((val_desc_t *)vdp + i)->vd_val); 775 } 776 done: 777 free(vdp); 778 return (status); 779 } 780 781 static dladm_status_t 782 i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid, 783 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags) 784 { 785 int i; 786 boolean_t found = B_FALSE; 787 datalink_class_t class; 788 uint32_t media; 789 dladm_status_t status = DLADM_STATUS_OK; 790 791 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, 792 NULL, 0); 793 if (status != DLADM_STATUS_OK) 794 return (status); 795 796 for (i = 0; i < DLADM_MAX_PROPS; i++) { 797 prop_desc_t *pdp = &prop_table[i]; 798 dladm_status_t s; 799 800 if (prop_name != NULL && 801 (strcasecmp(prop_name, pdp->pd_name) != 0)) 802 continue; 803 found = B_TRUE; 804 s = i_dladm_set_single_prop(handle, linkid, class, media, pdp, 805 prop_val, val_cnt, flags); 806 807 if (prop_name != NULL) { 808 status = s; 809 break; 810 } else { 811 if (s != DLADM_STATUS_OK && 812 s != DLADM_STATUS_NOTSUP) 813 status = s; 814 } 815 } 816 if (!found) { 817 if (prop_name[0] == '_') { 818 /* other private properties */ 819 status = i_dladm_set_private_prop(handle, linkid, 820 prop_name, prop_val, val_cnt, flags); 821 } else { 822 status = DLADM_STATUS_NOTFOUND; 823 } 824 } 825 826 return (status); 827 } 828 829 /* 830 * Set/reset link property for specific link 831 */ 832 dladm_status_t 833 dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid, 834 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags) 835 { 836 dladm_status_t status = DLADM_STATUS_OK; 837 838 if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) || 839 (prop_val == NULL && val_cnt > 0) || 840 (prop_val != NULL && val_cnt == 0) || 841 (prop_name == NULL && prop_val != NULL)) { 842 return (DLADM_STATUS_BADARG); 843 } 844 845 /* 846 * Check for valid link property against the flags passed 847 * and set the link property when active flag is passed. 848 */ 849 status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val, 850 val_cnt, flags); 851 if (status != DLADM_STATUS_OK) 852 return (status); 853 854 if (flags & DLADM_OPT_PERSIST) { 855 status = i_dladm_set_linkprop_db(handle, linkid, prop_name, 856 prop_val, val_cnt); 857 858 if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) { 859 prop_desc_t *pdp = prop_table; 860 int i; 861 862 for (i = 0; i < DLADM_MAX_PROPS; i++, pdp++) { 863 if (!(pdp->pd_flags & PD_AFTER_PERM)) 864 continue; 865 if (prop_name != NULL && 866 strcasecmp(prop_name, pdp->pd_name) != 0) 867 continue; 868 status = pdp->pd_set(handle, pdp, linkid, NULL, 869 0, flags, 0); 870 } 871 } 872 } 873 return (status); 874 } 875 876 /* 877 * Walk all link properties of the given specific link. 878 * 879 * Note: this function currently lacks the ability to walk _all_ private 880 * properties if the link, because there is no kernel interface to 881 * retrieve all known private property names. Once such an interface 882 * is added, this function should be fixed accordingly. 883 */ 884 dladm_status_t 885 dladm_walk_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg, 886 int (*func)(dladm_handle_t, datalink_id_t, const char *, void *)) 887 { 888 dladm_status_t status; 889 datalink_class_t class; 890 uint_t media; 891 int i; 892 893 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 894 return (DLADM_STATUS_BADARG); 895 896 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, 897 NULL, 0); 898 if (status != DLADM_STATUS_OK) 899 return (status); 900 901 /* public */ 902 for (i = 0; i < DLADM_MAX_PROPS; i++) { 903 if (!(prop_table[i].pd_class & class)) 904 continue; 905 906 if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media)) 907 continue; 908 909 if (func(handle, linkid, prop_table[i].pd_name, arg) == 910 DLADM_WALK_TERMINATE) { 911 break; 912 } 913 } 914 915 /* private */ 916 status = i_dladm_walk_linkprop_priv_db(handle, linkid, arg, func); 917 918 return (status); 919 } 920 921 /* 922 * Get linkprop of the given specific link. 923 */ 924 dladm_status_t 925 dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid, 926 dladm_prop_type_t type, const char *prop_name, char **prop_val, 927 uint_t *val_cntp) 928 { 929 dladm_status_t status = DLADM_STATUS_OK; 930 datalink_class_t class; 931 uint_t media; 932 prop_desc_t *pdp; 933 uint_t cnt, dld_flags = 0; 934 int i; 935 uint_t perm_flags; 936 937 if (type == DLADM_PROP_VAL_DEFAULT) 938 dld_flags |= MAC_PROP_DEFAULT; 939 else if (type == DLADM_PROP_VAL_MODIFIABLE) 940 dld_flags |= MAC_PROP_POSSIBLE; 941 942 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || 943 prop_val == NULL || val_cntp == NULL || *val_cntp == 0) 944 return (DLADM_STATUS_BADARG); 945 946 for (i = 0; i < DLADM_MAX_PROPS; i++) 947 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) 948 break; 949 950 if (i == DLADM_MAX_PROPS) { 951 if (prop_name[0] == '_') { 952 /* 953 * private property. 954 */ 955 if (type == DLADM_PROP_VAL_PERSISTENT) 956 return (i_dladm_get_linkprop_db(handle, linkid, 957 prop_name, prop_val, val_cntp)); 958 else 959 return (i_dladm_get_priv_prop(handle, linkid, 960 prop_name, prop_val, val_cntp, type, 961 dld_flags)); 962 } else { 963 return (DLADM_STATUS_NOTFOUND); 964 } 965 } 966 967 pdp = &prop_table[i]; 968 969 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, 970 NULL, 0); 971 if (status != DLADM_STATUS_OK) 972 return (status); 973 974 if (!(pdp->pd_class & class)) 975 return (DLADM_STATUS_BADARG); 976 977 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 978 return (DLADM_STATUS_BADARG); 979 980 switch (type) { 981 case DLADM_PROP_VAL_CURRENT: 982 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp, 983 media, dld_flags, &perm_flags); 984 break; 985 986 case DLADM_PROP_VAL_PERM: 987 if (pdp->pd_set == NULL) { 988 perm_flags = MAC_PROP_PERM_READ; 989 } else { 990 status = pdp->pd_get(handle, pdp, linkid, prop_val, 991 val_cntp, media, dld_flags, &perm_flags); 992 } 993 994 *prop_val[0] = '\0'; 995 *val_cntp = 1; 996 if (status == DLADM_STATUS_OK) 997 (void) dladm_perm2str(perm_flags, *prop_val); 998 break; 999 1000 case DLADM_PROP_VAL_DEFAULT: 1001 /* 1002 * If defaults are not defined for the property, 1003 * pd_defval.vd_name should be null. If the driver 1004 * has to be contacted for the value, vd_name should 1005 * be the empty string (""). Otherwise, dladm will 1006 * just print whatever is in the table. 1007 */ 1008 if (pdp->pd_defval.vd_name == NULL) { 1009 status = DLADM_STATUS_NOTSUP; 1010 break; 1011 } 1012 1013 if (strlen(pdp->pd_defval.vd_name) == 0) { 1014 status = pdp->pd_get(handle, pdp, linkid, prop_val, 1015 val_cntp, media, dld_flags, &perm_flags); 1016 } else { 1017 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 1018 } 1019 *val_cntp = 1; 1020 break; 1021 1022 case DLADM_PROP_VAL_MODIFIABLE: 1023 if (pdp->pd_getmod != NULL) { 1024 status = pdp->pd_getmod(handle, pdp, linkid, prop_val, 1025 val_cntp, media, dld_flags, &perm_flags); 1026 break; 1027 } 1028 cnt = pdp->pd_noptval; 1029 if (cnt == 0) { 1030 status = DLADM_STATUS_NOTSUP; 1031 } else if (cnt > *val_cntp) { 1032 status = DLADM_STATUS_TOOSMALL; 1033 } else { 1034 for (i = 0; i < cnt; i++) { 1035 (void) strcpy(prop_val[i], 1036 pdp->pd_optval[i].vd_name); 1037 } 1038 *val_cntp = cnt; 1039 } 1040 break; 1041 case DLADM_PROP_VAL_PERSISTENT: 1042 if (pdp->pd_flags & PD_TEMPONLY) 1043 return (DLADM_STATUS_TEMPONLY); 1044 status = i_dladm_get_linkprop_db(handle, linkid, prop_name, 1045 prop_val, val_cntp); 1046 break; 1047 default: 1048 status = DLADM_STATUS_BADARG; 1049 break; 1050 } 1051 1052 return (status); 1053 } 1054 1055 /* 1056 * Get linkprop of the given specific link and run any possible conversion 1057 * of the values using the check function for the property. Fails if the 1058 * check function doesn't succeed for the property value. 1059 */ 1060 dladm_status_t 1061 dladm_get_linkprop_values(dladm_handle_t handle, datalink_id_t linkid, 1062 dladm_prop_type_t type, const char *prop_name, uint_t *ret_val, 1063 uint_t *val_cntp) 1064 { 1065 dladm_status_t status; 1066 datalink_class_t class; 1067 uint_t media; 1068 prop_desc_t *pdp; 1069 uint_t dld_flags; 1070 int valc, i; 1071 char **prop_val; 1072 uint_t perm_flags; 1073 1074 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || 1075 ret_val == NULL || val_cntp == NULL || *val_cntp == 0) 1076 return (DLADM_STATUS_BADARG); 1077 1078 for (pdp = prop_table; pdp < prop_table + DLADM_MAX_PROPS; pdp++) 1079 if (strcasecmp(prop_name, pdp->pd_name) == 0) 1080 break; 1081 1082 if (pdp == prop_table + DLADM_MAX_PROPS) 1083 return (DLADM_STATUS_NOTFOUND); 1084 1085 if (pdp->pd_flags & PD_CHECK_ALLOC) 1086 return (DLADM_STATUS_BADARG); 1087 1088 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, 1089 NULL, 0); 1090 if (status != DLADM_STATUS_OK) 1091 return (status); 1092 1093 if (!(pdp->pd_class & class)) 1094 return (DLADM_STATUS_BADARG); 1095 1096 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 1097 return (DLADM_STATUS_BADARG); 1098 1099 prop_val = malloc(*val_cntp * sizeof (*prop_val) + 1100 *val_cntp * DLADM_PROP_VAL_MAX); 1101 if (prop_val == NULL) 1102 return (DLADM_STATUS_NOMEM); 1103 for (valc = 0; valc < *val_cntp; valc++) 1104 prop_val[valc] = (char *)(prop_val + *val_cntp) + 1105 valc * DLADM_PROP_VAL_MAX; 1106 1107 dld_flags = (type == DLADM_PROP_VAL_DEFAULT) ? MAC_PROP_DEFAULT : 0; 1108 1109 switch (type) { 1110 case DLADM_PROP_VAL_CURRENT: 1111 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp, 1112 media, dld_flags, &perm_flags); 1113 break; 1114 1115 case DLADM_PROP_VAL_DEFAULT: 1116 /* 1117 * If defaults are not defined for the property, 1118 * pd_defval.vd_name should be null. If the driver 1119 * has to be contacted for the value, vd_name should 1120 * be the empty string (""). Otherwise, dladm will 1121 * just print whatever is in the table. 1122 */ 1123 if (pdp->pd_defval.vd_name == NULL) { 1124 status = DLADM_STATUS_NOTSUP; 1125 break; 1126 } 1127 1128 if (pdp->pd_defval.vd_name[0] != '\0') { 1129 *val_cntp = 1; 1130 *ret_val = pdp->pd_defval.vd_val; 1131 free(prop_val); 1132 return (DLADM_STATUS_OK); 1133 } 1134 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp, 1135 media, dld_flags, &perm_flags); 1136 break; 1137 1138 case DLADM_PROP_VAL_PERSISTENT: 1139 if (pdp->pd_flags & PD_TEMPONLY) 1140 status = DLADM_STATUS_TEMPONLY; 1141 else 1142 status = i_dladm_get_linkprop_db(handle, linkid, 1143 prop_name, prop_val, val_cntp); 1144 break; 1145 1146 default: 1147 status = DLADM_STATUS_BADARG; 1148 break; 1149 } 1150 1151 if (status == DLADM_STATUS_OK) { 1152 if (pdp->pd_check != NULL) { 1153 val_desc_t *vdp; 1154 1155 vdp = malloc(sizeof (val_desc_t) * *val_cntp); 1156 if (vdp == NULL) 1157 status = DLADM_STATUS_NOMEM; 1158 else 1159 status = pdp->pd_check(handle, pdp, linkid, 1160 prop_val, *val_cntp, vdp, media); 1161 if (status == DLADM_STATUS_OK) { 1162 for (valc = 0; valc < *val_cntp; valc++) 1163 ret_val[valc] = vdp[valc].vd_val; 1164 } 1165 free(vdp); 1166 } else { 1167 for (valc = 0; valc < *val_cntp; valc++) { 1168 for (i = 0; i < pdp->pd_noptval; i++) { 1169 if (strcmp(pdp->pd_optval[i].vd_name, 1170 prop_val[valc]) == 0) { 1171 ret_val[valc] = 1172 pdp->pd_optval[i].vd_val; 1173 break; 1174 } 1175 } 1176 if (i == pdp->pd_noptval) { 1177 status = DLADM_STATUS_FAILED; 1178 break; 1179 } 1180 } 1181 } 1182 } 1183 1184 free(prop_val); 1185 1186 return (status); 1187 } 1188 1189 /*ARGSUSED*/ 1190 static int 1191 i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid, 1192 const char *prop_name, void *arg) 1193 { 1194 char *buf, **propvals; 1195 uint_t i, valcnt = DLADM_MAX_PROP_VALCNT; 1196 1197 if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 1198 DLADM_MAX_PROP_VALCNT)) == NULL) { 1199 return (DLADM_WALK_CONTINUE); 1200 } 1201 1202 propvals = (char **)(void *)buf; 1203 for (i = 0; i < valcnt; i++) { 1204 propvals[i] = buf + 1205 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 1206 i * DLADM_PROP_VAL_MAX; 1207 } 1208 1209 if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT, 1210 prop_name, propvals, &valcnt) != DLADM_STATUS_OK) { 1211 goto done; 1212 } 1213 1214 (void) dladm_set_linkprop(handle, linkid, prop_name, propvals, valcnt, 1215 DLADM_OPT_ACTIVE); 1216 1217 done: 1218 if (buf != NULL) 1219 free(buf); 1220 1221 return (DLADM_WALK_CONTINUE); 1222 } 1223 1224 /*ARGSUSED*/ 1225 static int 1226 i_dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg) 1227 { 1228 datalink_class_t class; 1229 dladm_status_t status; 1230 1231 status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 1232 NULL, 0); 1233 if (status != DLADM_STATUS_OK) 1234 return (DLADM_WALK_TERMINATE); 1235 1236 if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0) 1237 (void) dladm_init_linkprop(handle, linkid, B_TRUE); 1238 1239 return (DLADM_WALK_CONTINUE); 1240 } 1241 1242 dladm_status_t 1243 dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, 1244 boolean_t any_media) 1245 { 1246 datalink_media_t dmedia; 1247 uint32_t media; 1248 1249 dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI; 1250 1251 if (linkid == DATALINK_ALL_LINKID) { 1252 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle, 1253 NULL, DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST); 1254 } else if (any_media || 1255 ((dladm_datalink_id2info(handle, linkid, NULL, NULL, &media, NULL, 1256 0) == DLADM_STATUS_OK) && 1257 DATALINK_MEDIA_ACCEPTED(dmedia, media))) { 1258 (void) dladm_walk_linkprop(handle, linkid, NULL, 1259 i_dladm_init_one_prop); 1260 } 1261 return (DLADM_STATUS_OK); 1262 } 1263 1264 /* ARGSUSED */ 1265 static dladm_status_t 1266 do_get_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1267 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1268 uint_t flags, uint_t *perm_flags) 1269 { 1270 char zone_name[ZONENAME_MAX]; 1271 zoneid_t zid; 1272 dladm_status_t status; 1273 char *cp; 1274 dld_ioc_macprop_t *dip; 1275 1276 if (flags != 0) 1277 return (DLADM_STATUS_NOTSUP); 1278 1279 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1280 &status, perm_flags); 1281 if (status != DLADM_STATUS_OK) 1282 return (status); 1283 1284 cp = dip->pr_val; 1285 (void) memcpy(&zid, cp, sizeof (zid)); 1286 free(dip); 1287 1288 *val_cnt = 1; 1289 if (zid != GLOBAL_ZONEID) { 1290 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) { 1291 return (dladm_errno2status(errno)); 1292 } 1293 1294 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); 1295 } else { 1296 *prop_val[0] = '\0'; 1297 } 1298 1299 return (DLADM_STATUS_OK); 1300 } 1301 1302 typedef int (*zone_get_devroot_t)(char *, char *, size_t); 1303 1304 static int 1305 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen) 1306 { 1307 char root[MAXPATHLEN]; 1308 zone_get_devroot_t real_zone_get_devroot; 1309 void *dlhandle; 1310 void *sym; 1311 int ret; 1312 1313 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL) 1314 return (-1); 1315 1316 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) { 1317 (void) dlclose(dlhandle); 1318 return (-1); 1319 } 1320 1321 real_zone_get_devroot = (zone_get_devroot_t)sym; 1322 1323 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0) 1324 (void) snprintf(dev, devlen, "%s%s", root, "/dev"); 1325 (void) dlclose(dlhandle); 1326 return (ret); 1327 } 1328 1329 static dladm_status_t 1330 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid, 1331 datalink_id_t linkid, boolean_t add) 1332 { 1333 char path[MAXPATHLEN]; 1334 char name[MAXLINKNAMELEN]; 1335 di_prof_t prof = NULL; 1336 char zone_name[ZONENAME_MAX]; 1337 dladm_status_t status; 1338 int ret; 1339 1340 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 1341 return (dladm_errno2status(errno)); 1342 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) 1343 return (dladm_errno2status(errno)); 1344 if (di_prof_init(path, &prof) != 0) 1345 return (dladm_errno2status(errno)); 1346 1347 status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN); 1348 if (status != DLADM_STATUS_OK) 1349 goto cleanup; 1350 1351 if (add) 1352 ret = di_prof_add_dev(prof, name); 1353 else 1354 ret = di_prof_add_exclude(prof, name); 1355 1356 if (ret != 0) { 1357 status = dladm_errno2status(errno); 1358 goto cleanup; 1359 } 1360 1361 if (di_prof_commit(prof) != 0) 1362 status = dladm_errno2status(errno); 1363 cleanup: 1364 if (prof) 1365 di_prof_fini(prof); 1366 1367 return (status); 1368 } 1369 1370 /* ARGSUSED */ 1371 static dladm_status_t 1372 do_set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1373 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1374 { 1375 dladm_status_t status = DLADM_STATUS_OK; 1376 zoneid_t zid_old, zid_new; 1377 char *cp; 1378 dld_ioc_macprop_t *dip; 1379 dld_ioc_zid_t *dzp; 1380 1381 if (val_cnt != 1) 1382 return (DLADM_STATUS_BADVALCNT); 1383 1384 dzp = (dld_ioc_zid_t *)vdp->vd_val; 1385 1386 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1387 &status, NULL); 1388 if (status != DLADM_STATUS_OK) 1389 return (status); 1390 1391 cp = dip->pr_val; 1392 (void) memcpy(&zid_old, cp, sizeof (zid_old)); 1393 free(dip); 1394 1395 zid_new = dzp->diz_zid; 1396 if (zid_new == zid_old) 1397 return (DLADM_STATUS_OK); 1398 1399 if ((status = i_dladm_set_public_prop(handle, pdp, linkid, vdp, val_cnt, 1400 flags, media)) != DLADM_STATUS_OK) 1401 return (status); 1402 1403 /* 1404 * It is okay to fail to update the /dev entry (some vanity-named 1405 * links do not have a /dev entry). 1406 */ 1407 if (zid_old != GLOBAL_ZONEID) { 1408 (void) i_dladm_update_deventry(handle, zid_old, linkid, 1409 B_FALSE); 1410 } 1411 if (zid_new != GLOBAL_ZONEID) 1412 (void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE); 1413 1414 return (DLADM_STATUS_OK); 1415 } 1416 1417 /* ARGSUSED */ 1418 static dladm_status_t 1419 do_check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1420 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1421 { 1422 char *zone_name; 1423 zoneid_t zoneid; 1424 dladm_status_t status = DLADM_STATUS_OK; 1425 dld_ioc_zid_t *dzp; 1426 1427 if (val_cnt != 1) 1428 return (DLADM_STATUS_BADVALCNT); 1429 1430 dzp = malloc(sizeof (dld_ioc_zid_t)); 1431 if (dzp == NULL) 1432 return (DLADM_STATUS_NOMEM); 1433 1434 zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME; 1435 if ((zoneid = getzoneidbyname(zone_name)) == -1) { 1436 status = DLADM_STATUS_BADVAL; 1437 goto done; 1438 } 1439 1440 if (zoneid != GLOBAL_ZONEID) { 1441 ushort_t flags; 1442 1443 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags, 1444 sizeof (flags)) < 0) { 1445 status = dladm_errno2status(errno); 1446 goto done; 1447 } 1448 1449 if (!(flags & ZF_NET_EXCL)) { 1450 status = DLADM_STATUS_BADVAL; 1451 goto done; 1452 } 1453 } 1454 1455 (void) memset(dzp, 0, sizeof (dld_ioc_zid_t)); 1456 1457 dzp->diz_zid = zoneid; 1458 dzp->diz_linkid = linkid; 1459 1460 vdp->vd_val = (uintptr_t)dzp; 1461 return (DLADM_STATUS_OK); 1462 done: 1463 free(dzp); 1464 return (status); 1465 } 1466 1467 /* ARGSUSED */ 1468 static dladm_status_t 1469 i_dladm_maxbw_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1470 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1471 uint_t flags, uint_t *perm_flags) 1472 { 1473 dld_ioc_macprop_t *dip; 1474 mac_resource_props_t mrp; 1475 dladm_status_t status; 1476 1477 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1478 &status, perm_flags); 1479 if (dip == NULL) 1480 return (status); 1481 1482 bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t)); 1483 free(dip); 1484 1485 if ((mrp.mrp_mask & MRP_MAXBW) == 0) { 1486 (*prop_val)[0] = '\0'; 1487 } else { 1488 (void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]); 1489 } 1490 *val_cnt = 1; 1491 return (DLADM_STATUS_OK); 1492 } 1493 1494 /* ARGSUSED */ 1495 static dladm_status_t 1496 do_check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1497 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1498 { 1499 uint64_t *maxbw; 1500 dladm_status_t status = DLADM_STATUS_OK; 1501 1502 if (val_cnt != 1) 1503 return (DLADM_STATUS_BADVALCNT); 1504 1505 maxbw = malloc(sizeof (uint64_t)); 1506 if (maxbw == NULL) 1507 return (DLADM_STATUS_NOMEM); 1508 1509 status = dladm_str2bw(*prop_val, maxbw); 1510 if (status != DLADM_STATUS_OK) { 1511 free(maxbw); 1512 return (status); 1513 } 1514 1515 if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) { 1516 free(maxbw); 1517 return (DLADM_STATUS_MINMAXBW); 1518 } 1519 1520 vdp->vd_val = (uintptr_t)maxbw; 1521 return (DLADM_STATUS_OK); 1522 } 1523 1524 /* ARGSUSED */ 1525 dladm_status_t 1526 do_extract_maxbw(val_desc_t *vdp, void *arg, uint_t cnt) 1527 { 1528 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 1529 1530 bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t)); 1531 mrp->mrp_mask |= MRP_MAXBW; 1532 1533 return (DLADM_STATUS_OK); 1534 } 1535 1536 /* ARGSUSED */ 1537 static dladm_status_t 1538 i_dladm_cpus_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1539 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1540 uint_t flags, uint_t *perm_flags) 1541 { 1542 dld_ioc_macprop_t *dip; 1543 mac_resource_props_t mrp; 1544 int i; 1545 uint32_t ncpus; 1546 uchar_t *cp; 1547 dladm_status_t status; 1548 1549 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1550 &status, perm_flags); 1551 if (dip == NULL) 1552 return (status); 1553 1554 cp = (uchar_t *)dip->pr_val; 1555 (void) memcpy(&mrp, cp, sizeof (mac_resource_props_t)); 1556 free(dip); 1557 1558 ncpus = mrp.mrp_ncpus; 1559 1560 if (ncpus > *val_cnt) 1561 return (DLADM_STATUS_TOOSMALL); 1562 1563 if (ncpus == 0) { 1564 (*prop_val)[0] = '\0'; 1565 *val_cnt = 1; 1566 return (DLADM_STATUS_OK); 1567 } 1568 1569 *val_cnt = ncpus; 1570 for (i = 0; i < ncpus; i++) { 1571 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX, 1572 "%u", mrp.mrp_cpu[i]); 1573 } 1574 return (DLADM_STATUS_OK); 1575 } 1576 1577 /* ARGSUSED */ 1578 static dladm_status_t 1579 do_set_res(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1580 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1581 { 1582 mac_resource_props_t mrp; 1583 dladm_status_t status = DLADM_STATUS_OK; 1584 dld_ioc_macprop_t *dip; 1585 1586 bzero(&mrp, sizeof (mac_resource_props_t)); 1587 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 1588 flags, &status); 1589 1590 if (dip == NULL) 1591 return (status); 1592 1593 if (vdp->vd_val == RESET_VAL) { 1594 switch (dip->pr_num) { 1595 case MAC_PROP_MAXBW: 1596 mrp.mrp_maxbw = MRP_MAXBW_RESETVAL; 1597 mrp.mrp_mask = MRP_MAXBW; 1598 break; 1599 case MAC_PROP_PRIO: 1600 mrp.mrp_priority = MPL_RESET; 1601 mrp.mrp_mask = MRP_PRIORITY; 1602 break; 1603 default: 1604 free(dip); 1605 return (DLADM_STATUS_BADARG); 1606 } 1607 } else { 1608 switch (dip->pr_num) { 1609 case MAC_PROP_MAXBW: 1610 bcopy((void *)vdp->vd_val, &mrp.mrp_maxbw, 1611 sizeof (uint64_t)); 1612 mrp.mrp_mask = MRP_MAXBW; 1613 break; 1614 case MAC_PROP_PRIO: 1615 bcopy((void *)vdp->vd_val, &mrp.mrp_priority, 1616 sizeof (mac_priority_level_t)); 1617 mrp.mrp_mask = MRP_PRIORITY; 1618 break; 1619 default: 1620 free(dip); 1621 return (DLADM_STATUS_BADARG); 1622 } 1623 } 1624 1625 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize); 1626 status = i_dladm_macprop(handle, dip, B_TRUE); 1627 free(dip); 1628 return (status); 1629 } 1630 1631 /* ARGSUSED */ 1632 static dladm_status_t 1633 do_set_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1634 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1635 { 1636 mac_resource_props_t mrp; 1637 dladm_status_t status; 1638 dld_ioc_macprop_t *dip; 1639 datalink_class_t class; 1640 1641 /* 1642 * CPU bindings can be set on VNIC and regular physical links. 1643 * However VNICs fails the dladm_phys_info test(). So apply 1644 * the phys_info test only on physical links. 1645 */ 1646 if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class, 1647 NULL, NULL, 0)) != DLADM_STATUS_OK) { 1648 return (status); 1649 } 1650 1651 /* 1652 * We set intr_cpu to -1. The interrupt will be retargetted, 1653 * if possible when the setup is complete in MAC. 1654 */ 1655 bzero(&mrp, sizeof (mac_resource_props_t)); 1656 mrp.mrp_mask = MRP_CPUS; 1657 if (vdp != NULL && vdp->vd_val != RESET_VAL) { 1658 mac_resource_props_t *vmrp; 1659 1660 vmrp = (mac_resource_props_t *)vdp->vd_val; 1661 if (vmrp->mrp_ncpus > 0) { 1662 bcopy(vmrp, &mrp, sizeof (mac_resource_props_t)); 1663 mrp.mrp_mask = MRP_CPUS; 1664 } 1665 mrp.mrp_mask |= MRP_CPUS_USERSPEC; 1666 mrp.mrp_fanout_mode = MCM_CPUS; 1667 mrp.mrp_intr_cpu = -1; 1668 } 1669 1670 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 1671 flags, &status); 1672 if (dip == NULL) 1673 return (status); 1674 1675 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize); 1676 status = i_dladm_macprop(handle, dip, B_TRUE); 1677 free(dip); 1678 return (status); 1679 } 1680 1681 /* ARGSUSED */ 1682 static dladm_status_t 1683 do_check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1684 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1685 { 1686 uint32_t cpuid; 1687 int i, j, rc; 1688 long nproc = sysconf(_SC_NPROCESSORS_CONF); 1689 mac_resource_props_t *mrp; 1690 1691 mrp = malloc(sizeof (mac_resource_props_t)); 1692 if (mrp == NULL) 1693 return (DLADM_STATUS_NOMEM); 1694 1695 for (i = 0; i < val_cnt; i++) { 1696 errno = 0; 1697 cpuid = strtol(prop_val[i], (char **)NULL, 10); 1698 if (errno != 0 || cpuid >= nproc) { 1699 free(mrp); 1700 return (DLADM_STATUS_CPUMAX); 1701 } 1702 rc = p_online(cpuid, P_STATUS); 1703 if (rc < 1) { 1704 free(mrp); 1705 return (DLADM_STATUS_CPUERR); 1706 } 1707 if (rc != P_ONLINE) { 1708 free(mrp); 1709 return (DLADM_STATUS_CPUNOTONLINE); 1710 } 1711 mrp->mrp_cpu[i] = cpuid; 1712 } 1713 mrp->mrp_ncpus = (uint32_t)val_cnt; 1714 1715 /* Check for duplicates */ 1716 for (i = 0; i < val_cnt; i++) { 1717 for (j = 0; j < val_cnt; j++) { 1718 if (i != j && mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) { 1719 free(mrp); 1720 return (DLADM_STATUS_BADARG); 1721 } 1722 } 1723 } 1724 vdp->vd_val = (uintptr_t)mrp; 1725 1726 return (DLADM_STATUS_OK); 1727 } 1728 1729 /* ARGSUSED */ 1730 dladm_status_t 1731 do_extract_cpus(val_desc_t *vdp, void *arg, uint_t cnt) 1732 { 1733 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 1734 mac_resource_props_t *vmrp = (mac_resource_props_t *)vdp->vd_val; 1735 int i; 1736 1737 for (i = 0; i < vmrp->mrp_ncpus; i++) { 1738 mrp->mrp_cpu[i] = vmrp->mrp_cpu[i]; 1739 } 1740 mrp->mrp_ncpus = vmrp->mrp_ncpus; 1741 mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC); 1742 mrp->mrp_fanout_mode = MCM_CPUS; 1743 mrp->mrp_intr_cpu = -1; 1744 1745 return (DLADM_STATUS_OK); 1746 } 1747 1748 /* ARGSUSED */ 1749 static dladm_status_t 1750 i_dladm_priority_get(dladm_handle_t handle, prop_desc_t *pdp, 1751 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 1752 datalink_media_t media, uint_t flags, uint_t *perm_flags) 1753 { 1754 dld_ioc_macprop_t *dip; 1755 mac_resource_props_t mrp; 1756 mac_priority_level_t pri; 1757 dladm_status_t status; 1758 1759 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1760 &status, perm_flags); 1761 if (dip == NULL) 1762 return (status); 1763 1764 bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t)); 1765 free(dip); 1766 1767 pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH : 1768 mrp.mrp_priority; 1769 1770 (void) dladm_pri2str(pri, prop_val[0]); 1771 *val_cnt = 1; 1772 return (DLADM_STATUS_OK); 1773 } 1774 1775 /* ARGSUSED */ 1776 static dladm_status_t 1777 do_check_priority(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1778 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1779 { 1780 mac_priority_level_t *pri; 1781 dladm_status_t status = DLADM_STATUS_OK; 1782 1783 if (val_cnt != 1) 1784 return (DLADM_STATUS_BADVALCNT); 1785 1786 pri = malloc(sizeof (mac_priority_level_t)); 1787 if (pri == NULL) 1788 return (DLADM_STATUS_NOMEM); 1789 1790 status = dladm_str2pri(*prop_val, pri); 1791 if (status != DLADM_STATUS_OK) { 1792 free(pri); 1793 return (status); 1794 } 1795 1796 if (*pri < MPL_LOW || *pri > MPL_HIGH) { 1797 free(pri); 1798 return (DLADM_STATUS_BADVAL); 1799 } 1800 1801 vdp->vd_val = (uintptr_t)pri; 1802 return (DLADM_STATUS_OK); 1803 } 1804 1805 /* ARGSUSED */ 1806 dladm_status_t 1807 do_extract_priority(val_desc_t *vdp, void *arg, uint_t cnt) 1808 { 1809 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 1810 1811 bcopy((char *)vdp->vd_val, &mrp->mrp_priority, 1812 sizeof (mac_priority_level_t)); 1813 mrp->mrp_mask |= MRP_PRIORITY; 1814 1815 return (DLADM_STATUS_OK); 1816 } 1817 1818 /* ARGSUSED */ 1819 static dladm_status_t 1820 do_get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1821 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1822 uint_t flags, uint_t *perm_flags) 1823 { 1824 struct dlautopush dlap; 1825 int i, len; 1826 dladm_status_t status; 1827 dld_ioc_macprop_t *dip; 1828 1829 if (flags & MAC_PROP_DEFAULT) 1830 return (DLADM_STATUS_NOTDEFINED); 1831 1832 *val_cnt = 1; 1833 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1834 &status, perm_flags); 1835 if (dip == NULL) { 1836 (*prop_val)[0] = '\0'; 1837 return (DLADM_STATUS_OK); 1838 } 1839 (void) memcpy(&dlap, dip->pr_val, sizeof (dlap)); 1840 1841 for (i = 0, len = 0; i < dlap.dap_npush; i++) { 1842 if (i != 0) { 1843 (void) snprintf(*prop_val + len, 1844 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); 1845 len += 1; 1846 } 1847 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, 1848 "%s", dlap.dap_aplist[i]); 1849 len += strlen(dlap.dap_aplist[i]); 1850 if (dlap.dap_anchor - 1 == i) { 1851 (void) snprintf(*prop_val + len, 1852 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, 1853 AP_ANCHOR); 1854 len += (strlen(AP_ANCHOR) + 1); 1855 } 1856 } 1857 free(dip); 1858 done: 1859 return (DLADM_STATUS_OK); 1860 } 1861 1862 /* 1863 * Add the specified module to the dlautopush structure; returns a 1864 * DLADM_STATUS_* code. 1865 */ 1866 dladm_status_t 1867 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) 1868 { 1869 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) 1870 return (DLADM_STATUS_BADVAL); 1871 1872 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { 1873 /* 1874 * We don't allow multiple anchors, and the anchor must 1875 * be after at least one module. 1876 */ 1877 if (dlap->dap_anchor != 0) 1878 return (DLADM_STATUS_BADVAL); 1879 if (dlap->dap_npush == 0) 1880 return (DLADM_STATUS_BADVAL); 1881 1882 dlap->dap_anchor = dlap->dap_npush; 1883 return (DLADM_STATUS_OK); 1884 } 1885 if (dlap->dap_npush >= MAXAPUSH) 1886 return (DLADM_STATUS_BADVALCNT); 1887 1888 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, 1889 FMNAMESZ + 1); 1890 1891 return (DLADM_STATUS_OK); 1892 } 1893 1894 /* 1895 * Currently, both '.' and ' '(space) can be used as the delimiters between 1896 * autopush modules. The former is used in dladm set-linkprop, and the 1897 * latter is used in the autopush(1M) file. 1898 */ 1899 /* ARGSUSED */ 1900 static dladm_status_t 1901 do_check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1902 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1903 { 1904 char *module; 1905 struct dlautopush *dlap; 1906 dladm_status_t status; 1907 char val[DLADM_PROP_VAL_MAX]; 1908 char delimiters[4]; 1909 1910 if (val_cnt != 1) 1911 return (DLADM_STATUS_BADVALCNT); 1912 1913 if (prop_val != NULL) { 1914 dlap = malloc(sizeof (struct dlautopush)); 1915 if (dlap == NULL) 1916 return (DLADM_STATUS_NOMEM); 1917 1918 (void) memset(dlap, 0, sizeof (struct dlautopush)); 1919 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); 1920 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); 1921 module = strtok(val, delimiters); 1922 while (module != NULL) { 1923 status = i_dladm_add_ap_module(module, dlap); 1924 if (status != DLADM_STATUS_OK) 1925 return (status); 1926 module = strtok(NULL, delimiters); 1927 } 1928 1929 vdp->vd_val = (uintptr_t)dlap; 1930 } else { 1931 vdp->vd_val = 0; 1932 } 1933 return (DLADM_STATUS_OK); 1934 } 1935 1936 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET) 1937 1938 /* ARGSUSED */ 1939 static dladm_status_t 1940 do_get_rate_common(dladm_handle_t handle, prop_desc_t *pdp, 1941 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id, 1942 uint_t *perm_flags) 1943 { 1944 wl_rates_t *wrp; 1945 uint_t i; 1946 dladm_status_t status = DLADM_STATUS_OK; 1947 1948 wrp = malloc(WLDP_BUFSIZE); 1949 if (wrp == NULL) 1950 return (DLADM_STATUS_NOMEM); 1951 1952 status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE, 1953 B_FALSE); 1954 if (status != DLADM_STATUS_OK) 1955 goto done; 1956 1957 if (wrp->wl_rates_num > *val_cnt) { 1958 status = DLADM_STATUS_TOOSMALL; 1959 goto done; 1960 } 1961 1962 if (wrp->wl_rates_rates[0] == 0) { 1963 prop_val[0][0] = '\0'; 1964 *val_cnt = 1; 1965 goto done; 1966 } 1967 1968 for (i = 0; i < wrp->wl_rates_num; i++) { 1969 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 1970 wrp->wl_rates_rates[i] % 2, 1971 (float)wrp->wl_rates_rates[i] / 2); 1972 } 1973 *val_cnt = wrp->wl_rates_num; 1974 *perm_flags = MAC_PROP_PERM_RW; 1975 1976 done: 1977 free(wrp); 1978 return (status); 1979 } 1980 1981 static dladm_status_t 1982 do_get_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1983 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1984 uint_t flags, uint_t *perm_flags) 1985 { 1986 if (media != DL_WIFI) { 1987 return (i_dladm_speed_get(handle, pdp, linkid, prop_val, 1988 val_cnt, flags, perm_flags)); 1989 } 1990 1991 return (do_get_rate_common(handle, pdp, linkid, prop_val, val_cnt, 1992 MAC_PROP_WL_DESIRED_RATES, perm_flags)); 1993 } 1994 1995 /* ARGSUSED */ 1996 static dladm_status_t 1997 do_get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1998 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1999 uint_t flags, uint_t *perm_flags) 2000 { 2001 switch (media) { 2002 case DL_ETHER: 2003 /* 2004 * Speed for ethernet links is unbounded. E.g., 802.11b 2005 * links can have a speed of 5.5 Gbps. 2006 */ 2007 return (DLADM_STATUS_NOTSUP); 2008 2009 case DL_WIFI: 2010 return (do_get_rate_common(handle, pdp, linkid, prop_val, 2011 val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags)); 2012 default: 2013 return (DLADM_STATUS_BADARG); 2014 } 2015 } 2016 2017 static dladm_status_t 2018 do_set_rate(dladm_handle_t handle, datalink_id_t linkid, 2019 dladm_wlan_rates_t *rates) 2020 { 2021 int i; 2022 uint_t len; 2023 wl_rates_t *wrp; 2024 dladm_status_t status = DLADM_STATUS_OK; 2025 2026 wrp = malloc(WLDP_BUFSIZE); 2027 if (wrp == NULL) 2028 return (DLADM_STATUS_NOMEM); 2029 2030 bzero(wrp, WLDP_BUFSIZE); 2031 for (i = 0; i < rates->wr_cnt; i++) 2032 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 2033 wrp->wl_rates_num = rates->wr_cnt; 2034 2035 len = offsetof(wl_rates_t, wl_rates_rates) + 2036 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 2037 status = i_dladm_wlan_param(handle, linkid, wrp, 2038 MAC_PROP_WL_DESIRED_RATES, len, B_TRUE); 2039 2040 free(wrp); 2041 return (status); 2042 } 2043 2044 /* ARGSUSED */ 2045 static dladm_status_t 2046 do_set_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2047 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 2048 { 2049 dladm_wlan_rates_t rates; 2050 dladm_status_t status; 2051 2052 /* 2053 * can currently set rate on WIFI links only. 2054 */ 2055 if (media != DL_WIFI) 2056 return (DLADM_STATUS_PROPRDONLY); 2057 2058 if (val_cnt != 1) 2059 return (DLADM_STATUS_BADVALCNT); 2060 2061 rates.wr_cnt = 1; 2062 rates.wr_rates[0] = vdp[0].vd_val; 2063 2064 status = do_set_rate(handle, linkid, &rates); 2065 2066 done: 2067 return (status); 2068 } 2069 2070 /* ARGSUSED */ 2071 static dladm_status_t 2072 do_check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2073 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 2074 { 2075 int i; 2076 uint_t modval_cnt = MAX_SUPPORT_RATES; 2077 char *buf, **modval; 2078 dladm_status_t status; 2079 uint_t perm_flags; 2080 2081 if (val_cnt != 1) 2082 return (DLADM_STATUS_BADVALCNT); 2083 2084 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * 2085 MAX_SUPPORT_RATES); 2086 if (buf == NULL) { 2087 status = DLADM_STATUS_NOMEM; 2088 goto done; 2089 } 2090 2091 modval = (char **)(void *)buf; 2092 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 2093 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 2094 i * DLADM_STRSIZE; 2095 } 2096 2097 status = do_get_rate_mod(handle, NULL, linkid, modval, &modval_cnt, 2098 media, 0, &perm_flags); 2099 if (status != DLADM_STATUS_OK) 2100 goto done; 2101 2102 for (i = 0; i < modval_cnt; i++) { 2103 if (strcasecmp(*prop_val, modval[i]) == 0) { 2104 vdp->vd_val = (uintptr_t)(uint_t) 2105 (atof(*prop_val) * 2); 2106 status = DLADM_STATUS_OK; 2107 break; 2108 } 2109 } 2110 if (i == modval_cnt) 2111 status = DLADM_STATUS_BADVAL; 2112 done: 2113 free(buf); 2114 return (status); 2115 } 2116 2117 static dladm_status_t 2118 do_get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf, 2119 int buflen) 2120 { 2121 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG, 2122 buflen, B_FALSE)); 2123 } 2124 2125 /* ARGSUSED */ 2126 static dladm_status_t 2127 do_get_channel_prop(dladm_handle_t handle, prop_desc_t *pdp, 2128 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2129 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2130 { 2131 uint32_t channel; 2132 char buf[WLDP_BUFSIZE]; 2133 dladm_status_t status = DLADM_STATUS_OK; 2134 wl_phy_conf_t wl_phy_conf; 2135 2136 if ((status = do_get_phyconf(handle, linkid, buf, sizeof (buf))) 2137 != DLADM_STATUS_OK) 2138 goto done; 2139 2140 (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf)); 2141 if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) { 2142 status = DLADM_STATUS_NOTFOUND; 2143 goto done; 2144 } 2145 2146 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 2147 *val_cnt = 1; 2148 *perm_flags = MAC_PROP_PERM_READ; 2149 done: 2150 return (status); 2151 } 2152 2153 static dladm_status_t 2154 do_get_powermode(dladm_handle_t handle, datalink_id_t linkid, void *buf, 2155 int buflen) 2156 { 2157 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_POWER_MODE, 2158 buflen, B_FALSE)); 2159 } 2160 2161 /* ARGSUSED */ 2162 static dladm_status_t 2163 do_get_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp, 2164 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2165 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2166 { 2167 wl_ps_mode_t mode; 2168 const char *s; 2169 char buf[WLDP_BUFSIZE]; 2170 dladm_status_t status = DLADM_STATUS_OK; 2171 2172 if ((status = do_get_powermode(handle, linkid, buf, sizeof (buf))) 2173 != DLADM_STATUS_OK) 2174 goto done; 2175 2176 (void) memcpy(&mode, buf, sizeof (mode)); 2177 switch (mode.wl_ps_mode) { 2178 case WL_PM_AM: 2179 s = "off"; 2180 break; 2181 case WL_PM_MPS: 2182 s = "max"; 2183 break; 2184 case WL_PM_FAST: 2185 s = "fast"; 2186 break; 2187 default: 2188 status = DLADM_STATUS_NOTFOUND; 2189 goto done; 2190 } 2191 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 2192 *val_cnt = 1; 2193 *perm_flags = MAC_PROP_PERM_RW; 2194 done: 2195 return (status); 2196 } 2197 2198 static dladm_status_t 2199 do_set_powermode(dladm_handle_t handle, datalink_id_t linkid, 2200 dladm_wlan_powermode_t *pm) 2201 { 2202 wl_ps_mode_t ps_mode; 2203 2204 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 2205 2206 switch (*pm) { 2207 case DLADM_WLAN_PM_OFF: 2208 ps_mode.wl_ps_mode = WL_PM_AM; 2209 break; 2210 case DLADM_WLAN_PM_MAX: 2211 ps_mode.wl_ps_mode = WL_PM_MPS; 2212 break; 2213 case DLADM_WLAN_PM_FAST: 2214 ps_mode.wl_ps_mode = WL_PM_FAST; 2215 break; 2216 default: 2217 return (DLADM_STATUS_NOTSUP); 2218 } 2219 return (i_dladm_wlan_param(handle, linkid, &ps_mode, 2220 MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE)); 2221 } 2222 2223 /* ARGSUSED */ 2224 static dladm_status_t 2225 do_set_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp, 2226 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags, 2227 datalink_media_t media) 2228 { 2229 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 2230 dladm_status_t status; 2231 2232 if (val_cnt != 1) 2233 return (DLADM_STATUS_BADVALCNT); 2234 2235 status = do_set_powermode(handle, linkid, &powermode); 2236 2237 return (status); 2238 } 2239 2240 static dladm_status_t 2241 do_get_radio(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen) 2242 { 2243 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_RADIO, 2244 buflen, B_FALSE)); 2245 } 2246 2247 /* ARGSUSED */ 2248 static dladm_status_t 2249 do_get_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2250 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2251 uint_t flags, uint_t *perm_flags) 2252 { 2253 wl_radio_t radio; 2254 const char *s; 2255 char buf[WLDP_BUFSIZE]; 2256 dladm_status_t status = DLADM_STATUS_OK; 2257 2258 if ((status = do_get_radio(handle, linkid, buf, sizeof (buf))) 2259 != DLADM_STATUS_OK) 2260 goto done; 2261 2262 (void) memcpy(&radio, buf, sizeof (radio)); 2263 switch (radio) { 2264 case B_TRUE: 2265 s = "on"; 2266 break; 2267 case B_FALSE: 2268 s = "off"; 2269 break; 2270 default: 2271 status = DLADM_STATUS_NOTFOUND; 2272 goto done; 2273 } 2274 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 2275 *val_cnt = 1; 2276 *perm_flags = MAC_PROP_PERM_RW; 2277 done: 2278 return (status); 2279 } 2280 2281 static dladm_status_t 2282 do_set_radio(dladm_handle_t handle, datalink_id_t linkid, 2283 dladm_wlan_radio_t *radio) 2284 { 2285 wl_radio_t r; 2286 2287 switch (*radio) { 2288 case DLADM_WLAN_RADIO_ON: 2289 r = B_TRUE; 2290 break; 2291 case DLADM_WLAN_RADIO_OFF: 2292 r = B_FALSE; 2293 break; 2294 default: 2295 return (DLADM_STATUS_NOTSUP); 2296 } 2297 return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO, 2298 sizeof (r), B_TRUE)); 2299 } 2300 2301 /* ARGSUSED */ 2302 static dladm_status_t 2303 do_set_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2304 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 2305 { 2306 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 2307 dladm_status_t status; 2308 2309 if (val_cnt != 1) 2310 return (DLADM_STATUS_BADVALCNT); 2311 2312 status = do_set_radio(handle, linkid, &radio); 2313 2314 return (status); 2315 } 2316 2317 /* ARGSUSED */ 2318 static dladm_status_t 2319 do_check_hoplimit(dladm_handle_t handle, prop_desc_t *pdp, 2320 datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *vdp, 2321 datalink_media_t media) 2322 { 2323 int32_t hlim; 2324 char *ep; 2325 2326 if (val_cnt != 1) 2327 return (DLADM_STATUS_BADVALCNT); 2328 2329 errno = 0; 2330 hlim = strtol(*prop_val, &ep, 10); 2331 if (errno != 0 || ep == *prop_val || hlim < 1 || 2332 hlim > (int32_t)UINT8_MAX) 2333 return (DLADM_STATUS_BADVAL); 2334 vdp->vd_val = hlim; 2335 return (DLADM_STATUS_OK); 2336 } 2337 2338 /* ARGSUSED */ 2339 static dladm_status_t 2340 do_check_encaplim(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2341 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 2342 { 2343 int32_t elim; 2344 char *ep; 2345 2346 if (media != DL_IPV6) 2347 return (DLADM_STATUS_BADARG); 2348 2349 if (val_cnt != 1) 2350 return (DLADM_STATUS_BADVALCNT); 2351 2352 errno = 0; 2353 elim = strtol(*prop_val, &ep, 10); 2354 if (errno != 0 || ep == *prop_val || elim < 0 || 2355 elim > (int32_t)UINT8_MAX) 2356 return (DLADM_STATUS_BADVAL); 2357 vdp->vd_val = elim; 2358 return (DLADM_STATUS_OK); 2359 } 2360 2361 static dladm_status_t 2362 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid, 2363 const char *prop_name, char **prop_val, uint_t val_cnt) 2364 { 2365 char buf[MAXLINELEN]; 2366 int i; 2367 dladm_conf_t conf; 2368 dladm_status_t status; 2369 2370 status = dladm_read_conf(handle, linkid, &conf); 2371 if (status != DLADM_STATUS_OK) 2372 return (status); 2373 2374 /* 2375 * reset case. 2376 */ 2377 if (val_cnt == 0) { 2378 status = dladm_unset_conf_field(handle, conf, prop_name); 2379 if (status == DLADM_STATUS_OK) 2380 status = dladm_write_conf(handle, conf); 2381 goto done; 2382 } 2383 2384 buf[0] = '\0'; 2385 for (i = 0; i < val_cnt; i++) { 2386 (void) strlcat(buf, prop_val[i], MAXLINELEN); 2387 if (i != val_cnt - 1) 2388 (void) strlcat(buf, ",", MAXLINELEN); 2389 } 2390 2391 status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR, 2392 buf); 2393 if (status == DLADM_STATUS_OK) 2394 status = dladm_write_conf(handle, conf); 2395 2396 done: 2397 dladm_destroy_conf(handle, conf); 2398 return (status); 2399 } 2400 2401 static dladm_status_t 2402 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid, 2403 const char *prop_name, char **prop_val, uint_t *val_cntp) 2404 { 2405 char buf[MAXLINELEN], *str; 2406 uint_t cnt = 0; 2407 dladm_conf_t conf; 2408 dladm_status_t status; 2409 2410 status = dladm_read_conf(handle, linkid, &conf); 2411 if (status != DLADM_STATUS_OK) 2412 return (status); 2413 2414 status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN); 2415 if (status != DLADM_STATUS_OK) 2416 goto done; 2417 2418 str = strtok(buf, ","); 2419 while (str != NULL) { 2420 if (cnt == *val_cntp) { 2421 status = DLADM_STATUS_TOOSMALL; 2422 goto done; 2423 } 2424 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); 2425 str = strtok(NULL, ","); 2426 } 2427 2428 *val_cntp = cnt; 2429 2430 done: 2431 dladm_destroy_conf(handle, conf); 2432 return (status); 2433 } 2434 2435 /* 2436 * Walk persistent private link properties of a link. 2437 */ 2438 static dladm_status_t 2439 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid, 2440 void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *)) 2441 { 2442 dladm_status_t status; 2443 dladm_conf_t conf; 2444 char last_attr[MAXLINKATTRLEN]; 2445 char attr[MAXLINKATTRLEN]; 2446 char attrval[MAXLINKATTRVALLEN]; 2447 size_t attrsz; 2448 2449 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 2450 return (DLADM_STATUS_BADARG); 2451 2452 status = dladm_read_conf(handle, linkid, &conf); 2453 if (status != DLADM_STATUS_OK) 2454 return (status); 2455 2456 last_attr[0] = '\0'; 2457 while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr, 2458 attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) { 2459 if (attr[0] == '_') { 2460 if (func(handle, linkid, attr, arg) == 2461 DLADM_WALK_TERMINATE) 2462 break; 2463 } 2464 (void) strlcpy(last_attr, attr, MAXLINKATTRLEN); 2465 } 2466 2467 dladm_destroy_conf(handle, conf); 2468 return (DLADM_STATUS_OK); 2469 } 2470 2471 static link_attr_t * 2472 dladm_name2prop(const char *prop_name) 2473 { 2474 link_attr_t *p; 2475 2476 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 2477 if (strcmp(p->pp_name, prop_name) == 0) 2478 break; 2479 } 2480 return (p); 2481 } 2482 2483 static link_attr_t * 2484 dladm_id2prop(mac_prop_id_t propid) 2485 { 2486 link_attr_t *p; 2487 2488 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 2489 if (p->pp_id == propid) 2490 break; 2491 } 2492 return (p); 2493 } 2494 2495 static dld_ioc_macprop_t * 2496 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid, 2497 const char *prop_name, mac_prop_id_t propid, uint_t flags, 2498 dladm_status_t *status) 2499 { 2500 int dsize; 2501 dld_ioc_macprop_t *dip; 2502 2503 *status = DLADM_STATUS_OK; 2504 dsize = MAC_PROP_BUFSIZE(valsize); 2505 dip = malloc(dsize); 2506 if (dip == NULL) { 2507 *status = DLADM_STATUS_NOMEM; 2508 return (NULL); 2509 } 2510 bzero(dip, dsize); 2511 dip->pr_valsize = valsize; 2512 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name)); 2513 dip->pr_version = MAC_PROP_VERSION; 2514 dip->pr_linkid = linkid; 2515 dip->pr_num = propid; 2516 dip->pr_flags = flags; 2517 return (dip); 2518 } 2519 2520 static dld_ioc_macprop_t * 2521 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid, 2522 const char *prop_name, uint_t flags, dladm_status_t *status) 2523 { 2524 link_attr_t *p; 2525 2526 p = dladm_name2prop(prop_name); 2527 valsize = MAX(p->pp_valsize, valsize); 2528 return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id, 2529 flags, status)); 2530 } 2531 2532 static dld_ioc_macprop_t * 2533 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid, 2534 mac_prop_id_t propid, uint_t flags, dladm_status_t *status) 2535 { 2536 link_attr_t *p; 2537 2538 p = dladm_id2prop(propid); 2539 valsize = MAX(p->pp_valsize, valsize); 2540 return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid, 2541 flags, status)); 2542 } 2543 2544 /* ARGSUSED */ 2545 static dladm_status_t 2546 i_dladm_set_public_prop(dladm_handle_t handle, prop_desc_t *pdp, 2547 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags, 2548 datalink_media_t media) 2549 { 2550 dld_ioc_macprop_t *dip; 2551 dladm_status_t status = DLADM_STATUS_OK; 2552 uint8_t u8; 2553 uint16_t u16; 2554 uint32_t u32; 2555 void *val; 2556 2557 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status); 2558 if (dip == NULL) 2559 return (status); 2560 2561 if (pdp->pd_flags & PD_CHECK_ALLOC) 2562 val = (void *)vdp->vd_val; 2563 else { 2564 /* 2565 * Currently all 1/2/4-byte size properties are byte/word/int. 2566 * No need (yet) to distinguish these from arrays of same size. 2567 */ 2568 switch (dip->pr_valsize) { 2569 case 1: 2570 u8 = vdp->vd_val; 2571 val = &u8; 2572 break; 2573 case 2: 2574 u16 = vdp->vd_val; 2575 val = &u16; 2576 break; 2577 case 4: 2578 u32 = vdp->vd_val; 2579 val = &u32; 2580 break; 2581 default: 2582 val = &vdp->vd_val; 2583 break; 2584 } 2585 } 2586 2587 if (val != NULL) 2588 (void) memcpy(dip->pr_val, val, dip->pr_valsize); 2589 else 2590 dip->pr_valsize = 0; 2591 2592 status = i_dladm_macprop(handle, dip, B_TRUE); 2593 2594 done: 2595 free(dip); 2596 return (status); 2597 } 2598 2599 dladm_status_t 2600 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set) 2601 { 2602 dladm_status_t status = DLADM_STATUS_OK; 2603 2604 if (ioctl(dladm_dld_fd(handle), 2605 (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip)) 2606 status = dladm_errno2status(errno); 2607 2608 return (status); 2609 } 2610 2611 static dld_ioc_macprop_t * 2612 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid, 2613 char *prop_name, uint_t flags, dladm_status_t *status, uint_t *perm_flags) 2614 { 2615 dld_ioc_macprop_t *dip = NULL; 2616 2617 dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, status); 2618 if (dip == NULL) 2619 return (NULL); 2620 2621 *status = i_dladm_macprop(handle, dip, B_FALSE); 2622 if (*status != DLADM_STATUS_OK) { 2623 free(dip); 2624 return (NULL); 2625 } 2626 if (perm_flags != NULL) 2627 *perm_flags = dip->pr_perm_flags; 2628 2629 return (dip); 2630 } 2631 2632 /* ARGSUSED */ 2633 static dladm_status_t 2634 i_dladm_uint32_check(dladm_handle_t handle, prop_desc_t *pdp, 2635 datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *v, 2636 datalink_media_t media) 2637 { 2638 if (val_cnt != 1) 2639 return (DLADM_STATUS_BADVAL); 2640 v->vd_val = strtoul(prop_val[0], NULL, 0); 2641 return (DLADM_STATUS_OK); 2642 } 2643 2644 /* ARGSUSED */ 2645 static dladm_status_t 2646 i_dladm_duplex_get(dladm_handle_t handle, prop_desc_t *pdp, 2647 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2648 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2649 { 2650 link_duplex_t link_duplex; 2651 dladm_status_t status; 2652 2653 if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex", 2654 KSTAT_DATA_UINT32, &link_duplex)) != 0) 2655 return (status); 2656 2657 switch (link_duplex) { 2658 case LINK_DUPLEX_FULL: 2659 (void) strcpy(*prop_val, "full"); 2660 break; 2661 case LINK_DUPLEX_HALF: 2662 (void) strcpy(*prop_val, "half"); 2663 break; 2664 default: 2665 (void) strcpy(*prop_val, "unknown"); 2666 break; 2667 } 2668 *val_cnt = 1; 2669 return (DLADM_STATUS_OK); 2670 } 2671 2672 /* ARGSUSED */ 2673 static dladm_status_t 2674 i_dladm_speed_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2675 char **prop_val, uint_t *val_cnt, uint_t flags, uint_t *perm_flags) 2676 { 2677 uint64_t ifspeed = 0; 2678 dladm_status_t status; 2679 2680 if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed", 2681 KSTAT_DATA_UINT64, &ifspeed)) != 0) 2682 return (status); 2683 2684 if ((ifspeed % 1000000) != 0) { 2685 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 2686 "%llf", ifspeed / (float)1000000); /* Mbps */ 2687 } else { 2688 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 2689 "%llu", ifspeed / 1000000); /* Mbps */ 2690 } 2691 *val_cnt = 1; 2692 *perm_flags = MAC_PROP_PERM_READ; 2693 return (DLADM_STATUS_OK); 2694 } 2695 2696 /* ARGSUSED */ 2697 static dladm_status_t 2698 i_dladm_status_get(dladm_handle_t handle, prop_desc_t *pdp, 2699 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2700 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2701 { 2702 link_state_t link_state; 2703 dladm_status_t status; 2704 2705 status = i_dladm_get_state(handle, linkid, &link_state); 2706 if (status != DLADM_STATUS_OK) 2707 return (status); 2708 2709 switch (link_state) { 2710 case LINK_STATE_UP: 2711 (void) strcpy(*prop_val, "up"); 2712 break; 2713 case LINK_STATE_DOWN: 2714 (void) strcpy(*prop_val, "down"); 2715 break; 2716 default: 2717 (void) strcpy(*prop_val, "unknown"); 2718 break; 2719 } 2720 *val_cnt = 1; 2721 *perm_flags = MAC_PROP_PERM_READ; 2722 return (DLADM_STATUS_OK); 2723 } 2724 2725 /* ARGSUSED */ 2726 static dladm_status_t 2727 i_dladm_binary_get(dladm_handle_t handle, prop_desc_t *pdp, 2728 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2729 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2730 { 2731 dld_ioc_macprop_t *dip; 2732 dladm_status_t status; 2733 2734 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2735 &status, perm_flags); 2736 if (dip == NULL) 2737 return (status); 2738 2739 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]); 2740 free(dip); 2741 *val_cnt = 1; 2742 return (DLADM_STATUS_OK); 2743 } 2744 2745 /* ARGSUSED */ 2746 static dladm_status_t 2747 i_dladm_uint32_get(dladm_handle_t handle, prop_desc_t *pdp, 2748 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2749 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2750 { 2751 dld_ioc_macprop_t *dip; 2752 uint32_t v = 0; 2753 uchar_t *cp; 2754 dladm_status_t status; 2755 2756 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2757 &status, perm_flags); 2758 if (dip == NULL) 2759 return (status); 2760 2761 cp = (uchar_t *)dip->pr_val; 2762 (void) memcpy(&v, cp, sizeof (v)); 2763 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v); 2764 free(dip); 2765 *val_cnt = 1; 2766 return (DLADM_STATUS_OK); 2767 } 2768 2769 /* 2770 * Determines the size of the structure that needs to be sent to drivers 2771 * for retrieving the property range values. 2772 */ 2773 static int 2774 i_dladm_range_size(mac_propval_range_t *r, size_t *sz) 2775 { 2776 uint_t count = r->mpr_count; 2777 2778 *sz = sizeof (mac_propval_range_t); 2779 --count; 2780 2781 switch (r->mpr_type) { 2782 case MAC_PROPVAL_UINT32: 2783 *sz += (count * sizeof (mac_propval_uint32_range_t)); 2784 return (0); 2785 default: 2786 break; 2787 } 2788 *sz = 0; 2789 return (EINVAL); 2790 } 2791 2792 /* ARGSUSED */ 2793 static dladm_status_t 2794 i_dladm_range_get(dladm_handle_t handle, prop_desc_t *pdp, 2795 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2796 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2797 { 2798 dld_ioc_macprop_t *dip; 2799 dladm_status_t status = DLADM_STATUS_OK; 2800 size_t sz; 2801 mac_propval_range_t *rangep; 2802 2803 sz = sizeof (mac_propval_range_t); 2804 2805 /* 2806 * As caller we don't know number of value ranges, the driver 2807 * supports. To begin with we assume that number to be 1. If the 2808 * buffer size is insufficient, driver returns back with the 2809 * actual count of value ranges. See mac.h for more details. 2810 */ 2811 retry: 2812 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags, 2813 &status)) == NULL) 2814 return (status); 2815 2816 status = i_dladm_macprop(handle, dip, B_FALSE); 2817 if (status != DLADM_STATUS_OK) { 2818 if (status == DLADM_STATUS_TOOSMALL) { 2819 int err; 2820 2821 rangep = (mac_propval_range_t *)(void *)&dip->pr_val; 2822 if ((err = i_dladm_range_size(rangep, &sz)) == 0) { 2823 free(dip); 2824 goto retry; 2825 } else { 2826 status = dladm_errno2status(err); 2827 } 2828 } 2829 free(dip); 2830 return (status); 2831 } 2832 rangep = (mac_propval_range_t *)(void *)&dip->pr_val; 2833 2834 switch (rangep->mpr_type) { 2835 case MAC_PROPVAL_UINT32: { 2836 mac_propval_uint32_range_t *ur; 2837 uint_t count = rangep->mpr_count, i; 2838 2839 ur = &rangep->range_uint32[0]; 2840 2841 for (i = 0; i < count; i++, ur++) { 2842 if (ur->mpur_min == ur->mpur_max) { 2843 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX, 2844 "%ld", ur->mpur_min); 2845 } else { 2846 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX, 2847 "%ld-%ld", ur->mpur_min, ur->mpur_max); 2848 } 2849 } 2850 *val_cnt = count; 2851 break; 2852 } 2853 default: 2854 status = DLADM_STATUS_BADARG; 2855 break; 2856 } 2857 free(dip); 2858 return (status); 2859 } 2860 2861 /* ARGSUSED */ 2862 static dladm_status_t 2863 i_dladm_tagmode_get(dladm_handle_t handle, prop_desc_t *pdp, 2864 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2865 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2866 { 2867 dld_ioc_macprop_t *dip; 2868 link_tagmode_t mode; 2869 dladm_status_t status; 2870 2871 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2872 &status, perm_flags); 2873 if (dip == NULL) 2874 return (status); 2875 (void) memcpy(&mode, dip->pr_val, sizeof (mode)); 2876 free(dip); 2877 2878 switch (mode) { 2879 case LINK_TAGMODE_NORMAL: 2880 (void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX); 2881 break; 2882 case LINK_TAGMODE_VLANONLY: 2883 (void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX); 2884 break; 2885 default: 2886 (void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX); 2887 } 2888 *val_cnt = 1; 2889 return (DLADM_STATUS_OK); 2890 } 2891 2892 /* ARGSUSED */ 2893 static dladm_status_t 2894 i_dladm_flowctl_get(dladm_handle_t handle, prop_desc_t *pdp, 2895 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2896 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2897 { 2898 dld_ioc_macprop_t *dip; 2899 link_flowctrl_t v; 2900 dladm_status_t status; 2901 uchar_t *cp; 2902 2903 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2904 &status, perm_flags); 2905 if (dip == NULL) 2906 return (status); 2907 2908 cp = (uchar_t *)dip->pr_val; 2909 (void) memcpy(&v, cp, sizeof (v)); 2910 switch (v) { 2911 case LINK_FLOWCTRL_NONE: 2912 (void) sprintf(*prop_val, "no"); 2913 break; 2914 case LINK_FLOWCTRL_RX: 2915 (void) sprintf(*prop_val, "rx"); 2916 break; 2917 case LINK_FLOWCTRL_TX: 2918 (void) sprintf(*prop_val, "tx"); 2919 break; 2920 case LINK_FLOWCTRL_BI: 2921 (void) sprintf(*prop_val, "bi"); 2922 break; 2923 } 2924 free(dip); 2925 *val_cnt = 1; 2926 return (DLADM_STATUS_OK); 2927 } 2928 2929 2930 /* ARGSUSED */ 2931 static dladm_status_t 2932 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid, 2933 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags) 2934 2935 { 2936 int i, slen; 2937 int bufsize = 0; 2938 dld_ioc_macprop_t *dip = NULL; 2939 uchar_t *dp; 2940 link_attr_t *p; 2941 dladm_status_t status = DLADM_STATUS_OK; 2942 2943 if ((prop_name == NULL && prop_val != NULL) || 2944 (prop_val != NULL && val_cnt == 0)) 2945 return (DLADM_STATUS_BADARG); 2946 p = dladm_name2prop(prop_name); 2947 if (p->pp_id != MAC_PROP_PRIVATE) 2948 return (DLADM_STATUS_BADARG); 2949 2950 if (!(flags & DLADM_OPT_ACTIVE)) 2951 return (DLADM_STATUS_OK); 2952 2953 /* 2954 * private properties: all parsing is done in the kernel. 2955 * allocate a enough space for each property + its separator (','). 2956 */ 2957 for (i = 0; i < val_cnt; i++) { 2958 bufsize += strlen(prop_val[i]) + 1; 2959 } 2960 2961 if (prop_val == NULL) { 2962 /* 2963 * getting default value. so use more buffer space. 2964 */ 2965 bufsize += DLADM_PROP_BUF_CHUNK; 2966 } 2967 2968 dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name, 2969 (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status); 2970 if (dip == NULL) 2971 return (status); 2972 2973 dp = (uchar_t *)dip->pr_val; 2974 slen = 0; 2975 2976 if (prop_val == NULL) { 2977 status = i_dladm_macprop(handle, dip, B_FALSE); 2978 dip->pr_flags = 0; 2979 } else { 2980 for (i = 0; i < val_cnt; i++) { 2981 int plen = 0; 2982 2983 plen = strlen(prop_val[i]); 2984 bcopy(prop_val[i], dp, plen); 2985 slen += plen; 2986 /* 2987 * add a "," separator and update dp. 2988 */ 2989 if (i != (val_cnt -1)) 2990 dp[slen++] = ','; 2991 dp += (plen + 1); 2992 } 2993 } 2994 if (status == DLADM_STATUS_OK) 2995 status = i_dladm_macprop(handle, dip, B_TRUE); 2996 2997 free(dip); 2998 return (status); 2999 } 3000 3001 static dladm_status_t 3002 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid, 3003 const char *prop_name, char **prop_val, uint_t *val_cnt, 3004 dladm_prop_type_t type, uint_t dld_flags) 3005 { 3006 dladm_status_t status = DLADM_STATUS_OK; 3007 dld_ioc_macprop_t *dip = NULL; 3008 link_attr_t *p; 3009 3010 if ((prop_name == NULL && prop_val != NULL) || 3011 (prop_val != NULL && val_cnt == 0)) 3012 return (DLADM_STATUS_BADARG); 3013 3014 p = dladm_name2prop(prop_name); 3015 if (p->pp_id != MAC_PROP_PRIVATE) 3016 return (DLADM_STATUS_BADARG); 3017 3018 /* 3019 * private properties: all parsing is done in the kernel. 3020 */ 3021 dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name, 3022 dld_flags, &status); 3023 if (dip == NULL) 3024 return (status); 3025 3026 if ((status = i_dladm_macprop(handle, dip, B_FALSE)) == 3027 DLADM_STATUS_OK) { 3028 if (type == DLADM_PROP_VAL_PERM) { 3029 (void) dladm_perm2str(dip->pr_perm_flags, *prop_val); 3030 } else if (type == DLADM_PROP_VAL_MODIFIABLE) { 3031 *prop_val[0] = '\0'; 3032 } else { 3033 (void) strncpy(*prop_val, dip->pr_val, 3034 DLADM_PROP_VAL_MAX); 3035 } 3036 *val_cnt = 1; 3037 } else if ((status == DLADM_STATUS_NOTSUP) && 3038 (type == DLADM_PROP_VAL_CURRENT)) { 3039 status = DLADM_STATUS_NOTFOUND; 3040 } 3041 free(dip); 3042 return (status); 3043 } 3044 3045 3046 static dladm_status_t 3047 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp, 3048 datalink_id_t linkid, datalink_media_t media, uint_t flags) 3049 { 3050 dladm_status_t status; 3051 char **prop_vals = NULL, *buf; 3052 size_t bufsize; 3053 uint_t cnt; 3054 int i; 3055 uint_t perm_flags; 3056 3057 /* 3058 * Allocate buffer needed for prop_vals array. We can have at most 3059 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where 3060 * each entry has max size DLADM_PROP_VAL_MAX 3061 */ 3062 bufsize = 3063 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 3064 buf = malloc(bufsize); 3065 prop_vals = (char **)(void *)buf; 3066 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 3067 prop_vals[i] = buf + 3068 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 3069 i * DLADM_PROP_VAL_MAX; 3070 } 3071 3072 /* 3073 * For properties which have pdp->pd_defval.vd_name as a non-empty 3074 * string, the "" itself is used to reset the property (exceptions 3075 * are zone and autopush, which populate vdp->vd_val). So 3076 * libdladm can copy pdp->pd_defval over to the val_desc_t passed 3077 * down on the setprop using the global values in the table. For 3078 * other cases (vd_name is ""), doing reset-linkprop will cause 3079 * libdladm to do a getprop to find the default value and then do 3080 * a setprop to reset the value to default. 3081 */ 3082 status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media, 3083 MAC_PROP_DEFAULT, &perm_flags); 3084 if (status == DLADM_STATUS_OK) { 3085 if (perm_flags == MAC_PROP_PERM_RW) { 3086 status = i_dladm_set_single_prop(handle, linkid, 3087 pdp->pd_class, media, pdp, prop_vals, cnt, flags); 3088 } 3089 else 3090 status = DLADM_STATUS_NOTSUP; 3091 } 3092 free(buf); 3093 return (status); 3094 } 3095 3096 /* ARGSUSED */ 3097 static dladm_status_t 3098 get_stp_prop(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid, 3099 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags, 3100 uint_t *perm_flags) 3101 { 3102 const bridge_public_prop_t *bpp; 3103 dladm_status_t retv; 3104 int val, i; 3105 3106 if (flags != 0) 3107 return (DLADM_STATUS_NOTSUP); 3108 *perm_flags = MAC_PROP_PERM_RW; 3109 *val_cnt = 1; 3110 for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++) 3111 if (strcmp(bpp->bpp_name, pd->pd_name) == 0) 3112 break; 3113 retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val); 3114 /* If the daemon isn't running, then return the persistent value */ 3115 if (retv == DLADM_STATUS_NOTFOUND) { 3116 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name, 3117 prop_val, val_cnt) != DLADM_STATUS_OK) 3118 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 3119 DLADM_PROP_VAL_MAX); 3120 return (DLADM_STATUS_OK); 3121 } 3122 if (retv != DLADM_STATUS_OK) { 3123 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 3124 return (retv); 3125 } 3126 if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') { 3127 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 3128 DLADM_PROP_VAL_MAX); 3129 return (DLADM_STATUS_OK); 3130 } 3131 for (i = 0; i < pd->pd_noptval; i++) { 3132 if (val == pd->pd_optval[i].vd_val) { 3133 (void) strlcpy(*prop_val, pd->pd_optval[i].vd_name, 3134 DLADM_PROP_VAL_MAX); 3135 return (DLADM_STATUS_OK); 3136 } 3137 } 3138 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val); 3139 return (DLADM_STATUS_OK); 3140 } 3141 3142 /* ARGSUSED1 */ 3143 static dladm_status_t 3144 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, 3145 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 3146 { 3147 /* 3148 * Special case for mcheck: the daemon resets the value to zero, and we 3149 * don't want the daemon to refresh itself; it leads to deadlock. 3150 */ 3151 if (flags & DLADM_OPT_NOREFRESH) 3152 return (DLADM_STATUS_OK); 3153 3154 /* Tell the running daemon, if any */ 3155 return (dladm_bridge_refresh(handle, linkid)); 3156 } 3157 3158 /* 3159 * This is used only for stp_priority, stp_cost, and stp_mcheck. 3160 */ 3161 /* ARGSUSED */ 3162 static dladm_status_t 3163 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd, 3164 datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *vdp, 3165 datalink_media_t media) 3166 { 3167 char *cp; 3168 boolean_t iscost; 3169 3170 if (val_cnt != 1) 3171 return (DLADM_STATUS_BADVALCNT); 3172 3173 if (prop_val == NULL) { 3174 vdp->vd_val = 0; 3175 } else { 3176 /* Only stp_priority and stp_cost use this function */ 3177 iscost = strcmp(pd->pd_name, "stp_cost") == 0; 3178 3179 if (iscost && strcmp(prop_val[0], "auto") == 0) { 3180 /* Illegal value 0 is allowed to mean "automatic" */ 3181 vdp->vd_val = 0; 3182 } else { 3183 errno = 0; 3184 vdp->vd_val = strtoul(prop_val[0], &cp, 0); 3185 if (errno != 0 || *cp != '\0') 3186 return (DLADM_STATUS_BADVAL); 3187 } 3188 } 3189 3190 if (iscost) { 3191 return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL : 3192 DLADM_STATUS_OK); 3193 } else { 3194 if (vdp->vd_val > 255) 3195 return (DLADM_STATUS_BADVAL); 3196 /* 3197 * If the user is setting stp_mcheck non-zero, then (per the 3198 * IEEE management standards and UNH testing) we need to check 3199 * whether this link is part of a bridge that is running RSTP. 3200 * If it's not, then setting the flag is an error. Note that 3201 * errors are intentionally discarded here; it's the value 3202 * that's the problem -- it's not a bad value, merely one that 3203 * can't be used now. 3204 */ 3205 if (strcmp(pd->pd_name, "stp_mcheck") == 0 && 3206 vdp->vd_val != 0) { 3207 char bridge[MAXLINKNAMELEN]; 3208 UID_STP_CFG_T cfg; 3209 dladm_bridge_prot_t brprot; 3210 3211 if (dladm_bridge_getlink(handle, linkid, bridge, 3212 sizeof (bridge)) != DLADM_STATUS_OK || 3213 dladm_bridge_get_properties(bridge, &cfg, 3214 &brprot) != DLADM_STATUS_OK) 3215 return (DLADM_STATUS_FAILED); 3216 if (cfg.force_version <= 1) 3217 return (DLADM_STATUS_FAILED); 3218 } 3219 return (DLADM_STATUS_OK); 3220 } 3221 } 3222 3223 /* ARGSUSED */ 3224 static dladm_status_t 3225 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd, 3226 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3227 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3228 { 3229 dladm_status_t retv; 3230 uint_t val; 3231 3232 if (flags != 0) 3233 return (DLADM_STATUS_NOTSUP); 3234 *perm_flags = MAC_PROP_PERM_RW; 3235 *val_cnt = 1; 3236 retv = dladm_bridge_get_forwarding(handle, linkid, &val); 3237 if (retv == DLADM_STATUS_NOTFOUND) { 3238 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name, 3239 prop_val, val_cnt) != DLADM_STATUS_OK) 3240 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 3241 DLADM_PROP_VAL_MAX); 3242 return (DLADM_STATUS_OK); 3243 } 3244 if (retv == DLADM_STATUS_OK) 3245 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val); 3246 else 3247 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 3248 return (retv); 3249 } 3250 3251 /* ARGSUSED */ 3252 static dladm_status_t 3253 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, 3254 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 3255 { 3256 /* Tell the running daemon, if any */ 3257 return (dladm_bridge_refresh(handle, linkid)); 3258 } 3259 3260 /* ARGSUSED */ 3261 static dladm_status_t 3262 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd, 3263 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3264 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3265 { 3266 dladm_status_t status; 3267 dld_ioc_macprop_t *dip; 3268 uint16_t pvid; 3269 3270 if (flags != 0) 3271 return (DLADM_STATUS_NOTSUP); 3272 *perm_flags = MAC_PROP_PERM_RW; 3273 *val_cnt = 1; 3274 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID, 3275 0, &status); 3276 if (dip == NULL) 3277 return (status); 3278 status = i_dladm_macprop(handle, dip, B_FALSE); 3279 if (status == DLADM_STATUS_OK) { 3280 (void) memcpy(&pvid, dip->pr_val, sizeof (pvid)); 3281 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid); 3282 } else { 3283 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 3284 } 3285 free(dip); 3286 return (status); 3287 } 3288 3289 /* ARGSUSED */ 3290 static dladm_status_t 3291 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, 3292 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 3293 { 3294 dladm_status_t status; 3295 dld_ioc_macprop_t *dip; 3296 uint16_t pvid; 3297 3298 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID, 3299 0, &status); 3300 if (dip == NULL) 3301 return (status); 3302 pvid = vdp->vd_val; 3303 (void) memcpy(dip->pr_val, &pvid, sizeof (pvid)); 3304 status = i_dladm_macprop(handle, dip, B_TRUE); 3305 free(dip); 3306 if (status != DLADM_STATUS_OK) 3307 return (status); 3308 3309 /* Tell the running daemon, if any */ 3310 return (dladm_bridge_refresh(handle, linkid)); 3311 } 3312 3313 /* ARGSUSED */ 3314 static dladm_status_t 3315 check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd, 3316 datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *vdp, 3317 datalink_media_t media) 3318 { 3319 char *cp; 3320 3321 if (val_cnt != 1) 3322 return (DLADM_STATUS_BADVALCNT); 3323 3324 if (prop_val == NULL) { 3325 vdp->vd_val = 1; 3326 } else { 3327 errno = 0; 3328 vdp->vd_val = strtoul(prop_val[0], &cp, 0); 3329 if (errno != 0 || *cp != '\0') 3330 return (DLADM_STATUS_BADVAL); 3331 } 3332 3333 return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL : 3334 DLADM_STATUS_OK); 3335 } 3336 3337 dladm_status_t 3338 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf, 3339 mac_prop_id_t cmd, size_t len, boolean_t set) 3340 { 3341 uint32_t flags; 3342 dladm_status_t status; 3343 uint32_t media; 3344 dld_ioc_macprop_t *dip; 3345 void *dp; 3346 3347 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 3348 &media, NULL, 0)) != DLADM_STATUS_OK) { 3349 return (status); 3350 } 3351 3352 if (media != DL_WIFI) 3353 return (DLADM_STATUS_BADARG); 3354 3355 if (!(flags & DLADM_OPT_ACTIVE)) 3356 return (DLADM_STATUS_TEMPONLY); 3357 3358 if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET)) 3359 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1; 3360 3361 dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status); 3362 if (dip == NULL) 3363 return (DLADM_STATUS_NOMEM); 3364 3365 dp = (uchar_t *)dip->pr_val; 3366 if (set) 3367 (void) memcpy(dp, buf, len); 3368 3369 status = i_dladm_macprop(handle, dip, set); 3370 if (status == DLADM_STATUS_OK) { 3371 if (!set) 3372 (void) memcpy(buf, dp, len); 3373 } 3374 3375 free(dip); 3376 return (status); 3377 } 3378 3379 dladm_status_t 3380 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues) 3381 { 3382 return (dladm_parse_args(str, listp, novalues)); 3383 } 3384 3385 /* 3386 * Retrieve the one link property from the database 3387 */ 3388 /*ARGSUSED*/ 3389 static int 3390 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid, 3391 const char *prop_name, void *arg) 3392 { 3393 dladm_arg_list_t *proplist = arg; 3394 dladm_arg_info_t *aip = NULL; 3395 3396 aip = &proplist->al_info[proplist->al_count]; 3397 /* 3398 * it is fine to point to prop_name since prop_name points to the 3399 * prop_table[n].pd_name. 3400 */ 3401 aip->ai_name = prop_name; 3402 3403 (void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT, 3404 prop_name, aip->ai_val, &aip->ai_count); 3405 3406 if (aip->ai_count != 0) 3407 proplist->al_count++; 3408 3409 return (DLADM_WALK_CONTINUE); 3410 } 3411 3412 3413 /* 3414 * Retrieve all link properties for a link from the database and 3415 * return a property list. 3416 */ 3417 dladm_status_t 3418 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid, 3419 dladm_arg_list_t **listp) 3420 { 3421 dladm_arg_list_t *list; 3422 dladm_status_t status = DLADM_STATUS_OK; 3423 3424 list = calloc(1, sizeof (dladm_arg_list_t)); 3425 if (list == NULL) 3426 return (dladm_errno2status(errno)); 3427 3428 status = dladm_walk_linkprop(handle, linkid, list, 3429 i_dladm_get_one_prop); 3430 3431 *listp = list; 3432 return (status); 3433 } 3434 3435 /* 3436 * Retrieve the named property from a proplist, check the value and 3437 * convert to a kernel structure. 3438 */ 3439 static dladm_status_t 3440 i_dladm_link_proplist_extract_one(dladm_handle_t handle, 3441 dladm_arg_list_t *proplist, const char *name, void *val) 3442 { 3443 dladm_status_t status; 3444 dladm_arg_info_t *aip = NULL; 3445 int i, j; 3446 3447 /* Find named property in proplist */ 3448 for (i = 0; i < proplist->al_count; i++) { 3449 aip = &proplist->al_info[i]; 3450 if (strcasecmp(aip->ai_name, name) == 0) 3451 break; 3452 } 3453 3454 /* Property not in list */ 3455 if (i == proplist->al_count) 3456 return (DLADM_STATUS_OK); 3457 3458 for (i = 0; i < DLADM_MAX_PROPS; i++) { 3459 prop_desc_t *pdp = &prop_table[i]; 3460 val_desc_t *vdp; 3461 3462 vdp = malloc(sizeof (val_desc_t) * aip->ai_count); 3463 if (vdp == NULL) 3464 return (DLADM_STATUS_NOMEM); 3465 3466 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0) 3467 continue; 3468 3469 if (aip->ai_val == NULL) 3470 return (DLADM_STATUS_BADARG); 3471 3472 /* Check property value */ 3473 if (pdp->pd_check != NULL) { 3474 status = pdp->pd_check(handle, pdp, 0, aip->ai_val, 3475 aip->ai_count, vdp, 0); 3476 } else { 3477 status = DLADM_STATUS_BADARG; 3478 } 3479 3480 if (status != DLADM_STATUS_OK) 3481 return (status); 3482 3483 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) { 3484 resource_prop_t *rpp = &rsrc_prop_table[j]; 3485 3486 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0) 3487 continue; 3488 3489 /* Extract kernel structure */ 3490 if (rpp->rp_extract != NULL) { 3491 status = rpp->rp_extract(vdp, val, 3492 aip->ai_count); 3493 } else { 3494 status = DLADM_STATUS_BADARG; 3495 } 3496 break; 3497 } 3498 3499 if (status != DLADM_STATUS_OK) 3500 return (status); 3501 3502 break; 3503 } 3504 return (status); 3505 } 3506 3507 /* 3508 * Extract properties from a proplist and convert to mac_resource_props_t. 3509 */ 3510 dladm_status_t 3511 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist, 3512 mac_resource_props_t *mrp) 3513 { 3514 dladm_status_t status = DLADM_STATUS_OK; 3515 3516 status = i_dladm_link_proplist_extract_one(handle, proplist, "maxbw", 3517 mrp); 3518 if (status != DLADM_STATUS_OK) 3519 return (status); 3520 status = i_dladm_link_proplist_extract_one(handle, proplist, "priority", 3521 mrp); 3522 if (status != DLADM_STATUS_OK) 3523 return (status); 3524 status = i_dladm_link_proplist_extract_one(handle, proplist, "cpus", 3525 mrp); 3526 if (status != DLADM_STATUS_OK) 3527 return (status); 3528 return (status); 3529 } 3530 3531 static const char * 3532 dladm_perm2str(uint_t perm, char *buf) 3533 { 3534 (void) snprintf(buf, DLADM_STRSIZE, "%c%c", 3535 ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-', 3536 ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-'); 3537 return (buf); 3538 } 3539 3540 dladm_status_t 3541 i_dladm_get_state(dladm_handle_t handle, datalink_id_t linkid, 3542 link_state_t *state) 3543 { 3544 dld_ioc_macprop_t *dip; 3545 dladm_status_t status; 3546 uint_t perms; 3547 3548 dip = i_dladm_get_public_prop(handle, linkid, "state", 0, &status, 3549 &perms); 3550 if (status != DLADM_STATUS_OK) 3551 return (status); 3552 (void) memcpy(state, dip->pr_val, sizeof (*state)); 3553 free(dip); 3554 return (status); 3555 } 3556 3557 boolean_t 3558 dladm_attr_is_linkprop(const char *name) 3559 { 3560 /* non-property attribute names */ 3561 const char *nonprop[] = { 3562 /* dlmgmtd core attributes */ 3563 "name", 3564 "class", 3565 "media", 3566 FPHYMAJ, 3567 FPHYINST, 3568 FDEVNAME, 3569 3570 /* other attributes for vlan, aggr, etc */ 3571 DLADM_ATTR_NAMES 3572 }; 3573 boolean_t is_nonprop = B_FALSE; 3574 int i; 3575 3576 for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) { 3577 if (strcmp(name, nonprop[i]) == 0) { 3578 is_nonprop = B_TRUE; 3579 break; 3580 } 3581 } 3582 3583 return (!is_nonprop); 3584 } 3585