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 2008 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 <dlfcn.h> 45 #include <link.h> 46 #include <inet/wifi_ioctl.h> 47 #include <libdladm.h> 48 #include <sys/param.h> 49 #include <inttypes.h> 50 #include <sys/ethernet.h> 51 52 /* 53 * The linkprop get() callback. 54 * - pd: pointer to the struct prop_desc 55 * - propstrp: a property string array to keep the returned property. 56 * Caller allocated. 57 * - cntp: number of returned properties. 58 * Caller also uses it to indicate how many it expects. 59 */ 60 struct prop_desc; 61 62 typedef dladm_status_t pd_getf_t(struct prop_desc *pd, 63 datalink_id_t, char **propstp, uint_t *cntp, 64 datalink_media_t, uint_t); 65 66 /* 67 * The linkprop set() callback. 68 * - propval: a val_desc_t array which keeps the property values to be set. 69 * - cnt: number of properties to be set. 70 * - flags: additional flags passed down the system call. 71 * 72 * pd_set takes val_desc_t given by pd_check(), translates it into 73 * a format suitable for kernel consumption. This may require allocation 74 * of ioctl buffers etc. pd_set() may call another common routine (used 75 * by all other pd_sets) which invokes the ioctl. 76 */ 77 typedef dladm_status_t pd_setf_t(struct prop_desc *, datalink_id_t, 78 val_desc_t *propval, uint_t cnt, uint_t flags, 79 datalink_media_t); 80 81 82 /* 83 * The linkprop check() callback. 84 * - propstrp: property string array which keeps the property to be checked. 85 * - cnt: number of properties. 86 * - propval: return value; the property values of the given property strings. 87 * 88 * pd_check checks that the input values are valid. It does so by 89 * iteraring through the pd_modval list for the property. If 90 * the modifiable values cannot be expressed as a list, a pd_check 91 * specific to this property can be used. If the input values are 92 * verified to be valid, pd_check allocates a val_desc_t and fills it 93 * with either a val_desc_t found on the pd_modval list or something 94 * generated on the fly. 95 */ 96 typedef dladm_status_t pd_checkf_t(struct prop_desc *pd, 97 datalink_id_t, char **propstrp, 98 uint_t cnt, val_desc_t *propval, 99 datalink_media_t); 100 101 typedef struct dladm_public_prop_s { 102 mac_prop_id_t pp_id; 103 size_t pp_valsize; 104 char *pp_name; 105 char *pp_desc; 106 } dladm_public_prop_t; 107 108 static dld_ioc_macprop_t *i_dladm_buf_alloc(size_t, datalink_id_t, const char *, 109 uint_t, dladm_status_t *); 110 static dladm_status_t i_dladm_set_prop(datalink_id_t, const char *, char **, 111 uint_t, uint_t); 112 static dladm_status_t i_dladm_get_prop(datalink_id_t, const char *, char **, 113 uint_t *, dladm_prop_type_t, uint_t); 114 static dladm_public_prop_t *dladm_name2prop(const char *); 115 static dld_ioc_macprop_t *i_dladm_get_public_prop(datalink_id_t, char *, uint_t, 116 dladm_status_t *); 117 static pd_getf_t do_get_zone, do_get_autopush, do_get_rate_mod, 118 do_get_rate_prop, do_get_channel_prop, 119 do_get_powermode_prop, do_get_radio_prop, 120 i_dladm_duplex_get, i_dladm_status_get, 121 i_dladm_binary_get, i_dladm_uint32_get, 122 i_dladm_flowctl_get; 123 static pd_setf_t do_set_zone, do_set_rate_prop, 124 do_set_powermode_prop, do_set_radio_prop, 125 i_dladm_set_public_prop; 126 static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate, 127 i_dladm_defmtu_check; 128 129 static dladm_status_t i_dladm_speed_get(struct prop_desc *, datalink_id_t, 130 char **, uint_t *, uint_t); 131 132 typedef struct prop_desc { 133 /* 134 * link property name 135 */ 136 char *pd_name; 137 138 /* 139 * default property value, can be set to { "", NULL } 140 */ 141 val_desc_t pd_defval; 142 143 /* 144 * list of optional property values, can be NULL. 145 * 146 * This is set to non-NULL if there is a list of possible property 147 * values. pd_optval would point to the array of possible values. 148 */ 149 val_desc_t *pd_optval; 150 151 /* 152 * count of the above optional property values. 0 if pd_optval is NULL. 153 */ 154 uint_t pd_noptval; 155 156 /* 157 * callback to set link property; 158 * set to NULL if this property is read-only 159 */ 160 pd_setf_t *pd_set; 161 162 /* 163 * callback to get modifiable link property 164 */ 165 pd_getf_t *pd_getmod; 166 167 /* 168 * callback to get current link property 169 */ 170 pd_getf_t *pd_get; 171 172 /* 173 * callback to validate link property value, set to NULL if pd_optval 174 * is not NULL. In that case, validate the value by comparing it with 175 * the pd_optval. Return a val_desc_t array pointer if the value is 176 * valid. 177 */ 178 pd_checkf_t *pd_check; 179 180 uint_t pd_flags; 181 #define PD_TEMPONLY 0x1 /* property is temporary only */ 182 #define PD_CHECK_ALLOC 0x2 /* alloc vd_val as part of pd_check */ 183 /* 184 * indicate link classes this property applies to. 185 */ 186 datalink_class_t pd_class; 187 188 /* 189 * indicate link media type this property applies to. 190 */ 191 datalink_media_t pd_dmedia; 192 } prop_desc_t; 193 194 #define MAC_PROP_BUFSIZE(v) sizeof (dld_ioc_macprop_t) + (v) - 1 195 196 197 static dladm_public_prop_t dladm_prop[] = { 198 { MAC_PROP_DUPLEX, sizeof (link_duplex_t), 199 "duplex", "link duplex mode" }, 200 201 { MAC_PROP_SPEED, sizeof (uint64_t), 202 "speed", "link speed (bps)" }, 203 204 { MAC_PROP_STATUS, sizeof (link_state_t), 205 "state", "link up/down" }, 206 207 { MAC_PROP_AUTONEG, sizeof (uint8_t), 208 "adv_autoneg_cap", "Advertised auto-negotiation" }, 209 210 { MAC_PROP_MTU, sizeof (uint32_t), 211 "mtu", "current link mtu" }, 212 213 { MAC_PROP_FLOWCTRL, sizeof (link_flowctrl_t), 214 "flowctrl", "flowcontrol" }, 215 216 { MAC_PROP_ZONE, sizeof (dld_ioc_zid_t), 217 "zone", "non-global zones" }, 218 219 { MAC_PROP_AUTOPUSH, sizeof (struct dlautopush), 220 "autopush", "autopush modules" }, 221 222 { MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t), 223 "adv_1000fdx_cap", "Adv 1000 Mbps fdx" }, 224 225 { MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t), 226 "en_1000fdx_cap", "Enable 1000 Mbps fdx" }, 227 228 { MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t), 229 "adv_1000hdx_cap", "Adv 1000 Mbps hdx" }, 230 231 { MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t), 232 "en_1000hdx_cap", "Enable 1000 Mbps hdx" }, 233 234 { MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t), 235 "adv_100fdx_cap", "Adv 100 Mbps fdx" }, 236 237 { MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t), 238 "en_100fdx_cap", "Enable 100 Mbps fdx" }, 239 240 { MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t), 241 "adv_100hdx_cap", "Adv 100 Mbps hdx" }, 242 243 { MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t), 244 "en_100hdx_cap", "Enable 100 Mbps hdx" }, 245 246 { MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t), 247 "adv_10fdx_cap", "Adv 10 Mbps fdx" }, 248 249 { MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t), 250 "en_10fdx_cap", "Enable 10 Mbps fdx" }, 251 252 { MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t), 253 "adv_10hdx_cap", "Adv 10 Mbps hdx" }, 254 255 { MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t), 256 "en_10hdx_cap", "Enable 10 Mbps hdx" }, 257 258 { MAC_PROP_PRIVATE, 0, 259 "driver-private", "" } 260 }; 261 262 static val_desc_t link_duplex_vals[] = { 263 { "half", LINK_DUPLEX_HALF }, 264 { "full", LINK_DUPLEX_HALF } 265 }; 266 static val_desc_t link_status_vals[] = { 267 { "up", LINK_STATE_UP }, 268 { "down", LINK_STATE_DOWN } 269 }; 270 static val_desc_t link_01_vals[] = { 271 { "1", 1 }, 272 { "0", 0 } 273 }; 274 static val_desc_t link_flow_vals[] = { 275 { "no", LINK_FLOWCTRL_NONE }, 276 { "tx", LINK_FLOWCTRL_TX }, 277 { "rx", LINK_FLOWCTRL_RX }, 278 { "bi", LINK_FLOWCTRL_BI } 279 }; 280 281 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) 282 283 static val_desc_t dladm_wlan_radio_vals[] = { 284 { "on", DLADM_WLAN_RADIO_ON }, 285 { "off", DLADM_WLAN_RADIO_OFF } 286 }; 287 288 static val_desc_t dladm_wlan_powermode_vals[] = { 289 { "off", DLADM_WLAN_PM_OFF }, 290 { "fast", DLADM_WLAN_PM_FAST }, 291 { "max", DLADM_WLAN_PM_MAX } 292 }; 293 294 static prop_desc_t prop_table[] = { 295 296 { "channel", { NULL, 0 }, 297 NULL, 0, NULL, NULL, 298 do_get_channel_prop, NULL, 0, 299 DATALINK_CLASS_PHYS, DL_WIFI }, 300 301 { "powermode", { "off", DLADM_WLAN_PM_OFF }, 302 dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals), 303 do_set_powermode_prop, NULL, 304 do_get_powermode_prop, NULL, 0, 305 DATALINK_CLASS_PHYS, DL_WIFI }, 306 307 { "radio", { "on", DLADM_WLAN_RADIO_ON }, 308 dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals), 309 do_set_radio_prop, NULL, 310 do_get_radio_prop, NULL, 0, 311 DATALINK_CLASS_PHYS, DL_WIFI }, 312 313 { "speed", { "", 0 }, NULL, 0, 314 do_set_rate_prop, do_get_rate_mod, 315 do_get_rate_prop, do_check_rate, 0, 316 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE }, 317 318 { "autopush", { "", 0 }, NULL, 0, 319 i_dladm_set_public_prop, NULL, 320 do_get_autopush, do_check_autopush, PD_CHECK_ALLOC, 321 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 322 323 { "zone", { "", 0 }, NULL, 0, 324 do_set_zone, NULL, 325 do_get_zone, do_check_zone, PD_TEMPONLY|PD_CHECK_ALLOC, 326 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 327 328 { "duplex", { "", 0 }, 329 link_duplex_vals, VALCNT(link_duplex_vals), 330 NULL, NULL, i_dladm_duplex_get, NULL, 331 0, DATALINK_CLASS_PHYS, DL_ETHER }, 332 333 { "state", { "up", LINK_STATE_UP }, 334 link_status_vals, VALCNT(link_status_vals), 335 NULL, NULL, i_dladm_status_get, NULL, 336 0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 337 338 { "adv_autoneg_cap", { "1", 1 }, 339 link_01_vals, VALCNT(link_01_vals), 340 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 341 0, DATALINK_CLASS_PHYS, DL_ETHER }, 342 343 { "mtu", { "", 0 }, NULL, 0, 344 i_dladm_set_public_prop, NULL, i_dladm_uint32_get, 345 i_dladm_defmtu_check, 0, DATALINK_CLASS_ALL, 346 DATALINK_ANY_MEDIATYPE }, 347 348 { "flowctrl", { "", 0 }, 349 link_flow_vals, VALCNT(link_flow_vals), 350 i_dladm_set_public_prop, NULL, i_dladm_flowctl_get, NULL, 351 0, DATALINK_CLASS_PHYS, DL_ETHER }, 352 353 { "adv_1000fdx_cap", { "", 0 }, 354 link_01_vals, VALCNT(link_01_vals), 355 NULL, NULL, i_dladm_binary_get, NULL, 356 0, DATALINK_CLASS_PHYS, DL_ETHER }, 357 358 { "en_1000fdx_cap", { "", 0 }, 359 link_01_vals, VALCNT(link_01_vals), 360 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 361 0, DATALINK_CLASS_PHYS, DL_ETHER }, 362 363 { "adv_1000hdx_cap", { "", 0 }, 364 link_01_vals, VALCNT(link_01_vals), 365 NULL, NULL, i_dladm_binary_get, NULL, 366 0, DATALINK_CLASS_PHYS, DL_ETHER }, 367 368 { "en_1000hdx_cap", { "", 0 }, 369 link_01_vals, VALCNT(link_01_vals), 370 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 371 0, DATALINK_CLASS_PHYS, DL_ETHER }, 372 373 { "adv_100fdx_cap", { "", 0 }, 374 link_01_vals, VALCNT(link_01_vals), 375 NULL, NULL, i_dladm_binary_get, NULL, 376 0, DATALINK_CLASS_PHYS, DL_ETHER }, 377 378 { "en_100fdx_cap", { "", 0 }, 379 link_01_vals, VALCNT(link_01_vals), 380 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 381 0, DATALINK_CLASS_PHYS, DL_ETHER }, 382 383 { "adv_100hdx_cap", { "", 0 }, 384 link_01_vals, VALCNT(link_01_vals), 385 NULL, NULL, i_dladm_binary_get, NULL, 386 0, DATALINK_CLASS_PHYS, DL_ETHER }, 387 388 { "en_100hdx_cap", { "", 0 }, 389 link_01_vals, VALCNT(link_01_vals), 390 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 391 0, DATALINK_CLASS_PHYS, DL_ETHER }, 392 393 { "adv_10fdx_cap", { "", 0 }, 394 link_01_vals, VALCNT(link_01_vals), 395 NULL, NULL, i_dladm_binary_get, NULL, 396 0, DATALINK_CLASS_PHYS, DL_ETHER }, 397 398 { "en_10fdx_cap", { "", 0 }, 399 link_01_vals, VALCNT(link_01_vals), 400 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 401 0, DATALINK_CLASS_PHYS, DL_ETHER }, 402 403 { "adv_10hdx_cap", { "", 0 }, 404 link_01_vals, VALCNT(link_01_vals), 405 NULL, NULL, i_dladm_binary_get, NULL, 406 0, DATALINK_CLASS_PHYS, DL_ETHER }, 407 408 { "en_10hdx_cap", { "", 0 }, 409 link_01_vals, VALCNT(link_01_vals), 410 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 411 0, DATALINK_CLASS_PHYS, DL_ETHER } 412 413 }; 414 415 #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) 416 417 static dladm_status_t i_dladm_set_linkprop_db(datalink_id_t, const char *, 418 char **, uint_t); 419 static dladm_status_t i_dladm_get_linkprop_db(datalink_id_t, const char *, 420 char **, uint_t *); 421 static dladm_status_t i_dladm_set_single_prop(datalink_id_t, datalink_class_t, 422 uint32_t, prop_desc_t *, char **, uint_t, uint_t); 423 static dladm_status_t i_dladm_set_linkprop(datalink_id_t, const char *, 424 char **, uint_t, uint_t); 425 static dladm_status_t i_dladm_getset_defval(prop_desc_t *, datalink_id_t, 426 datalink_media_t, uint_t); 427 /* 428 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all 429 * rates to be retrieved. However, we cannot increase it at this 430 * time because it will break binary compatibility with unbundled 431 * WiFi drivers and utilities. So for now we define an additional 432 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. 433 */ 434 #define MAX_SUPPORT_RATES 64 435 436 #define AP_ANCHOR "[anchor]" 437 #define AP_DELIMITER '.' 438 439 static dladm_status_t 440 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, 441 val_desc_t *vdp) 442 { 443 int i, j; 444 dladm_status_t status = DLADM_STATUS_OK; 445 446 for (j = 0; j < val_cnt; j++) { 447 for (i = 0; i < pdp->pd_noptval; i++) { 448 if (strcasecmp(*prop_val, 449 pdp->pd_optval[i].vd_name) == 0) { 450 break; 451 } 452 } 453 if (i == pdp->pd_noptval) { 454 status = DLADM_STATUS_BADVAL; 455 goto done; 456 } 457 (void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t)); 458 } 459 460 done: 461 return (status); 462 } 463 464 static dladm_status_t 465 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class, 466 uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt, 467 uint_t flags) 468 { 469 dladm_status_t status = DLADM_STATUS_OK; 470 val_desc_t *vdp = NULL; 471 boolean_t needfree = B_FALSE; 472 uint_t cnt, i; 473 474 if (!(pdp->pd_class & class)) 475 return (DLADM_STATUS_BADARG); 476 477 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 478 return (DLADM_STATUS_BADARG); 479 480 if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY)) 481 return (DLADM_STATUS_TEMPONLY); 482 483 if (!(flags & DLADM_OPT_ACTIVE)) 484 return (DLADM_STATUS_OK); 485 486 if (pdp->pd_set == NULL) 487 return (DLADM_STATUS_PROPRDONLY); 488 489 if (pdp->pd_flags & PD_CHECK_ALLOC) 490 needfree = B_TRUE; 491 else 492 needfree = B_FALSE; 493 if (prop_val != NULL) { 494 vdp = malloc(sizeof (val_desc_t) * val_cnt); 495 if (vdp == NULL) 496 return (DLADM_STATUS_NOMEM); 497 498 499 if (pdp->pd_check != NULL) { 500 status = pdp->pd_check(pdp, linkid, prop_val, val_cnt, 501 vdp, media); 502 } else if (pdp->pd_optval != NULL) { 503 status = do_check_prop(pdp, prop_val, val_cnt, vdp); 504 } else { 505 status = DLADM_STATUS_BADARG; 506 } 507 508 if (status != DLADM_STATUS_OK) 509 goto done; 510 511 cnt = val_cnt; 512 } else { 513 if (pdp->pd_defval.vd_name == NULL) 514 return (DLADM_STATUS_NOTSUP); 515 516 cnt = 1; 517 if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || 518 strlen(pdp->pd_defval.vd_name) > 0) { 519 if ((vdp = malloc(sizeof (val_desc_t))) == NULL) 520 return (DLADM_STATUS_NOMEM); 521 522 if (pdp->pd_check != NULL) { 523 status = pdp->pd_check(pdp, linkid, prop_val, 524 cnt, vdp, media); 525 if (status != DLADM_STATUS_OK) 526 goto done; 527 } else { 528 (void) memcpy(vdp, &pdp->pd_defval, 529 sizeof (val_desc_t)); 530 } 531 } else { 532 status = i_dladm_getset_defval(pdp, linkid, 533 media, flags); 534 return (status); 535 } 536 } 537 status = pdp->pd_set(pdp, linkid, vdp, cnt, flags, media); 538 if (needfree) { 539 for (i = 0; i < cnt; i++) 540 free((void *)((val_desc_t *)vdp + i)->vd_val); 541 } 542 done: 543 free(vdp); 544 return (status); 545 } 546 547 static dladm_status_t 548 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, 549 char **prop_val, uint_t val_cnt, uint_t flags) 550 { 551 int i; 552 boolean_t found = B_FALSE; 553 datalink_class_t class; 554 uint32_t media; 555 dladm_status_t status = DLADM_STATUS_OK; 556 557 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 558 if (status != DLADM_STATUS_OK) 559 return (status); 560 561 for (i = 0; i < DLADM_MAX_PROPS; i++) { 562 prop_desc_t *pdp = &prop_table[i]; 563 dladm_status_t s; 564 565 if (prop_name != NULL && 566 (strcasecmp(prop_name, pdp->pd_name) != 0)) 567 continue; 568 569 found = B_TRUE; 570 s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val, 571 val_cnt, flags); 572 573 if (prop_name != NULL) { 574 status = s; 575 break; 576 } else { 577 if (s != DLADM_STATUS_OK && 578 s != DLADM_STATUS_NOTSUP) 579 status = s; 580 } 581 } 582 if (!found) { 583 if (prop_name[0] == '_') { 584 /* other private properties */ 585 status = i_dladm_set_prop(linkid, prop_name, prop_val, 586 val_cnt, flags); 587 } else { 588 status = DLADM_STATUS_NOTFOUND; 589 } 590 } 591 592 return (status); 593 } 594 595 /* 596 * Set/reset link property for specific link 597 */ 598 dladm_status_t 599 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val, 600 uint_t val_cnt, uint_t flags) 601 { 602 dladm_status_t status = DLADM_STATUS_OK; 603 604 if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) || 605 (prop_val == NULL && val_cnt > 0) || 606 (prop_val != NULL && val_cnt == 0) || 607 (prop_name == NULL && prop_val != NULL)) { 608 return (DLADM_STATUS_BADARG); 609 } 610 611 status = i_dladm_set_linkprop(linkid, prop_name, prop_val, 612 val_cnt, flags); 613 if (status != DLADM_STATUS_OK) 614 return (status); 615 616 if (flags & DLADM_OPT_PERSIST) { 617 status = i_dladm_set_linkprop_db(linkid, prop_name, 618 prop_val, val_cnt); 619 } 620 return (status); 621 } 622 623 /* 624 * Walk link properties of the given specific link. 625 */ 626 dladm_status_t 627 dladm_walk_linkprop(datalink_id_t linkid, void *arg, 628 int (*func)(datalink_id_t, const char *, void *)) 629 { 630 dladm_status_t status; 631 datalink_class_t class; 632 uint_t media; 633 int i; 634 635 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 636 return (DLADM_STATUS_BADARG); 637 638 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 639 if (status != DLADM_STATUS_OK) 640 return (status); 641 642 for (i = 0; i < DLADM_MAX_PROPS; i++) { 643 if (!(prop_table[i].pd_class & class)) 644 continue; 645 646 if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media)) 647 continue; 648 649 if (func(linkid, prop_table[i].pd_name, arg) == 650 DLADM_WALK_TERMINATE) { 651 break; 652 } 653 } 654 655 return (DLADM_STATUS_OK); 656 } 657 658 /* 659 * Get linkprop of the given specific link. 660 */ 661 dladm_status_t 662 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type, 663 const char *prop_name, char **prop_val, uint_t *val_cntp) 664 { 665 dladm_status_t status = DLADM_STATUS_OK; 666 datalink_class_t class; 667 uint_t media; 668 prop_desc_t *pdp; 669 uint_t cnt, dld_flags = 0; 670 int i; 671 672 if (type == DLADM_PROP_VAL_DEFAULT) 673 dld_flags = MAC_PROP_DEFAULT; 674 675 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || 676 prop_val == NULL || val_cntp == NULL || *val_cntp == 0) 677 return (DLADM_STATUS_BADARG); 678 679 for (i = 0; i < DLADM_MAX_PROPS; i++) 680 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) 681 break; 682 683 if (i == DLADM_MAX_PROPS) { 684 if (prop_name[0] == '_') { 685 /* 686 * private property. 687 */ 688 return (i_dladm_get_prop(linkid, prop_name, 689 prop_val, val_cntp, type, dld_flags)); 690 } else { 691 return (DLADM_STATUS_NOTFOUND); 692 } 693 } 694 695 pdp = &prop_table[i]; 696 697 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 698 if (status != DLADM_STATUS_OK) 699 return (status); 700 701 if (!(pdp->pd_class & class)) 702 return (DLADM_STATUS_BADARG); 703 704 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 705 return (DLADM_STATUS_BADARG); 706 707 switch (type) { 708 case DLADM_PROP_VAL_CURRENT: 709 status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, media, 710 dld_flags); 711 break; 712 713 case DLADM_PROP_VAL_DEFAULT: 714 /* 715 * If defaults are not defined for the property, 716 * pd_defval.vd_name should be null. If the driver 717 * has to be contacted for the value, vd_name should 718 * be the empty string (""). Otherwise, dladm will 719 * just print whatever is in the table. 720 */ 721 if (pdp->pd_defval.vd_name == NULL) { 722 status = DLADM_STATUS_NOTSUP; 723 break; 724 } 725 726 if (strlen(pdp->pd_defval.vd_name) == 0) { 727 status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, 728 media, dld_flags); 729 } else { 730 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 731 } 732 *val_cntp = 1; 733 break; 734 735 case DLADM_PROP_VAL_MODIFIABLE: 736 if (pdp->pd_getmod != NULL) { 737 status = pdp->pd_getmod(pdp, linkid, prop_val, 738 val_cntp, media, dld_flags); 739 break; 740 } 741 cnt = pdp->pd_noptval; 742 if (cnt == 0) { 743 status = DLADM_STATUS_NOTSUP; 744 } else if (cnt > *val_cntp) { 745 status = DLADM_STATUS_TOOSMALL; 746 } else { 747 for (i = 0; i < cnt; i++) { 748 (void) strcpy(prop_val[i], 749 pdp->pd_optval[i].vd_name); 750 } 751 *val_cntp = cnt; 752 } 753 break; 754 case DLADM_PROP_VAL_PERSISTENT: 755 if (pdp->pd_flags & PD_TEMPONLY) 756 return (DLADM_STATUS_TEMPONLY); 757 status = i_dladm_get_linkprop_db(linkid, prop_name, 758 prop_val, val_cntp); 759 break; 760 default: 761 status = DLADM_STATUS_BADARG; 762 break; 763 } 764 765 return (status); 766 } 767 768 /*ARGSUSED*/ 769 static int 770 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg) 771 { 772 char *buf, **propvals; 773 uint_t i, valcnt = DLADM_MAX_PROP_VALCNT; 774 775 if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 776 DLADM_MAX_PROP_VALCNT)) == NULL) { 777 return (DLADM_WALK_CONTINUE); 778 } 779 780 propvals = (char **)(void *)buf; 781 for (i = 0; i < valcnt; i++) { 782 propvals[i] = buf + 783 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 784 i * DLADM_PROP_VAL_MAX; 785 } 786 787 if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name, 788 propvals, &valcnt) != DLADM_STATUS_OK) { 789 goto done; 790 } 791 792 (void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt, 793 DLADM_OPT_ACTIVE); 794 795 done: 796 if (buf != NULL) 797 free(buf); 798 799 return (DLADM_WALK_CONTINUE); 800 } 801 802 /*ARGSUSED*/ 803 static int 804 i_dladm_init_linkprop(datalink_id_t linkid, void *arg) 805 { 806 (void) dladm_init_linkprop(linkid, B_TRUE); 807 return (DLADM_WALK_CONTINUE); 808 } 809 810 dladm_status_t 811 dladm_init_linkprop(datalink_id_t linkid, boolean_t any_media) 812 { 813 datalink_media_t dmedia; 814 uint32_t media; 815 816 dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI; 817 818 if (linkid == DATALINK_ALL_LINKID) { 819 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, 820 DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST); 821 } else if (any_media || ((dladm_datalink_id2info(linkid, NULL, NULL, 822 &media, NULL, 0) == DLADM_STATUS_OK) && 823 DATALINK_MEDIA_ACCEPTED(dmedia, media))) { 824 (void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop); 825 } 826 return (DLADM_STATUS_OK); 827 } 828 829 /* ARGSUSED */ 830 static dladm_status_t 831 do_get_zone(struct prop_desc *pd, datalink_id_t linkid, 832 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 833 { 834 char zone_name[ZONENAME_MAX]; 835 zoneid_t zid; 836 dladm_status_t status; 837 char *cp; 838 dld_ioc_macprop_t *dip; 839 840 if (flags != 0) 841 return (DLADM_STATUS_NOTSUP); 842 843 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 844 if (status != DLADM_STATUS_OK) 845 return (status); 846 847 cp = dip->pr_val; 848 (void) memcpy(&zid, cp, sizeof (zid)); 849 free(dip); 850 851 *val_cnt = 1; 852 if (zid != GLOBAL_ZONEID) { 853 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 854 return (dladm_errno2status(errno)); 855 856 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); 857 } else { 858 *prop_val[0] = '\0'; 859 } 860 861 return (DLADM_STATUS_OK); 862 } 863 864 typedef int (*zone_get_devroot_t)(char *, char *, size_t); 865 866 static int 867 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen) 868 { 869 char root[MAXPATHLEN]; 870 zone_get_devroot_t real_zone_get_devroot; 871 void *dlhandle; 872 void *sym; 873 int ret; 874 875 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL) 876 return (-1); 877 878 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) { 879 (void) dlclose(dlhandle); 880 return (-1); 881 } 882 883 real_zone_get_devroot = (zone_get_devroot_t)sym; 884 885 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0) 886 (void) snprintf(dev, devlen, "%s%s", root, "/dev"); 887 (void) dlclose(dlhandle); 888 return (ret); 889 } 890 891 static dladm_status_t 892 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add) 893 { 894 char path[MAXPATHLEN]; 895 char name[MAXLINKNAMELEN]; 896 di_prof_t prof = NULL; 897 char zone_name[ZONENAME_MAX]; 898 dladm_status_t status; 899 int ret; 900 901 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 902 return (dladm_errno2status(errno)); 903 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) 904 return (dladm_errno2status(errno)); 905 if (di_prof_init(path, &prof) != 0) 906 return (dladm_errno2status(errno)); 907 908 status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN); 909 if (status != DLADM_STATUS_OK) 910 goto cleanup; 911 912 if (add) 913 ret = di_prof_add_dev(prof, name); 914 else 915 ret = di_prof_add_exclude(prof, name); 916 917 if (ret != 0) { 918 status = dladm_errno2status(errno); 919 goto cleanup; 920 } 921 922 if (di_prof_commit(prof) != 0) 923 status = dladm_errno2status(errno); 924 cleanup: 925 if (prof) 926 di_prof_fini(prof); 927 928 return (status); 929 } 930 931 /* ARGSUSED */ 932 static dladm_status_t 933 do_set_zone(prop_desc_t *pd, datalink_id_t linkid, val_desc_t *vdp, 934 uint_t val_cnt, uint_t flags, datalink_media_t media) 935 { 936 dladm_status_t status = DLADM_STATUS_OK; 937 zoneid_t zid_old, zid_new; 938 char link[MAXLINKNAMELEN]; 939 char *cp; 940 dld_ioc_macprop_t *dip; 941 dld_ioc_zid_t *dzp; 942 943 if (val_cnt != 1) 944 return (DLADM_STATUS_BADVALCNT); 945 946 dzp = (dld_ioc_zid_t *)vdp->vd_val; 947 948 /* 949 * If diz_is_ppa_hack is set, then an implicit vlan must be created. 950 * There is no old value to compare against, and vdp->vd_val is 951 * already populated with the zoneid and linkname in the function 952 * do_check_zone(). 953 */ 954 955 if (dzp->diz_is_ppa_hack) { 956 zid_old = GLOBAL_ZONEID; 957 } else { 958 dip = i_dladm_get_public_prop(linkid, pd->pd_name, 959 flags, &status); 960 if (status != DLADM_STATUS_OK) 961 return (status); 962 963 cp = dip->pr_val; 964 (void) memcpy(&zid_old, cp, sizeof (zid_old)); 965 free(dip); 966 } 967 968 zid_new = dzp->diz_zid; 969 (void) strlcpy(link, dzp->diz_link, MAXLINKNAMELEN); 970 971 /* Do nothing if setting to current value */ 972 if (zid_new == zid_old) 973 return (status); 974 975 if (zid_new != GLOBAL_ZONEID) { 976 /* 977 * If the new zoneid is the global zone, we could destroy 978 * the link (in the case of an implicitly-created VLAN) as a 979 * result of setting the zoneid. In that case, we defer the 980 * operation to the end of this function to avoid recreating 981 * the VLAN and getting a different linkid during the rollback 982 * if other operation fails. 983 * 984 * Otherwise, this operation will hold a reference to the 985 * link and prevent a link renaming, so we need to do it 986 * before other operations. 987 */ 988 status = i_dladm_set_public_prop(pd, linkid, vdp, val_cnt, 989 flags, media); 990 if (status != DLADM_STATUS_OK) 991 return (status); 992 } 993 994 if (zid_old != GLOBAL_ZONEID) { 995 if (zone_remove_datalink(zid_old, link) != 0 && 996 errno != ENXIO) { 997 status = dladm_errno2status(errno); 998 goto rollback1; 999 } 1000 1001 /* 1002 * It is okay to fail to update the /dev entry (some 1003 * vanity-named links do not have a /dev entry). 1004 */ 1005 (void) i_dladm_update_deventry(zid_old, linkid, B_FALSE); 1006 } 1007 1008 if (zid_new != GLOBAL_ZONEID) { 1009 if (zone_add_datalink(zid_new, link) != 0) { 1010 status = dladm_errno2status(errno); 1011 goto rollback2; 1012 } 1013 1014 if (dzp->diz_is_ppa_hack) { 1015 if ((status = dladm_name2info(link, &linkid, NULL, NULL, 1016 NULL)) != DLADM_STATUS_OK) { 1017 return (status); 1018 } 1019 } 1020 1021 (void) i_dladm_update_deventry(zid_new, linkid, B_TRUE); 1022 } else { 1023 status = i_dladm_set_public_prop(pd, linkid, vdp, val_cnt, 1024 flags, media); 1025 if (status != DLADM_STATUS_OK) 1026 goto rollback2; 1027 } 1028 1029 return (DLADM_STATUS_OK); 1030 1031 rollback2: 1032 if (zid_old != GLOBAL_ZONEID) 1033 (void) i_dladm_update_deventry(zid_old, linkid, B_TRUE); 1034 if (zid_old != GLOBAL_ZONEID) 1035 (void) zone_add_datalink(zid_old, link); 1036 rollback1: 1037 if (zid_new != GLOBAL_ZONEID) { 1038 dzp->diz_zid = zid_old; 1039 (void) i_dladm_set_public_prop(pd, linkid, vdp, val_cnt, 1040 flags, media); 1041 } 1042 1043 return (status); 1044 } 1045 1046 /* ARGSUSED */ 1047 static dladm_status_t 1048 do_check_zone(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, 1049 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1050 { 1051 char *zone_name; 1052 char linkname[MAXLINKNAMELEN]; 1053 zoneid_t zoneid; 1054 char *cp; 1055 dladm_status_t status = DLADM_STATUS_OK; 1056 boolean_t is_ppa_hack = B_FALSE; 1057 dld_ioc_zid_t *dzp; 1058 1059 if (val_cnt != 1) 1060 return (DLADM_STATUS_BADVALCNT); 1061 1062 dzp = malloc(sizeof (dld_ioc_zid_t)); 1063 if (dzp == NULL) 1064 return (DLADM_STATUS_NOMEM); 1065 1066 if (prop_val) { 1067 /* 1068 * The prop_val contains zone_name{:linkname}. The linkname is 1069 * present only when the link is a ppa-hacked vlan. 1070 */ 1071 cp = strchr(*prop_val, ':'); 1072 if (cp) { 1073 (void) strlcpy(linkname, cp + 1, MAXLINKNAMELEN); 1074 *cp = '\0'; 1075 is_ppa_hack = B_TRUE; 1076 } else { 1077 status = dladm_datalink_id2info(linkid, NULL, NULL, 1078 NULL, linkname, MAXLINKNAMELEN); 1079 if (status != DLADM_STATUS_OK) { 1080 goto done; 1081 } 1082 } 1083 zone_name = *prop_val; 1084 } else { 1085 zone_name = GLOBAL_ZONENAME; 1086 if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, 1087 linkname, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 1088 goto done; 1089 } 1090 } 1091 1092 if (strlen(linkname) > MAXLINKNAMELEN) { 1093 status = DLADM_STATUS_BADVAL; 1094 goto done; 1095 } 1096 1097 if ((zoneid = getzoneidbyname(zone_name)) == -1) { 1098 status = DLADM_STATUS_BADVAL; 1099 goto done; 1100 } 1101 1102 if (zoneid != GLOBAL_ZONEID) { 1103 ushort_t flags; 1104 1105 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags, 1106 sizeof (flags)) < 0) { 1107 status = dladm_errno2status(errno); 1108 goto done; 1109 } 1110 1111 if (!(flags & ZF_NET_EXCL)) { 1112 status = DLADM_STATUS_BADVAL; 1113 goto done; 1114 } 1115 } 1116 1117 (void) memset(dzp, 0, sizeof (dld_ioc_zid_t)); 1118 1119 dzp->diz_zid = zoneid; 1120 (void) strlcpy(dzp->diz_link, linkname, MAXLINKNAMELEN); 1121 dzp->diz_is_ppa_hack = is_ppa_hack; 1122 1123 vdp->vd_val = (uintptr_t)dzp; 1124 return (DLADM_STATUS_OK); 1125 done: 1126 free(dzp); 1127 return (status); 1128 } 1129 1130 /* ARGSUSED */ 1131 static dladm_status_t 1132 do_get_autopush(struct prop_desc *pd, datalink_id_t linkid, 1133 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1134 { 1135 struct dlautopush dlap; 1136 int i, len; 1137 dladm_status_t status; 1138 dld_ioc_macprop_t *dip; 1139 1140 if (flags & MAC_PROP_DEFAULT) 1141 return (DLADM_STATUS_NOTSUP); 1142 1143 *val_cnt = 1; 1144 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 1145 if (dip == NULL) { 1146 (*prop_val)[0] = '\0'; 1147 goto done; 1148 } 1149 (void) memcpy(&dlap, dip->pr_val, sizeof (dlap)); 1150 1151 for (i = 0, len = 0; i < dlap.dap_npush; i++) { 1152 if (i != 0) { 1153 (void) snprintf(*prop_val + len, 1154 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); 1155 len += 1; 1156 } 1157 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, 1158 "%s", dlap.dap_aplist[i]); 1159 len += strlen(dlap.dap_aplist[i]); 1160 if (dlap.dap_anchor - 1 == i) { 1161 (void) snprintf(*prop_val + len, 1162 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, 1163 AP_ANCHOR); 1164 len += (strlen(AP_ANCHOR) + 1); 1165 } 1166 } 1167 1168 free(dip); 1169 done: 1170 return (DLADM_STATUS_OK); 1171 } 1172 1173 /* 1174 * Add the specified module to the dlautopush structure; returns a 1175 * DLADM_STATUS_* code. 1176 */ 1177 dladm_status_t 1178 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) 1179 { 1180 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) 1181 return (DLADM_STATUS_BADVAL); 1182 1183 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { 1184 /* 1185 * We don't allow multiple anchors, and the anchor must 1186 * be after at least one module. 1187 */ 1188 if (dlap->dap_anchor != 0) 1189 return (DLADM_STATUS_BADVAL); 1190 if (dlap->dap_npush == 0) 1191 return (DLADM_STATUS_BADVAL); 1192 1193 dlap->dap_anchor = dlap->dap_npush; 1194 return (DLADM_STATUS_OK); 1195 } 1196 if (dlap->dap_npush > MAXAPUSH) 1197 return (DLADM_STATUS_BADVALCNT); 1198 1199 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, 1200 FMNAMESZ + 1); 1201 1202 return (DLADM_STATUS_OK); 1203 } 1204 1205 /* 1206 * Currently, both '.' and ' '(space) can be used as the delimiters between 1207 * autopush modules. The former is used in dladm set-linkprop, and the 1208 * latter is used in the autopush(1M) file. 1209 */ 1210 /* ARGSUSED */ 1211 static dladm_status_t 1212 do_check_autopush(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, 1213 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1214 { 1215 char *module; 1216 struct dlautopush *dlap; 1217 dladm_status_t status; 1218 char val[DLADM_PROP_VAL_MAX]; 1219 char delimiters[4]; 1220 1221 if (val_cnt != 1) 1222 return (DLADM_STATUS_BADVALCNT); 1223 1224 if (prop_val != NULL) { 1225 dlap = malloc(sizeof (struct dlautopush)); 1226 if (dlap == NULL) 1227 return (DLADM_STATUS_NOMEM); 1228 1229 (void) memset(dlap, 0, sizeof (struct dlautopush)); 1230 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); 1231 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); 1232 module = strtok(val, delimiters); 1233 while (module != NULL) { 1234 status = i_dladm_add_ap_module(module, dlap); 1235 if (status != DLADM_STATUS_OK) 1236 return (status); 1237 module = strtok(NULL, delimiters); 1238 } 1239 1240 vdp->vd_val = (uintptr_t)dlap; 1241 } else { 1242 vdp->vd_val = 0; 1243 } 1244 return (DLADM_STATUS_OK); 1245 } 1246 1247 /* ARGSUSED */ 1248 static dladm_status_t 1249 do_get_rate_common(struct prop_desc *pd, datalink_id_t linkid, 1250 char **prop_val, uint_t *val_cnt, uint_t id) 1251 { 1252 wl_rates_t *wrp; 1253 uint_t i; 1254 wldp_t *gbuf = NULL; 1255 dladm_status_t status = DLADM_STATUS_OK; 1256 1257 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 1258 status = DLADM_STATUS_NOMEM; 1259 goto done; 1260 } 1261 1262 status = i_dladm_wlan_get_ioctl(linkid, gbuf, id); 1263 if (status != DLADM_STATUS_OK) 1264 goto done; 1265 1266 wrp = (wl_rates_t *)gbuf->wldp_buf; 1267 if (wrp->wl_rates_num > *val_cnt) { 1268 status = DLADM_STATUS_TOOSMALL; 1269 goto done; 1270 } 1271 1272 if (wrp->wl_rates_rates[0] == 0) { 1273 prop_val[0][0] = '\0'; 1274 *val_cnt = 1; 1275 goto done; 1276 } 1277 1278 for (i = 0; i < wrp->wl_rates_num; i++) { 1279 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 1280 wrp->wl_rates_rates[i] % 2, 1281 (float)wrp->wl_rates_rates[i] / 2); 1282 } 1283 *val_cnt = wrp->wl_rates_num; 1284 1285 done: 1286 free(gbuf); 1287 return (status); 1288 } 1289 1290 static dladm_status_t 1291 do_get_rate_prop(struct prop_desc *pd, datalink_id_t linkid, 1292 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1293 { 1294 if (media != DL_WIFI) 1295 return (i_dladm_speed_get(pd, linkid, prop_val, 1296 val_cnt, flags)); 1297 1298 return (do_get_rate_common(pd, linkid, prop_val, val_cnt, 1299 WL_DESIRED_RATES)); 1300 } 1301 1302 /* ARGSUSED */ 1303 static dladm_status_t 1304 do_get_rate_mod(struct prop_desc *pd, datalink_id_t linkid, 1305 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1306 { 1307 switch (media) { 1308 case DL_ETHER: 1309 /* 1310 * Speed for ethernet links is unbounded. E.g., 802.11b 1311 * links can have a speed of 5.5 Gbps. 1312 */ 1313 return (DLADM_STATUS_NOTSUP); 1314 1315 case DL_WIFI: 1316 return (do_get_rate_common(pd, linkid, prop_val, val_cnt, 1317 WL_SUPPORTED_RATES)); 1318 default: 1319 return (DLADM_STATUS_BADARG); 1320 } 1321 } 1322 1323 static dladm_status_t 1324 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates) 1325 { 1326 int i; 1327 uint_t len; 1328 wldp_t *gbuf; 1329 wl_rates_t *wrp; 1330 dladm_status_t status = DLADM_STATUS_OK; 1331 1332 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1333 return (DLADM_STATUS_NOMEM); 1334 1335 (void) memset(gbuf, 0, MAX_BUF_LEN); 1336 1337 wrp = (wl_rates_t *)gbuf->wldp_buf; 1338 for (i = 0; i < rates->wr_cnt; i++) 1339 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 1340 wrp->wl_rates_num = rates->wr_cnt; 1341 1342 len = offsetof(wl_rates_t, wl_rates_rates) + 1343 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 1344 status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len, 1345 WLAN_SET_PARAM, len); 1346 1347 free(gbuf); 1348 return (status); 1349 } 1350 1351 /* ARGSUSED */ 1352 static dladm_status_t 1353 do_set_rate_prop(prop_desc_t *pd, datalink_id_t linkid, 1354 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1355 { 1356 dladm_wlan_rates_t rates; 1357 dladm_status_t status; 1358 1359 /* 1360 * can currently set rate on WIFI links only. 1361 */ 1362 if (media != DL_WIFI) 1363 return (DLADM_STATUS_PROPRDONLY); 1364 1365 if (val_cnt != 1) 1366 return (DLADM_STATUS_BADVALCNT); 1367 1368 rates.wr_cnt = 1; 1369 rates.wr_rates[0] = vdp[0].vd_val; 1370 1371 status = do_set_rate(linkid, &rates); 1372 1373 done: 1374 return (status); 1375 } 1376 1377 /* ARGSUSED */ 1378 static dladm_status_t 1379 do_check_rate(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, 1380 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1381 { 1382 int i; 1383 uint_t modval_cnt = MAX_SUPPORT_RATES; 1384 char *buf, **modval; 1385 dladm_status_t status; 1386 1387 if (val_cnt != 1) 1388 return (DLADM_STATUS_BADVALCNT); 1389 1390 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * 1391 MAX_SUPPORT_RATES); 1392 if (buf == NULL) { 1393 status = DLADM_STATUS_NOMEM; 1394 goto done; 1395 } 1396 1397 modval = (char **)(void *)buf; 1398 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 1399 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 1400 i * DLADM_STRSIZE; 1401 } 1402 1403 status = do_get_rate_mod(NULL, linkid, modval, &modval_cnt, media, 0); 1404 if (status != DLADM_STATUS_OK) 1405 goto done; 1406 1407 for (i = 0; i < modval_cnt; i++) { 1408 if (strcasecmp(*prop_val, modval[i]) == 0) { 1409 vdp->vd_val = (uintptr_t)(uint_t) 1410 (atof(*prop_val) * 2); 1411 status = DLADM_STATUS_OK; 1412 break; 1413 } 1414 } 1415 if (i == modval_cnt) 1416 status = DLADM_STATUS_BADVAL; 1417 done: 1418 free(buf); 1419 return (status); 1420 } 1421 1422 static dladm_status_t 1423 do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf) 1424 { 1425 return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG)); 1426 } 1427 1428 /* ARGSUSED */ 1429 static dladm_status_t 1430 do_get_channel_prop(struct prop_desc *pd, datalink_id_t linkid, 1431 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1432 { 1433 uint32_t channel; 1434 wldp_t *gbuf; 1435 dladm_status_t status = DLADM_STATUS_OK; 1436 1437 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1438 return (DLADM_STATUS_NOMEM); 1439 1440 if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK) 1441 goto done; 1442 1443 if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, 1444 &channel)) { 1445 status = DLADM_STATUS_NOTFOUND; 1446 goto done; 1447 } 1448 1449 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 1450 *val_cnt = 1; 1451 1452 done: 1453 free(gbuf); 1454 return (status); 1455 } 1456 1457 static dladm_status_t 1458 do_get_powermode(datalink_id_t linkid, wldp_t *gbuf) 1459 { 1460 return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE)); 1461 } 1462 1463 /* ARGSUSED */ 1464 static dladm_status_t 1465 do_get_powermode_prop(struct prop_desc *pd, datalink_id_t linkid, 1466 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1467 { 1468 wl_ps_mode_t *mode; 1469 const char *s; 1470 wldp_t *gbuf; 1471 dladm_status_t status = DLADM_STATUS_OK; 1472 1473 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1474 return (DLADM_STATUS_NOMEM); 1475 1476 if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK) 1477 goto done; 1478 1479 mode = (wl_ps_mode_t *)(gbuf->wldp_buf); 1480 switch (mode->wl_ps_mode) { 1481 case WL_PM_AM: 1482 s = "off"; 1483 break; 1484 case WL_PM_MPS: 1485 s = "max"; 1486 break; 1487 case WL_PM_FAST: 1488 s = "fast"; 1489 break; 1490 default: 1491 status = DLADM_STATUS_NOTFOUND; 1492 goto done; 1493 } 1494 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1495 *val_cnt = 1; 1496 1497 done: 1498 free(gbuf); 1499 return (status); 1500 } 1501 1502 static dladm_status_t 1503 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm) 1504 { 1505 wl_ps_mode_t ps_mode; 1506 1507 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 1508 1509 switch (*pm) { 1510 case DLADM_WLAN_PM_OFF: 1511 ps_mode.wl_ps_mode = WL_PM_AM; 1512 break; 1513 case DLADM_WLAN_PM_MAX: 1514 ps_mode.wl_ps_mode = WL_PM_MPS; 1515 break; 1516 case DLADM_WLAN_PM_FAST: 1517 ps_mode.wl_ps_mode = WL_PM_FAST; 1518 break; 1519 default: 1520 return (DLADM_STATUS_NOTSUP); 1521 } 1522 return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode, 1523 sizeof (ps_mode))); 1524 } 1525 1526 /* ARGSUSED */ 1527 static dladm_status_t 1528 do_set_powermode_prop(prop_desc_t *pd, datalink_id_t linkid, 1529 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1530 { 1531 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 1532 dladm_status_t status; 1533 1534 if (val_cnt != 1) 1535 return (DLADM_STATUS_BADVALCNT); 1536 1537 status = do_set_powermode(linkid, &powermode); 1538 1539 return (status); 1540 } 1541 1542 static dladm_status_t 1543 do_get_radio(datalink_id_t linkid, wldp_t *gbuf) 1544 { 1545 return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO)); 1546 } 1547 1548 /* ARGSUSED */ 1549 static dladm_status_t 1550 do_get_radio_prop(struct prop_desc *pd, datalink_id_t linkid, 1551 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1552 { 1553 wl_radio_t radio; 1554 const char *s; 1555 wldp_t *gbuf; 1556 dladm_status_t status = DLADM_STATUS_OK; 1557 1558 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1559 return (DLADM_STATUS_NOMEM); 1560 1561 if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK) 1562 goto done; 1563 1564 radio = *(wl_radio_t *)(gbuf->wldp_buf); 1565 switch (radio) { 1566 case B_TRUE: 1567 s = "on"; 1568 break; 1569 case B_FALSE: 1570 s = "off"; 1571 break; 1572 default: 1573 status = DLADM_STATUS_NOTFOUND; 1574 goto done; 1575 } 1576 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1577 *val_cnt = 1; 1578 1579 done: 1580 free(gbuf); 1581 return (status); 1582 } 1583 1584 static dladm_status_t 1585 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio) 1586 { 1587 wl_radio_t r; 1588 1589 switch (*radio) { 1590 case DLADM_WLAN_RADIO_ON: 1591 r = B_TRUE; 1592 break; 1593 case DLADM_WLAN_RADIO_OFF: 1594 r = B_FALSE; 1595 break; 1596 default: 1597 return (DLADM_STATUS_NOTSUP); 1598 } 1599 return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r))); 1600 } 1601 1602 /* ARGSUSED */ 1603 static dladm_status_t 1604 do_set_radio_prop(prop_desc_t *pd, datalink_id_t linkid, 1605 val_desc_t *vdp, uint_t val_cnt, uint_t fags, datalink_media_t media) 1606 { 1607 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 1608 dladm_status_t status; 1609 1610 if (val_cnt != 1) 1611 return (DLADM_STATUS_BADVALCNT); 1612 1613 status = do_set_radio(linkid, &radio); 1614 1615 return (status); 1616 } 1617 1618 static dladm_status_t 1619 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name, 1620 char **prop_val, uint_t val_cnt) 1621 { 1622 char buf[MAXLINELEN]; 1623 int i; 1624 dladm_conf_t conf; 1625 dladm_status_t status; 1626 1627 status = dladm_read_conf(linkid, &conf); 1628 if (status != DLADM_STATUS_OK) 1629 return (status); 1630 1631 /* 1632 * reset case. 1633 */ 1634 if (val_cnt == 0) { 1635 status = dladm_unset_conf_field(conf, prop_name); 1636 if (status == DLADM_STATUS_OK) 1637 status = dladm_write_conf(conf); 1638 goto done; 1639 } 1640 1641 buf[0] = '\0'; 1642 for (i = 0; i < val_cnt; i++) { 1643 (void) strlcat(buf, prop_val[i], MAXLINELEN); 1644 if (i != val_cnt - 1) 1645 (void) strlcat(buf, ",", MAXLINELEN); 1646 } 1647 1648 status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf); 1649 if (status == DLADM_STATUS_OK) 1650 status = dladm_write_conf(conf); 1651 1652 done: 1653 dladm_destroy_conf(conf); 1654 return (status); 1655 } 1656 1657 static dladm_status_t 1658 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name, 1659 char **prop_val, uint_t *val_cntp) 1660 { 1661 char buf[MAXLINELEN], *str; 1662 uint_t cnt = 0; 1663 dladm_conf_t conf; 1664 dladm_status_t status; 1665 1666 status = dladm_read_conf(linkid, &conf); 1667 if (status != DLADM_STATUS_OK) 1668 return (status); 1669 1670 status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN); 1671 if (status != DLADM_STATUS_OK) 1672 goto done; 1673 1674 str = strtok(buf, ","); 1675 while (str != NULL) { 1676 if (cnt == *val_cntp) { 1677 status = DLADM_STATUS_TOOSMALL; 1678 goto done; 1679 } 1680 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); 1681 str = strtok(NULL, ","); 1682 } 1683 1684 *val_cntp = cnt; 1685 1686 done: 1687 dladm_destroy_conf(conf); 1688 return (status); 1689 } 1690 1691 static dladm_public_prop_t * 1692 dladm_name2prop(const char *prop_name) 1693 { 1694 dladm_public_prop_t *p; 1695 1696 for (p = dladm_prop; p->pp_id != MAC_PROP_PRIVATE; p++) { 1697 if (strcmp(p->pp_name, prop_name) == 0) 1698 break; 1699 } 1700 return (p); 1701 } 1702 1703 1704 static dld_ioc_macprop_t * 1705 i_dladm_buf_alloc(size_t valsize, datalink_id_t linkid, const char *prop_name, 1706 uint_t flags, dladm_status_t *status) 1707 { 1708 int dsize; 1709 dld_ioc_macprop_t *dip; 1710 dladm_public_prop_t *p; 1711 1712 *status = DLADM_STATUS_OK; 1713 p = dladm_name2prop(prop_name); 1714 if (p->pp_id != MAC_PROP_PRIVATE) 1715 valsize = p->pp_valsize; 1716 1717 dsize = MAC_PROP_BUFSIZE(valsize); 1718 dip = malloc(dsize); 1719 if (dip == NULL) { 1720 *status = DLADM_STATUS_NOMEM; 1721 return (NULL); 1722 } 1723 bzero(dip, dsize); 1724 dip->pr_valsize = valsize; 1725 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name)); 1726 dip->pr_version = MAC_PROP_VERSION; 1727 dip->pr_linkid = linkid; 1728 dip->pr_num = p->pp_id; 1729 dip->pr_flags = flags; 1730 return (dip); 1731 } 1732 1733 /* ARGSUSED */ 1734 static dladm_status_t 1735 i_dladm_set_public_prop(prop_desc_t *pd, datalink_id_t linkid, 1736 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1737 { 1738 dld_ioc_macprop_t *dip; 1739 int fd; 1740 dladm_status_t status = DLADM_STATUS_OK; 1741 uint8_t u8; 1742 uint16_t u16; 1743 uint32_t u32; 1744 void *val; 1745 1746 dip = i_dladm_buf_alloc(0, linkid, pd->pd_name, 0, &status); 1747 if (dip == NULL) 1748 return (status); 1749 1750 if (pd->pd_flags & PD_CHECK_ALLOC) 1751 val = (void *)vdp->vd_val; 1752 else { 1753 /* 1754 * Currently all 1/2/4-byte size properties are byte/word/int. 1755 * No need (yet) to distinguish these from arrays of same size. 1756 */ 1757 switch (dip->pr_valsize) { 1758 case 1: 1759 u8 = vdp->vd_val; 1760 val = &u8; 1761 break; 1762 case 2: 1763 u16 = vdp->vd_val; 1764 val = &u16; 1765 break; 1766 case 4: 1767 u32 = vdp->vd_val; 1768 val = &u32; 1769 break; 1770 default: 1771 val = &vdp->vd_val; 1772 break; 1773 } 1774 } 1775 1776 if (val != NULL) 1777 (void) memcpy(dip->pr_val, val, dip->pr_valsize); 1778 else 1779 dip->pr_valsize = 0; 1780 1781 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { 1782 status = dladm_errno2status(errno); 1783 goto done; 1784 } 1785 if (ioctl(fd, DLDIOC_SETMACPROP, dip) < 0) 1786 status = dladm_errno2status(errno); 1787 1788 (void) close(fd); 1789 done: 1790 free(dip); 1791 return (status); 1792 } 1793 1794 static dld_ioc_macprop_t * 1795 i_dladm_get_public_prop(datalink_id_t linkid, char *prop_name, uint_t flags, 1796 dladm_status_t *status) 1797 { 1798 int fd; 1799 dld_ioc_macprop_t *dip = NULL; 1800 1801 *status = DLADM_STATUS_OK; 1802 1803 dip = i_dladm_buf_alloc(0, linkid, prop_name, flags, status); 1804 if (dip == NULL) 1805 return (NULL); 1806 1807 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { 1808 *status = dladm_errno2status(errno); 1809 goto done; 1810 } 1811 if (ioctl(fd, DLDIOC_GETMACPROP, dip) < 0) 1812 *status = dladm_errno2status(errno); 1813 1814 (void) close(fd); 1815 done: 1816 if (*status != DLADM_STATUS_OK) { 1817 free(dip); 1818 return (NULL); 1819 } 1820 return (dip); 1821 } 1822 1823 /* ARGSUSED */ 1824 static dladm_status_t 1825 i_dladm_defmtu_check(struct prop_desc *pd, datalink_id_t linkid, 1826 char **prop_val, uint_t val_cnt, val_desc_t *v, datalink_media_t media) 1827 { 1828 if (val_cnt != 1) 1829 return (DLADM_STATUS_BADVAL); 1830 v->vd_val = atoi(prop_val[0]); 1831 return (DLADM_STATUS_OK); 1832 } 1833 1834 /* ARGSUSED */ 1835 static dladm_status_t 1836 i_dladm_duplex_get(struct prop_desc *pd, datalink_id_t linkid, 1837 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1838 { 1839 link_duplex_t link_duplex; 1840 dladm_status_t status; 1841 1842 if (flags & MAC_PROP_DEFAULT) 1843 return (DLADM_STATUS_NOTSUP); 1844 1845 if ((status = dladm_get_single_mac_stat(linkid, "link_duplex", 1846 KSTAT_DATA_UINT32, &link_duplex)) != 0) 1847 return (status); 1848 1849 switch (link_duplex) { 1850 case LINK_DUPLEX_FULL: 1851 (void) strcpy(*prop_val, "full"); 1852 break; 1853 case LINK_DUPLEX_HALF: 1854 (void) strcpy(*prop_val, "half"); 1855 break; 1856 default: 1857 (void) strcpy(*prop_val, "unknown"); 1858 break; 1859 } 1860 *val_cnt = 1; 1861 return (DLADM_STATUS_OK); 1862 } 1863 1864 /* ARGSUSED */ 1865 static dladm_status_t 1866 i_dladm_speed_get(struct prop_desc *pd, datalink_id_t linkid, 1867 char **prop_val, uint_t *val_cnt, uint_t flags) 1868 { 1869 uint64_t ifspeed = 0; 1870 dladm_status_t status; 1871 1872 if (flags & MAC_PROP_DEFAULT) 1873 return (DLADM_STATUS_NOTSUP); 1874 1875 if ((status = dladm_get_single_mac_stat(linkid, "ifspeed", 1876 KSTAT_DATA_UINT64, &ifspeed)) != 0) 1877 return (status); 1878 1879 if ((ifspeed % 1000000) != 0) { 1880 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 1881 "%llf", ifspeed / (float)1000000); /* Mbps */ 1882 } else { 1883 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 1884 "%llu", ifspeed / 1000000); /* Mbps */ 1885 } 1886 *val_cnt = 1; 1887 return (DLADM_STATUS_OK); 1888 } 1889 1890 /* ARGSUSED */ 1891 static dladm_status_t 1892 i_dladm_status_get(struct prop_desc *pd, datalink_id_t linkid, 1893 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1894 { 1895 link_state_t link_state; 1896 dladm_status_t status; 1897 uchar_t *cp; 1898 dld_ioc_macprop_t *dip; 1899 1900 if (flags & MAC_PROP_DEFAULT) 1901 return (DLADM_STATUS_NOTSUP); 1902 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 1903 if (status != DLADM_STATUS_OK) 1904 return (status); 1905 cp = (uchar_t *)dip->pr_val; 1906 (void) memcpy(&link_state, cp, sizeof (link_state)); 1907 1908 switch (link_state) { 1909 case LINK_STATE_UP: 1910 (void) strcpy(*prop_val, "up"); 1911 break; 1912 case LINK_STATE_DOWN: 1913 (void) strcpy(*prop_val, "down"); 1914 break; 1915 default: 1916 (void) strcpy(*prop_val, "unknown"); 1917 break; 1918 } 1919 *val_cnt = 1; 1920 free(dip); 1921 return (DLADM_STATUS_OK); 1922 } 1923 1924 /* ARGSUSED */ 1925 static dladm_status_t 1926 i_dladm_binary_get(struct prop_desc *pd, datalink_id_t linkid, 1927 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1928 { 1929 dld_ioc_macprop_t *dip; 1930 dladm_status_t status; 1931 1932 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 1933 if (dip == NULL) 1934 return (status); 1935 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]); 1936 free(dip); 1937 *val_cnt = 1; 1938 return (DLADM_STATUS_OK); 1939 } 1940 1941 /* ARGSUSED */ 1942 static dladm_status_t 1943 i_dladm_uint32_get(struct prop_desc *pd, datalink_id_t linkid, 1944 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1945 { 1946 dld_ioc_macprop_t *dip; 1947 uint32_t v = 0; 1948 uchar_t *cp; 1949 dladm_status_t status; 1950 1951 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 1952 if (dip == NULL) 1953 return (status); 1954 cp = (uchar_t *)dip->pr_val; 1955 (void) memcpy(&v, cp, sizeof (v)); 1956 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v); 1957 free(dip); 1958 *val_cnt = 1; 1959 return (DLADM_STATUS_OK); 1960 } 1961 1962 /* ARGSUSED */ 1963 static dladm_status_t 1964 i_dladm_flowctl_get(struct prop_desc *pd, datalink_id_t linkid, 1965 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1966 { 1967 dld_ioc_macprop_t *dip; 1968 link_flowctrl_t v; 1969 dladm_status_t status; 1970 uchar_t *cp; 1971 1972 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 1973 if (dip == NULL) 1974 return (status); 1975 cp = (uchar_t *)dip->pr_val; 1976 (void) memcpy(&v, cp, sizeof (v)); 1977 switch (v) { 1978 case LINK_FLOWCTRL_NONE: 1979 (void) sprintf(*prop_val, "no"); 1980 break; 1981 case LINK_FLOWCTRL_RX: 1982 (void) sprintf(*prop_val, "rx"); 1983 break; 1984 case LINK_FLOWCTRL_TX: 1985 (void) sprintf(*prop_val, "tx"); 1986 break; 1987 case LINK_FLOWCTRL_BI: 1988 (void) sprintf(*prop_val, "bi"); 1989 break; 1990 } 1991 free(dip); 1992 *val_cnt = 1; 1993 return (DLADM_STATUS_OK); 1994 } 1995 1996 1997 /* ARGSUSED */ 1998 static dladm_status_t 1999 i_dladm_set_prop(datalink_id_t linkid, const char *prop_name, 2000 char **prop_val, uint_t val_cnt, uint_t flags) 2001 { 2002 int fd, i, slen; 2003 int bufsize = 0; 2004 dld_ioc_macprop_t *dip = NULL; 2005 uchar_t *dp; 2006 dladm_public_prop_t *p; 2007 dladm_status_t status = DLADM_STATUS_OK; 2008 2009 if ((prop_name == NULL && prop_val != NULL) || 2010 (prop_val != NULL && val_cnt == 0)) 2011 return (DLADM_STATUS_BADARG); 2012 p = dladm_name2prop(prop_name); 2013 if (p->pp_id != MAC_PROP_PRIVATE) 2014 return (DLADM_STATUS_BADARG); 2015 2016 /* 2017 * private properties: all parsing is done in the kernel. 2018 * allocate a enough space for each property + its separator (','). 2019 */ 2020 for (i = 0; i < val_cnt; i++) { 2021 bufsize += strlen(prop_val[i]) + 1; 2022 } 2023 2024 if (prop_val == NULL) { 2025 /* 2026 * getting default value. so use more buffer space. 2027 */ 2028 bufsize += 1024; 2029 } 2030 2031 dip = i_dladm_buf_alloc(bufsize + 1, linkid, prop_name, 2032 (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status); 2033 if (dip == NULL) 2034 return (status); 2035 2036 dp = (uchar_t *)dip->pr_val; 2037 slen = 0; 2038 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { 2039 status = dladm_errno2status(errno); 2040 goto done; 2041 } 2042 if (prop_val == NULL) { 2043 if (ioctl(fd, DLDIOC_GETMACPROP, dip) < 0) { 2044 status = dladm_errno2status(errno); 2045 goto done; 2046 } 2047 } else { 2048 for (i = 0; i < val_cnt; i++) { 2049 int plen = 0; 2050 2051 plen = strlen(prop_val[i]); 2052 bcopy(prop_val[i], dp, plen); 2053 slen += plen; 2054 /* 2055 * add a "," separator and update dp. 2056 */ 2057 if (i != (val_cnt -1)) 2058 dp[slen++] = ','; 2059 dp += (plen + 1); 2060 } 2061 } 2062 if (ioctl(fd, DLDIOC_SETMACPROP, dip) < 0) 2063 status = dladm_errno2status(errno); 2064 2065 done: 2066 if (fd > 0) 2067 (void) close(fd); 2068 free(dip); 2069 return (status); 2070 } 2071 2072 static dladm_status_t 2073 i_dladm_get_prop(datalink_id_t linkid, const char *prop_name, 2074 char **prop_val, uint_t *val_cnt, dladm_prop_type_t type, uint_t dld_flags) 2075 { 2076 int fd; 2077 dladm_status_t status = DLADM_STATUS_OK; 2078 dld_ioc_macprop_t *dip = NULL; 2079 dladm_public_prop_t *p; 2080 char tmp = '\0'; 2081 2082 if ((prop_name == NULL && prop_val != NULL) || 2083 (prop_val != NULL && val_cnt == 0)) 2084 return (DLADM_STATUS_BADARG); 2085 2086 p = dladm_name2prop(prop_name); 2087 if (p->pp_id != MAC_PROP_PRIVATE) 2088 return (DLADM_STATUS_BADARG); 2089 2090 if (type == DLADM_PROP_VAL_MODIFIABLE) { 2091 *prop_val = &tmp; 2092 *val_cnt = 1; 2093 return (DLADM_STATUS_OK); 2094 } 2095 2096 /* 2097 * private properties: all parsing is done in the kernel. 2098 */ 2099 dip = i_dladm_buf_alloc(1024, linkid, prop_name, dld_flags, &status); 2100 if (dip == NULL) 2101 return (status); 2102 2103 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { 2104 free(dip); 2105 return (DLADM_STATUS_BADARG); 2106 } 2107 2108 if (ioctl(fd, DLDIOC_GETMACPROP, dip) < 0) { 2109 status = dladm_errno2status(errno); 2110 } else { 2111 (void) strncpy(*prop_val, dip->pr_val, DLADM_PROP_VAL_MAX); 2112 *val_cnt = 1; 2113 } 2114 2115 (void) close(fd); 2116 free(dip); 2117 return (status); 2118 } 2119 2120 2121 static dladm_status_t 2122 i_dladm_getset_defval(prop_desc_t *pdp, datalink_id_t linkid, 2123 datalink_media_t media, uint_t flags) 2124 { 2125 dladm_status_t status; 2126 char **prop_vals = NULL, *buf; 2127 size_t bufsize; 2128 uint_t cnt; 2129 int i; 2130 2131 /* 2132 * Allocate buffer needed for prop_vals array. We can have at most 2133 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where 2134 * each entry has max size DLADM_PROP_VAL_MAX 2135 */ 2136 bufsize = 2137 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 2138 buf = malloc(bufsize); 2139 prop_vals = (char **)(void *)buf; 2140 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 2141 prop_vals[i] = buf + 2142 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 2143 i * DLADM_PROP_VAL_MAX; 2144 } 2145 2146 /* 2147 * For properties which have pdp->pd_defval.vd_name as a non-empty 2148 * string, the "" itself is used to reset the property (exceptions 2149 * are zone and autopush, which populate vdp->vd_val). So 2150 * libdladm can copy pdp->pd_defval over to the val_desc_t passed 2151 * down on the setprop using the global values in the table. For 2152 * other cases (vd_name is ""), doing reset-linkprop will cause 2153 * libdladm to do a getprop to find the default value and then do 2154 * a setprop to reset the value to default. 2155 */ 2156 status = pdp->pd_get(pdp, linkid, prop_vals, &cnt, media, 2157 MAC_PROP_DEFAULT); 2158 if (status == DLADM_STATUS_OK) { 2159 status = i_dladm_set_single_prop(linkid, pdp->pd_class, 2160 media, pdp, prop_vals, cnt, flags); 2161 } 2162 free(buf); 2163 return (status); 2164 } 2165