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