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