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); 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 dld_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_prop_t *dld_buf_alloc(size_t, datalink_id_t, const char *, 112 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); 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_uint64_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 *); 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 /* 183 * indicate link classes this property applies to. 184 */ 185 datalink_class_t pd_class; 186 187 /* 188 * indicate link media type this property applies to. 189 */ 190 datalink_media_t pd_dmedia; 191 } prop_desc_t; 192 193 #define DLD_PROPBUF_SIZE(v) sizeof (dld_ioc_prop_t) + (v) - 1 194 195 196 static dld_public_prop_t dld_prop[] = { 197 { DLD_PROP_DUPLEX, sizeof (uint8_t), 198 "duplex", "link duplex mode" }, 199 200 {DLD_PROP_SPEED, sizeof (uint64_t), 201 "speed", "link speed (bps)" }, 202 203 { DLD_PROP_STATUS, sizeof (uint8_t), 204 "state", "link up/down" }, 205 206 { DLD_PROP_AUTONEG, sizeof (uint8_t), 207 "adv_autoneg_cap", "Advertised auto-negotiation" }, 208 209 { DLD_PROP_DEFMTU, sizeof (uint64_t), 210 "mtu", "current link mtu" }, 211 212 { DLD_PROP_FLOWCTRL, sizeof (link_flowctrl_t), 213 "flowctrl", "flowcontrol" }, 214 215 { DLD_PROP_ADV_1000FDX_CAP, sizeof (uint8_t), 216 "adv_1000fdx_cap", "Adv 1000 Mbps fdx" }, 217 218 { DLD_PROP_EN_1000FDX_CAP, sizeof (uint8_t), 219 "en_1000fdx_cap", "Enable 1000 Mbps fdx" }, 220 221 { DLD_PROP_ADV_1000HDX_CAP, sizeof (uint8_t), 222 "adv_1000hdx_cap", "Adv 1000 Mbps hdx" }, 223 224 { DLD_PROP_EN_1000HDX_CAP, sizeof (uint8_t), 225 "en_1000hdx_cap", "Enable 1000 Mbps hdx" }, 226 227 { DLD_PROP_ADV_100FDX_CAP, sizeof (uint8_t), 228 "adv_100fdx_cap", "Adv 100 Mbps fdx" }, 229 230 { DLD_PROP_EN_100FDX_CAP, sizeof (uint8_t), 231 "en_100fdx_cap", "Enable 100 Mbps fdx" }, 232 233 { DLD_PROP_ADV_100HDX_CAP, sizeof (uint8_t), 234 "adv_100hdx_cap", "Adv 100 Mbps hdx" }, 235 236 { DLD_PROP_EN_100HDX_CAP, sizeof (uint8_t), 237 "en_100hdx_cap", "Enable 100 Mbps hdx" }, 238 239 { DLD_PROP_ADV_10FDX_CAP, sizeof (uint8_t), 240 "adv_10fdx_cap", "Adv 10 Mbps fdx" }, 241 242 { DLD_PROP_EN_10FDX_CAP, sizeof (uint8_t), 243 "en_10fdx_cap", "Enable 10 Mbps fdx" }, 244 245 { DLD_PROP_ADV_10HDX_CAP, sizeof (uint8_t), 246 "adv_10hdx_cap", "Adv 10 Mbps hdx" }, 247 248 { DLD_PROP_EN_10HDX_CAP, sizeof (uint8_t), 249 "en_10hdx_cap", "Enable 10 Mbps hdx" }, 250 251 { DLD_PROP_PRIVATE, 0, 252 "driver-private", "" } 253 }; 254 255 static val_desc_t link_duplex_vals[] = { 256 { "half", LINK_DUPLEX_HALF }, 257 { "full", LINK_DUPLEX_HALF } 258 }; 259 static val_desc_t link_speed_vals[] = { 260 { "10", 10 }, 261 { "100", 100 }, 262 { "1000", 1000 } 263 }; 264 static val_desc_t link_status_vals[] = { 265 { "up", LINK_STATE_UP }, 266 { "down", LINK_STATE_DOWN } 267 }; 268 static val_desc_t link_01_vals[] = { 269 { "1", 1 }, 270 { "0", 0 } 271 }; 272 static val_desc_t link_flow_vals[] = { 273 { "no", LINK_FLOWCTRL_NONE }, 274 { "tx", LINK_FLOWCTRL_TX }, 275 { "rx", LINK_FLOWCTRL_RX }, 276 { "bi", LINK_FLOWCTRL_BI } 277 }; 278 static val_desc_t macdefaultmtu_vals[] = { 279 { "68-9000", NULL } 280 }; 281 282 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) 283 284 static val_desc_t dladm_wlan_radio_vals[] = { 285 { "on", DLADM_WLAN_RADIO_ON }, 286 { "off", DLADM_WLAN_RADIO_OFF } 287 }; 288 289 static val_desc_t dladm_wlan_powermode_vals[] = { 290 { "off", DLADM_WLAN_PM_OFF }, 291 { "fast", DLADM_WLAN_PM_FAST }, 292 { "max", DLADM_WLAN_PM_MAX } 293 }; 294 295 static prop_desc_t prop_table[] = { 296 297 { "channel", { NULL, 0 }, 298 NULL, 0, NULL, NULL, 299 do_get_channel_prop, NULL, 0, 300 DATALINK_CLASS_PHYS, DL_WIFI }, 301 302 { "powermode", { "off", DLADM_WLAN_PM_OFF }, 303 dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals), 304 do_set_powermode_prop, NULL, 305 do_get_powermode_prop, NULL, 0, 306 DATALINK_CLASS_PHYS, DL_WIFI }, 307 308 { "radio", { "on", DLADM_WLAN_RADIO_ON }, 309 dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals), 310 do_set_radio_prop, NULL, 311 do_get_radio_prop, NULL, 0, 312 DATALINK_CLASS_PHYS, DL_WIFI }, 313 314 { "speed", { "", 0 }, NULL, 0, 315 do_set_rate_prop, do_get_rate_mod, 316 do_get_rate_prop, do_check_rate, 0, 317 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE }, 318 319 { "autopush", { "", NULL }, NULL, 0, 320 do_set_autopush, NULL, 321 do_get_autopush, do_check_autopush, PD_CHECK_ALLOC, 322 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 323 324 { "zone", { "", NULL }, NULL, 0, 325 do_set_zone, NULL, 326 do_get_zone, do_check_zone, PD_TEMPONLY, 327 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 328 329 { "duplex", { "full", LINK_DUPLEX_FULL }, 330 link_duplex_vals, VALCNT(link_duplex_vals), 331 NULL, NULL, dld_duplex_get, NULL, 332 0, DATALINK_CLASS_PHYS, DL_ETHER }, 333 334 { "state", { "up", LINK_STATE_UP }, 335 link_status_vals, VALCNT(link_status_vals), 336 NULL, NULL, dld_status_get, NULL, 337 0, DATALINK_CLASS_PHYS, DL_ETHER }, 338 339 { "adv_autoneg_cap", { "1", 1 }, 340 link_01_vals, VALCNT(link_01_vals), 341 dld_set_public_prop, NULL, dld_binary_get, NULL, 342 0, DATALINK_CLASS_PHYS, DL_ETHER }, 343 344 { "mtu", { NULL, NULL }, 345 macdefaultmtu_vals, VALCNT(macdefaultmtu_vals), 346 dld_set_public_prop, NULL, dld_uint64_get, dld_defmtu_check, 347 PD_CHECK_ALLOC, DATALINK_CLASS_PHYS, DL_ETHER }, 348 349 { "flowctrl", { "bi", LINK_FLOWCTRL_BI }, 350 link_flow_vals, VALCNT(link_flow_vals), 351 dld_set_public_prop, NULL, dld_flowctl_get, NULL, 352 0, DATALINK_CLASS_PHYS, DL_ETHER }, 353 354 { "adv_1000fdx_cap", { NULL, NULL }, 355 link_01_vals, 0, 356 NULL, NULL, dld_binary_get, NULL, 357 0, DATALINK_CLASS_PHYS, DL_ETHER }, 358 359 { "en_1000fdx_cap", { NULL, NULL }, 360 link_01_vals, VALCNT(link_01_vals), 361 dld_set_public_prop, NULL, dld_binary_get, NULL, 362 0, DATALINK_CLASS_PHYS, DL_ETHER }, 363 364 { "adv_1000hdx_cap", { NULL, NULL }, 365 link_01_vals, VALCNT(link_01_vals), 366 NULL, NULL, dld_binary_get, NULL, 367 0, DATALINK_CLASS_PHYS, DL_ETHER }, 368 369 { "en_1000hdx_cap", { NULL, NULL }, 370 link_01_vals, VALCNT(link_01_vals), 371 dld_set_public_prop, NULL, dld_binary_get, NULL, 372 0, DATALINK_CLASS_PHYS, DL_ETHER }, 373 374 { "adv_100fdx_cap", { NULL, NULL }, 375 link_01_vals, VALCNT(link_01_vals), 376 NULL, NULL, dld_binary_get, NULL, 377 0, DATALINK_CLASS_PHYS, DL_ETHER }, 378 379 { "en_100fdx_cap", { NULL, NULL }, 380 link_01_vals, VALCNT(link_01_vals), 381 dld_set_public_prop, NULL, dld_binary_get, NULL, 382 0, DATALINK_CLASS_PHYS, DL_ETHER }, 383 384 { "adv_100hdx_cap", { NULL, NULL }, 385 link_01_vals, VALCNT(link_01_vals), 386 NULL, NULL, dld_binary_get, NULL, 387 0, DATALINK_CLASS_PHYS, DL_ETHER }, 388 389 { "en_100hdx_cap", { NULL, NULL }, 390 link_01_vals, VALCNT(link_01_vals), 391 dld_set_public_prop, NULL, dld_binary_get, NULL, 392 0, DATALINK_CLASS_PHYS, DL_ETHER }, 393 394 { "adv_10fdx_cap", { NULL, NULL }, 395 link_01_vals, VALCNT(link_01_vals), 396 NULL, NULL, dld_binary_get, NULL, 397 0, DATALINK_CLASS_PHYS, DL_ETHER }, 398 399 { "en_10fdx_cap", { NULL, NULL }, 400 link_01_vals, VALCNT(link_01_vals), 401 dld_set_public_prop, NULL, dld_binary_get, NULL, 402 0, DATALINK_CLASS_PHYS, DL_ETHER }, 403 404 { "adv_10hdx_cap", { NULL, NULL }, 405 link_01_vals, VALCNT(link_01_vals), 406 NULL, NULL, dld_binary_get, NULL, 407 0, DATALINK_CLASS_PHYS, DL_ETHER }, 408 409 { "en_10hdx_cap", { NULL, NULL }, 410 link_01_vals, VALCNT(link_01_vals), 411 dld_set_public_prop, NULL, dld_binary_get, NULL, 412 0, DATALINK_CLASS_PHYS, DL_ETHER } 413 414 }; 415 416 #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) 417 418 static dladm_status_t i_dladm_set_linkprop_db(datalink_id_t, const char *, 419 char **, uint_t); 420 static dladm_status_t i_dladm_get_linkprop_db(datalink_id_t, const char *, 421 char **, uint_t *); 422 static dladm_status_t i_dladm_set_single_prop(datalink_id_t, datalink_class_t, 423 uint32_t, prop_desc_t *, char **, uint_t, uint_t); 424 static dladm_status_t i_dladm_set_linkprop(datalink_id_t, const char *, 425 char **, uint_t, uint_t); 426 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 if ((vdp = malloc(sizeof (val_desc_t))) == NULL) 517 return (DLADM_STATUS_NOMEM); 518 519 (void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t)); 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; 655 int i; 656 657 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || 658 prop_val == NULL || val_cntp == NULL || *val_cntp == 0) 659 return (DLADM_STATUS_BADARG); 660 661 for (i = 0; i < DLADM_MAX_PROPS; i++) 662 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) 663 break; 664 665 if (i == DLADM_MAX_PROPS) { 666 if (prop_name[0] == '_') { 667 /* 668 * private property. 669 */ 670 return (dld_get_prop(linkid, prop_name, 671 prop_val, val_cntp, type)); 672 } else { 673 return (DLADM_STATUS_NOTFOUND); 674 } 675 } 676 677 pdp = &prop_table[i]; 678 679 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 680 if (status != DLADM_STATUS_OK) 681 return (status); 682 683 if (!(pdp->pd_class & class)) 684 return (DLADM_STATUS_BADARG); 685 686 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 687 return (DLADM_STATUS_BADARG); 688 689 switch (type) { 690 case DLADM_PROP_VAL_CURRENT: 691 status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, media); 692 break; 693 694 case DLADM_PROP_VAL_DEFAULT: 695 if (pdp->pd_defval.vd_name == NULL) { 696 status = DLADM_STATUS_NOTSUP; 697 break; 698 } 699 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 700 *val_cntp = 1; 701 break; 702 703 case DLADM_PROP_VAL_MODIFIABLE: 704 if (pdp->pd_getmod != NULL) { 705 status = pdp->pd_getmod(pdp, linkid, prop_val, 706 val_cntp, media); 707 break; 708 } 709 cnt = pdp->pd_noptval; 710 if (cnt == 0) { 711 status = DLADM_STATUS_NOTSUP; 712 } else if (cnt > *val_cntp) { 713 status = DLADM_STATUS_TOOSMALL; 714 } else { 715 for (i = 0; i < cnt; i++) { 716 (void) strcpy(prop_val[i], 717 pdp->pd_optval[i].vd_name); 718 } 719 *val_cntp = cnt; 720 } 721 break; 722 case DLADM_PROP_VAL_PERSISTENT: 723 if (pdp->pd_flags & PD_TEMPONLY) 724 return (DLADM_STATUS_TEMPONLY); 725 status = i_dladm_get_linkprop_db(linkid, prop_name, 726 prop_val, val_cntp); 727 break; 728 default: 729 status = DLADM_STATUS_BADARG; 730 break; 731 } 732 733 return (status); 734 } 735 736 /*ARGSUSED*/ 737 static int 738 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg) 739 { 740 char *buf, **propvals; 741 uint_t i, valcnt = DLADM_MAX_PROP_VALCNT; 742 743 if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 744 DLADM_MAX_PROP_VALCNT)) == NULL) { 745 return (DLADM_WALK_CONTINUE); 746 } 747 748 propvals = (char **)(void *)buf; 749 for (i = 0; i < valcnt; i++) { 750 propvals[i] = buf + 751 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 752 i * DLADM_PROP_VAL_MAX; 753 } 754 755 if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name, 756 propvals, &valcnt) != DLADM_STATUS_OK) { 757 goto done; 758 } 759 760 (void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt, 761 DLADM_OPT_ACTIVE); 762 763 done: 764 if (buf != NULL) 765 free(buf); 766 767 return (DLADM_WALK_CONTINUE); 768 } 769 770 /*ARGSUSED*/ 771 static int 772 i_dladm_init_linkprop(datalink_id_t linkid, void *arg) 773 { 774 (void) dladm_init_linkprop(linkid); 775 return (DLADM_WALK_CONTINUE); 776 } 777 778 dladm_status_t 779 dladm_init_linkprop(datalink_id_t linkid) 780 { 781 if (linkid == DATALINK_ALL_LINKID) { 782 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, 783 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 784 DLADM_OPT_PERSIST); 785 } else { 786 (void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop); 787 } 788 return (DLADM_STATUS_OK); 789 } 790 791 /* ARGSUSED */ 792 static dladm_status_t 793 do_get_zone(struct prop_desc *pd, datalink_id_t linkid, 794 char **prop_val, uint_t *val_cnt, datalink_media_t media) 795 { 796 char zone_name[ZONENAME_MAX]; 797 zoneid_t zid; 798 dladm_status_t status; 799 800 status = dladm_getzid(linkid, &zid); 801 if (status != DLADM_STATUS_OK) 802 return (status); 803 804 *val_cnt = 1; 805 if (zid != GLOBAL_ZONEID) { 806 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 807 return (dladm_errno2status(errno)); 808 809 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); 810 } else { 811 *prop_val[0] = '\0'; 812 } 813 814 return (DLADM_STATUS_OK); 815 } 816 817 typedef int (*zone_get_devroot_t)(char *, char *, size_t); 818 819 static int 820 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen) 821 { 822 char root[MAXPATHLEN]; 823 zone_get_devroot_t real_zone_get_devroot; 824 void *dlhandle; 825 void *sym; 826 int ret; 827 828 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL) 829 return (-1); 830 831 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) { 832 (void) dlclose(dlhandle); 833 return (-1); 834 } 835 836 real_zone_get_devroot = (zone_get_devroot_t)sym; 837 838 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0) 839 (void) snprintf(dev, devlen, "%s%s", root, "/dev"); 840 (void) dlclose(dlhandle); 841 return (ret); 842 } 843 844 static dladm_status_t 845 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add) 846 { 847 char path[MAXPATHLEN]; 848 char name[MAXLINKNAMELEN]; 849 di_prof_t prof = NULL; 850 char zone_name[ZONENAME_MAX]; 851 dladm_status_t status; 852 int ret; 853 854 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 855 return (dladm_errno2status(errno)); 856 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) 857 return (dladm_errno2status(errno)); 858 if (di_prof_init(path, &prof) != 0) 859 return (dladm_errno2status(errno)); 860 861 status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN); 862 if (status != DLADM_STATUS_OK) 863 goto cleanup; 864 865 if (add) 866 ret = di_prof_add_dev(prof, name); 867 else 868 ret = di_prof_add_exclude(prof, name); 869 870 if (ret != 0) { 871 status = dladm_errno2status(errno); 872 goto cleanup; 873 } 874 875 if (di_prof_commit(prof) != 0) 876 status = dladm_errno2status(errno); 877 cleanup: 878 if (prof) 879 di_prof_fini(prof); 880 881 return (status); 882 } 883 884 /* ARGSUSED */ 885 static dladm_status_t 886 do_set_zone(prop_desc_t *pd, datalink_id_t linkid, val_desc_t *vdp, 887 uint_t val_cnt, uint_t flags, datalink_media_t media) 888 { 889 dladm_status_t status; 890 zoneid_t zid_old, zid_new; 891 char link[MAXLINKNAMELEN]; 892 893 if (val_cnt != 1) 894 return (DLADM_STATUS_BADVALCNT); 895 896 status = dladm_getzid(linkid, &zid_old); 897 if (status != DLADM_STATUS_OK) 898 return (status); 899 900 /* Do nothing if setting to current value */ 901 zid_new = vdp->vd_val; 902 if (zid_new == zid_old) 903 return (DLADM_STATUS_OK); 904 905 if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, 906 link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 907 return (status); 908 } 909 910 if (zid_new != GLOBAL_ZONEID) { 911 /* 912 * If the new zoneid is the global zone, we could destroy 913 * the link (in the case of an implicitly-created VLAN) as a 914 * result of the dladm_setzid() operation. In that case, 915 * we defer the operation to the end of this function to avoid 916 * recreating the VLAN and getting a different linkid during 917 * the rollback if other operation fails. 918 * 919 * Otherwise, dladm_setzid() will hold a reference to the 920 * link and prevent a link renaming, so we need to do it 921 * before other operations. 922 */ 923 status = dladm_setzid(link, zid_new); 924 if (status != DLADM_STATUS_OK) 925 return (status); 926 } 927 928 if (zid_old != GLOBAL_ZONEID) { 929 if (zone_remove_datalink(zid_old, link) != 0 && 930 errno != ENXIO) { 931 status = dladm_errno2status(errno); 932 goto rollback1; 933 } 934 935 /* 936 * It is okay to fail to update the /dev entry (some 937 * vanity-named links do not have a /dev entry). 938 */ 939 (void) i_dladm_update_deventry(zid_old, linkid, B_FALSE); 940 } 941 942 if (zid_new != GLOBAL_ZONEID) { 943 if (zone_add_datalink(zid_new, link) != 0) { 944 status = dladm_errno2status(errno); 945 goto rollback2; 946 } 947 948 (void) i_dladm_update_deventry(zid_new, linkid, B_TRUE); 949 } else { 950 status = dladm_setzid(link, zid_new); 951 if (status != DLADM_STATUS_OK) 952 goto rollback2; 953 } 954 955 return (DLADM_STATUS_OK); 956 957 rollback2: 958 if (zid_old != GLOBAL_ZONEID) 959 (void) i_dladm_update_deventry(zid_old, linkid, B_TRUE); 960 if (zid_old != GLOBAL_ZONEID) 961 (void) zone_add_datalink(zid_old, link); 962 rollback1: 963 if (zid_new != GLOBAL_ZONEID) 964 (void) dladm_setzid(link, zid_old); 965 return (status); 966 } 967 968 /* ARGSUSED */ 969 static dladm_status_t 970 do_check_zone(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, 971 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 972 { 973 zoneid_t zid; 974 975 if (val_cnt != 1) 976 return (DLADM_STATUS_BADVALCNT); 977 978 if ((zid = getzoneidbyname(*prop_val)) == -1) 979 return (DLADM_STATUS_BADVAL); 980 981 if (zid != GLOBAL_ZONEID) { 982 ushort_t flags; 983 984 if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags, 985 sizeof (flags)) < 0) { 986 return (dladm_errno2status(errno)); 987 } 988 989 if (!(flags & ZF_NET_EXCL)) { 990 return (DLADM_STATUS_BADVAL); 991 } 992 } 993 994 vdp->vd_val = zid; 995 return (DLADM_STATUS_OK); 996 } 997 998 /* ARGSUSED */ 999 static dladm_status_t 1000 do_get_autopush(struct prop_desc *pd, datalink_id_t linkid, 1001 char **prop_val, uint_t *val_cnt, datalink_media_t media) 1002 { 1003 dld_ioc_ap_t dia; 1004 int fd, i, len; 1005 1006 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 1007 return (dladm_errno2status(errno)); 1008 1009 *val_cnt = 1; 1010 dia.dia_linkid = linkid; 1011 if (i_dladm_ioctl(fd, DLDIOC_GETAUTOPUSH, &dia, sizeof (dia)) < 0) { 1012 (*prop_val)[0] = '\0'; 1013 goto done; 1014 } 1015 1016 for (i = 0, len = 0; i < dia.dia_npush; i++) { 1017 if (i != 0) { 1018 (void) snprintf(*prop_val + len, 1019 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); 1020 len += 1; 1021 } 1022 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, 1023 "%s", dia.dia_aplist[i]); 1024 len += strlen(dia.dia_aplist[i]); 1025 if (dia.dia_anchor - 1 == i) { 1026 (void) snprintf(*prop_val + len, 1027 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, 1028 AP_ANCHOR); 1029 len += (strlen(AP_ANCHOR) + 1); 1030 } 1031 } 1032 1033 done: 1034 (void) close(fd); 1035 return (DLADM_STATUS_OK); 1036 } 1037 1038 /* ARGSUSED */ 1039 static dladm_status_t 1040 do_set_autopush(prop_desc_t *pd, datalink_id_t linkid, val_desc_t *vdp, 1041 uint_t val_cnt, uint_t flags, datalink_media_t media) 1042 { 1043 dld_ioc_ap_t dia; 1044 struct dlautopush *dlap = (struct dlautopush *)vdp->vd_val; 1045 dladm_status_t status = DLADM_STATUS_OK; 1046 int fd, i; 1047 int ic_cmd; 1048 1049 if (val_cnt != 1) 1050 return (DLADM_STATUS_BADVALCNT); 1051 1052 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 1053 return (dladm_errno2status(errno)); 1054 1055 dia.dia_linkid = linkid; 1056 if (dlap != NULL) { 1057 dia.dia_anchor = dlap->dap_anchor; 1058 dia.dia_npush = dlap->dap_npush; 1059 for (i = 0; i < dia.dia_npush; i++) { 1060 (void) strlcpy(dia.dia_aplist[i], dlap->dap_aplist[i], 1061 FMNAMESZ+1); 1062 } 1063 ic_cmd = DLDIOC_SETAUTOPUSH; 1064 } else { 1065 ic_cmd = DLDIOC_CLRAUTOPUSH; 1066 } 1067 1068 if (i_dladm_ioctl(fd, ic_cmd, &dia, sizeof (dia)) < 0) 1069 status = dladm_errno2status(errno); 1070 1071 (void) close(fd); 1072 return (status); 1073 } 1074 1075 /* 1076 * Add the specified module to the dlautopush structure; returns a 1077 * DLADM_STATUS_* code. 1078 */ 1079 dladm_status_t 1080 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) 1081 { 1082 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) 1083 return (DLADM_STATUS_BADVAL); 1084 1085 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { 1086 /* 1087 * We don't allow multiple anchors, and the anchor must 1088 * be after at least one module. 1089 */ 1090 if (dlap->dap_anchor != 0) 1091 return (DLADM_STATUS_BADVAL); 1092 if (dlap->dap_npush == 0) 1093 return (DLADM_STATUS_BADVAL); 1094 1095 dlap->dap_anchor = dlap->dap_npush; 1096 return (DLADM_STATUS_OK); 1097 } 1098 if (dlap->dap_npush > MAXAPUSH) 1099 return (DLADM_STATUS_BADVALCNT); 1100 1101 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, 1102 FMNAMESZ + 1); 1103 1104 return (DLADM_STATUS_OK); 1105 } 1106 1107 /* 1108 * Currently, both '.' and ' '(space) can be used as the delimiters between 1109 * autopush modules. The former is used in dladm set-linkprop, and the 1110 * latter is used in the autopush(1M) file. 1111 */ 1112 /* ARGSUSED */ 1113 static dladm_status_t 1114 do_check_autopush(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, 1115 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1116 { 1117 char *module; 1118 struct dlautopush *dlap; 1119 dladm_status_t status; 1120 char val[DLADM_PROP_VAL_MAX]; 1121 char delimiters[4]; 1122 1123 if (val_cnt != 1) 1124 return (DLADM_STATUS_BADVALCNT); 1125 1126 dlap = malloc(sizeof (struct dlautopush)); 1127 if (dlap == NULL) 1128 return (DLADM_STATUS_NOMEM); 1129 1130 (void) memset(dlap, 0, sizeof (struct dlautopush)); 1131 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); 1132 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); 1133 module = strtok(val, delimiters); 1134 while (module != NULL) { 1135 status = i_dladm_add_ap_module(module, dlap); 1136 if (status != DLADM_STATUS_OK) 1137 return (status); 1138 module = strtok(NULL, delimiters); 1139 } 1140 1141 vdp->vd_val = (uintptr_t)dlap; 1142 return (DLADM_STATUS_OK); 1143 } 1144 1145 /* ARGSUSED */ 1146 static dladm_status_t 1147 do_get_rate_common(struct prop_desc *pd, datalink_id_t linkid, 1148 char **prop_val, uint_t *val_cnt, uint_t id) 1149 { 1150 wl_rates_t *wrp; 1151 uint_t i; 1152 wldp_t *gbuf = NULL; 1153 dladm_status_t status = DLADM_STATUS_OK; 1154 1155 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 1156 status = DLADM_STATUS_NOMEM; 1157 goto done; 1158 } 1159 1160 status = i_dladm_wlan_get_ioctl(linkid, gbuf, id); 1161 if (status != DLADM_STATUS_OK) 1162 goto done; 1163 1164 wrp = (wl_rates_t *)gbuf->wldp_buf; 1165 if (wrp->wl_rates_num > *val_cnt) { 1166 status = DLADM_STATUS_TOOSMALL; 1167 goto done; 1168 } 1169 1170 if (wrp->wl_rates_rates[0] == 0) { 1171 prop_val[0][0] = '\0'; 1172 *val_cnt = 1; 1173 goto done; 1174 } 1175 1176 for (i = 0; i < wrp->wl_rates_num; i++) { 1177 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 1178 wrp->wl_rates_rates[i] % 2, 1179 (float)wrp->wl_rates_rates[i] / 2); 1180 } 1181 *val_cnt = wrp->wl_rates_num; 1182 1183 done: 1184 free(gbuf); 1185 return (status); 1186 } 1187 1188 static dladm_status_t 1189 do_get_rate_prop(struct prop_desc *pd, datalink_id_t linkid, 1190 char **prop_val, uint_t *val_cnt, datalink_media_t media) 1191 { 1192 if (media != DL_WIFI) 1193 return (dld_speed_get(pd, linkid, prop_val, val_cnt)); 1194 1195 return (do_get_rate_common(pd, linkid, prop_val, val_cnt, 1196 WL_DESIRED_RATES)); 1197 } 1198 1199 static dladm_status_t 1200 do_get_rate_mod(struct prop_desc *pd, datalink_id_t linkid, 1201 char **prop_val, uint_t *val_cnt, datalink_media_t media) 1202 { 1203 int i; 1204 1205 switch (media) { 1206 case DL_ETHER: 1207 if (VALCNT(link_speed_vals) > *val_cnt) 1208 return (DLADM_STATUS_TOOSMALL); 1209 for (i = 0; i < VALCNT(link_speed_vals); i++) 1210 (void) strcpy(prop_val[i], link_speed_vals[i].vd_name); 1211 *val_cnt = VALCNT(link_speed_vals); 1212 return (DLADM_STATUS_OK); 1213 1214 case DL_WIFI: 1215 return (do_get_rate_common(pd, linkid, prop_val, val_cnt, 1216 WL_SUPPORTED_RATES)); 1217 default: 1218 return (DLADM_STATUS_BADARG); 1219 } 1220 } 1221 1222 static dladm_status_t 1223 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates) 1224 { 1225 int i; 1226 uint_t len; 1227 wldp_t *gbuf; 1228 wl_rates_t *wrp; 1229 dladm_status_t status = DLADM_STATUS_OK; 1230 1231 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1232 return (DLADM_STATUS_NOMEM); 1233 1234 (void) memset(gbuf, 0, MAX_BUF_LEN); 1235 1236 wrp = (wl_rates_t *)gbuf->wldp_buf; 1237 for (i = 0; i < rates->wr_cnt; i++) 1238 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 1239 wrp->wl_rates_num = rates->wr_cnt; 1240 1241 len = offsetof(wl_rates_t, wl_rates_rates) + 1242 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 1243 status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len, 1244 WLAN_SET_PARAM, len); 1245 1246 free(gbuf); 1247 return (status); 1248 } 1249 1250 /* ARGSUSED */ 1251 static dladm_status_t 1252 do_set_rate_prop(prop_desc_t *pd, datalink_id_t linkid, 1253 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1254 { 1255 dladm_wlan_rates_t rates; 1256 dladm_status_t status; 1257 1258 /* 1259 * can currently set rate on WIFI links only. 1260 */ 1261 if (media != DL_WIFI) 1262 return (DLADM_STATUS_PROPRDONLY); 1263 1264 if (val_cnt != 1) 1265 return (DLADM_STATUS_BADVALCNT); 1266 1267 rates.wr_cnt = 1; 1268 rates.wr_rates[0] = vdp[0].vd_val; 1269 1270 status = do_set_rate(linkid, &rates); 1271 1272 done: 1273 return (status); 1274 } 1275 1276 /* ARGSUSED */ 1277 static dladm_status_t 1278 do_check_rate(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, 1279 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1280 { 1281 int i; 1282 uint_t modval_cnt = MAX_SUPPORT_RATES; 1283 char *buf, **modval; 1284 dladm_status_t status; 1285 1286 if (val_cnt != 1) 1287 return (DLADM_STATUS_BADVALCNT); 1288 1289 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * 1290 MAX_SUPPORT_RATES); 1291 if (buf == NULL) { 1292 status = DLADM_STATUS_NOMEM; 1293 goto done; 1294 } 1295 1296 modval = (char **)(void *)buf; 1297 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 1298 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 1299 i * DLADM_STRSIZE; 1300 } 1301 1302 status = do_get_rate_mod(NULL, linkid, modval, &modval_cnt, media); 1303 if (status != DLADM_STATUS_OK) 1304 goto done; 1305 1306 for (i = 0; i < modval_cnt; i++) { 1307 if (strcasecmp(*prop_val, modval[i]) == 0) { 1308 vdp->vd_val = (uintptr_t)(uint_t) 1309 (atof(*prop_val) * 2); 1310 status = DLADM_STATUS_OK; 1311 break; 1312 } 1313 } 1314 if (i == modval_cnt) 1315 status = DLADM_STATUS_BADVAL; 1316 done: 1317 free(buf); 1318 return (status); 1319 } 1320 1321 static dladm_status_t 1322 do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf) 1323 { 1324 return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG)); 1325 } 1326 1327 /* ARGSUSED */ 1328 static dladm_status_t 1329 do_get_channel_prop(struct prop_desc *pd, datalink_id_t linkid, 1330 char **prop_val, uint_t *val_cnt, datalink_media_t media) 1331 { 1332 uint32_t channel; 1333 wldp_t *gbuf; 1334 dladm_status_t status = DLADM_STATUS_OK; 1335 1336 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1337 return (DLADM_STATUS_NOMEM); 1338 1339 if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK) 1340 goto done; 1341 1342 if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, 1343 &channel)) { 1344 status = DLADM_STATUS_NOTFOUND; 1345 goto done; 1346 } 1347 1348 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 1349 *val_cnt = 1; 1350 1351 done: 1352 free(gbuf); 1353 return (status); 1354 } 1355 1356 static dladm_status_t 1357 do_get_powermode(datalink_id_t linkid, wldp_t *gbuf) 1358 { 1359 return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE)); 1360 } 1361 1362 /* ARGSUSED */ 1363 static dladm_status_t 1364 do_get_powermode_prop(struct prop_desc *pd, datalink_id_t linkid, 1365 char **prop_val, uint_t *val_cnt, datalink_media_t media) 1366 { 1367 wl_ps_mode_t *mode; 1368 const char *s; 1369 wldp_t *gbuf; 1370 dladm_status_t status = DLADM_STATUS_OK; 1371 1372 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1373 return (DLADM_STATUS_NOMEM); 1374 1375 if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK) 1376 goto done; 1377 1378 mode = (wl_ps_mode_t *)(gbuf->wldp_buf); 1379 switch (mode->wl_ps_mode) { 1380 case WL_PM_AM: 1381 s = "off"; 1382 break; 1383 case WL_PM_MPS: 1384 s = "max"; 1385 break; 1386 case WL_PM_FAST: 1387 s = "fast"; 1388 break; 1389 default: 1390 status = DLADM_STATUS_NOTFOUND; 1391 goto done; 1392 } 1393 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1394 *val_cnt = 1; 1395 1396 done: 1397 free(gbuf); 1398 return (status); 1399 } 1400 1401 static dladm_status_t 1402 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm) 1403 { 1404 wl_ps_mode_t ps_mode; 1405 1406 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 1407 1408 switch (*pm) { 1409 case DLADM_WLAN_PM_OFF: 1410 ps_mode.wl_ps_mode = WL_PM_AM; 1411 break; 1412 case DLADM_WLAN_PM_MAX: 1413 ps_mode.wl_ps_mode = WL_PM_MPS; 1414 break; 1415 case DLADM_WLAN_PM_FAST: 1416 ps_mode.wl_ps_mode = WL_PM_FAST; 1417 break; 1418 default: 1419 return (DLADM_STATUS_NOTSUP); 1420 } 1421 return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode, 1422 sizeof (ps_mode))); 1423 } 1424 1425 /* ARGSUSED */ 1426 static dladm_status_t 1427 do_set_powermode_prop(prop_desc_t *pd, datalink_id_t linkid, 1428 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1429 { 1430 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 1431 dladm_status_t status; 1432 1433 if (val_cnt != 1) 1434 return (DLADM_STATUS_BADVALCNT); 1435 1436 status = do_set_powermode(linkid, &powermode); 1437 1438 return (status); 1439 } 1440 1441 static dladm_status_t 1442 do_get_radio(datalink_id_t linkid, wldp_t *gbuf) 1443 { 1444 return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO)); 1445 } 1446 1447 /* ARGSUSED */ 1448 static dladm_status_t 1449 do_get_radio_prop(struct prop_desc *pd, datalink_id_t linkid, 1450 char **prop_val, uint_t *val_cnt, datalink_media_t media) 1451 { 1452 wl_radio_t radio; 1453 const char *s; 1454 wldp_t *gbuf; 1455 dladm_status_t status = DLADM_STATUS_OK; 1456 1457 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1458 return (DLADM_STATUS_NOMEM); 1459 1460 if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK) 1461 goto done; 1462 1463 radio = *(wl_radio_t *)(gbuf->wldp_buf); 1464 switch (radio) { 1465 case B_TRUE: 1466 s = "on"; 1467 break; 1468 case B_FALSE: 1469 s = "off"; 1470 break; 1471 default: 1472 status = DLADM_STATUS_NOTFOUND; 1473 goto done; 1474 } 1475 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1476 *val_cnt = 1; 1477 1478 done: 1479 free(gbuf); 1480 return (status); 1481 } 1482 1483 static dladm_status_t 1484 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio) 1485 { 1486 wl_radio_t r; 1487 1488 switch (*radio) { 1489 case DLADM_WLAN_RADIO_ON: 1490 r = B_TRUE; 1491 break; 1492 case DLADM_WLAN_RADIO_OFF: 1493 r = B_FALSE; 1494 break; 1495 default: 1496 return (DLADM_STATUS_NOTSUP); 1497 } 1498 return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r))); 1499 } 1500 1501 /* ARGSUSED */ 1502 static dladm_status_t 1503 do_set_radio_prop(prop_desc_t *pd, datalink_id_t linkid, 1504 val_desc_t *vdp, uint_t val_cnt, uint_t fags, datalink_media_t media) 1505 { 1506 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 1507 dladm_status_t status; 1508 1509 if (val_cnt != 1) 1510 return (DLADM_STATUS_BADVALCNT); 1511 1512 status = do_set_radio(linkid, &radio); 1513 1514 return (status); 1515 } 1516 1517 static dladm_status_t 1518 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name, 1519 char **prop_val, uint_t val_cnt) 1520 { 1521 char buf[MAXLINELEN]; 1522 int i; 1523 dladm_conf_t conf; 1524 dladm_status_t status; 1525 1526 status = dladm_read_conf(linkid, &conf); 1527 if (status != DLADM_STATUS_OK) 1528 return (status); 1529 1530 /* 1531 * reset case. 1532 */ 1533 if (val_cnt == 0) { 1534 status = dladm_unset_conf_field(conf, prop_name); 1535 if (status == DLADM_STATUS_OK) 1536 status = dladm_write_conf(conf); 1537 goto done; 1538 } 1539 1540 buf[0] = '\0'; 1541 for (i = 0; i < val_cnt; i++) { 1542 (void) strlcat(buf, prop_val[i], MAXLINELEN); 1543 if (i != val_cnt - 1) 1544 (void) strlcat(buf, ",", MAXLINELEN); 1545 } 1546 1547 status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf); 1548 if (status == DLADM_STATUS_OK) 1549 status = dladm_write_conf(conf); 1550 1551 done: 1552 dladm_destroy_conf(conf); 1553 return (status); 1554 } 1555 1556 static dladm_status_t 1557 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name, 1558 char **prop_val, uint_t *val_cntp) 1559 { 1560 char buf[MAXLINELEN], *str; 1561 uint_t cnt = 0; 1562 dladm_conf_t conf; 1563 dladm_status_t status; 1564 1565 status = dladm_read_conf(linkid, &conf); 1566 if (status != DLADM_STATUS_OK) 1567 return (status); 1568 1569 status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN); 1570 if (status != DLADM_STATUS_OK) 1571 goto done; 1572 1573 str = strtok(buf, ","); 1574 while (str != NULL) { 1575 if (cnt == *val_cntp) { 1576 status = DLADM_STATUS_TOOSMALL; 1577 goto done; 1578 } 1579 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); 1580 str = strtok(NULL, ","); 1581 } 1582 1583 *val_cntp = cnt; 1584 1585 done: 1586 dladm_destroy_conf(conf); 1587 return (status); 1588 } 1589 1590 static dld_public_prop_t * 1591 dladm_name2prop(const char *prop_name) 1592 { 1593 dld_public_prop_t *p; 1594 1595 for (p = dld_prop; p->pp_id != DLD_PROP_PRIVATE; p++) { 1596 if (strcmp(p->pp_name, prop_name) == 0) 1597 break; 1598 } 1599 return (p); 1600 } 1601 1602 1603 static dld_ioc_prop_t * 1604 dld_buf_alloc(size_t valsize, datalink_id_t linkid, const char *prop_name, 1605 dladm_status_t *status) 1606 { 1607 int dsize; 1608 dld_ioc_prop_t *dip; 1609 dld_public_prop_t *p; 1610 1611 *status = DLADM_STATUS_OK; 1612 p = dladm_name2prop(prop_name); 1613 if (p->pp_id != DLD_PROP_PRIVATE) 1614 valsize = p->pp_valsize; 1615 1616 dsize = DLD_PROPBUF_SIZE(valsize); 1617 dip = malloc(dsize); 1618 if (dip == NULL) { 1619 *status = DLADM_STATUS_NOMEM; 1620 return (NULL); 1621 } 1622 bzero(dip, dsize); 1623 dip->pr_valsize = valsize; 1624 (void) strlcpy(dip->pr_name, prop_name, DLD_LINKPROP_NAME_MAX); 1625 dip->pr_version = DLD_PROP_VERSION; 1626 dip->pr_linkid = linkid; 1627 dip->pr_num = p->pp_id; 1628 return (dip); 1629 } 1630 1631 /* ARGSUSED */ 1632 static dladm_status_t 1633 dld_set_public_prop(prop_desc_t *pd, datalink_id_t linkid, 1634 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1635 { 1636 dld_ioc_prop_t *dip; 1637 int fd, dsize; 1638 dladm_status_t status = DLADM_STATUS_OK; 1639 uint8_t u8; 1640 uint16_t u16; 1641 uint32_t u32; 1642 void *val; 1643 1644 dip = dld_buf_alloc(0, linkid, pd->pd_name, &status); 1645 if (dip == NULL) 1646 return (status); 1647 1648 if (pd->pd_flags & PD_CHECK_ALLOC) 1649 val = (void *)vdp->vd_val; 1650 else { 1651 /* 1652 * Currently all 1/2/4-byte size properties are byte/word/int. 1653 * No need (yet) to distinguish these from arrays of same size. 1654 */ 1655 switch (dip->pr_valsize) { 1656 case 1: 1657 u8 = vdp->vd_val; 1658 val = &u8; 1659 break; 1660 case 2: 1661 u16 = vdp->vd_val; 1662 val = &u16; 1663 break; 1664 case 4: 1665 u32 = vdp->vd_val; 1666 val = &u32; 1667 break; 1668 default: 1669 val = &vdp->vd_val; 1670 break; 1671 } 1672 } 1673 1674 (void) memcpy(dip->pr_val, val, dip->pr_valsize); 1675 dsize = DLD_PROPBUF_SIZE(dip->pr_valsize); 1676 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { 1677 status = dladm_errno2status(errno); 1678 goto done; 1679 } 1680 if (i_dladm_ioctl(fd, DLDIOCSETPROP, dip, dsize) < 0) 1681 status = dladm_errno2status(errno); 1682 1683 (void) close(fd); 1684 done: 1685 return (status); 1686 } 1687 1688 static dladm_status_t 1689 dld_get_public_prop(dld_ioc_prop_t *dip) 1690 { 1691 int fd, dsize; 1692 dladm_status_t status = DLADM_STATUS_OK; 1693 1694 dsize = DLD_PROPBUF_SIZE(dip->pr_valsize); 1695 1696 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { 1697 status = dladm_errno2status(errno); 1698 goto done; 1699 } 1700 if (i_dladm_ioctl(fd, DLDIOCGETPROP, dip, dsize) < 0) { 1701 status = dladm_errno2status(errno); 1702 } 1703 done: 1704 return (status); 1705 } 1706 1707 /* ARGSUSED */ 1708 static dladm_status_t 1709 dld_defmtu_check(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, 1710 uint_t val_cnt, val_desc_t *v, datalink_media_t media) 1711 { 1712 uint64_t mtu; 1713 1714 if (val_cnt != 1) 1715 return (DLADM_STATUS_BADVAL); 1716 mtu = atoll(prop_val[0]); 1717 v->vd_val = (uintptr_t)malloc(sizeof (uint64_t)); 1718 if ((void *)v->vd_val == NULL) 1719 return (DLADM_STATUS_NOMEM); 1720 bcopy(&mtu, (void *)v->vd_val, sizeof (mtu)); 1721 return (DLADM_STATUS_OK); 1722 } 1723 1724 /* ARGSUSED */ 1725 static dladm_status_t 1726 dld_duplex_get(struct prop_desc *pd, datalink_id_t linkid, 1727 char **prop_val, uint_t *val_cnt, datalink_media_t media) 1728 { 1729 link_duplex_t link_duplex; 1730 dladm_status_t status; 1731 1732 if ((status = dladm_get_single_mac_stat(linkid, "link_duplex", 1733 KSTAT_DATA_UINT32, &link_duplex)) != 0) 1734 return (status); 1735 1736 switch (link_duplex) { 1737 case LINK_DUPLEX_FULL: 1738 (void) strcpy(*prop_val, "full"); 1739 break; 1740 case LINK_DUPLEX_HALF: 1741 (void) strcpy(*prop_val, "half"); 1742 break; 1743 default: 1744 (void) strcpy(*prop_val, "unknown"); 1745 break; 1746 } 1747 *val_cnt = 1; 1748 return (DLADM_STATUS_OK); 1749 } 1750 1751 /* ARGSUSED */ 1752 static dladm_status_t 1753 dld_speed_get(struct prop_desc *pd, datalink_id_t linkid, 1754 char **prop_val, uint_t *val_cnt) 1755 { 1756 uint64_t ifspeed = 0; 1757 dladm_status_t status; 1758 1759 if ((status = dladm_get_single_mac_stat(linkid, "ifspeed", 1760 KSTAT_DATA_UINT64, &ifspeed)) != 0) 1761 return (status); 1762 if ((ifspeed % 1000000) != 0) { 1763 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 1764 "%llf", ifspeed / (float)1000000); /* Mbps */ 1765 } else { 1766 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 1767 "%llu", ifspeed / 1000000); /* Mbps */ 1768 } 1769 *val_cnt = 1; 1770 return (DLADM_STATUS_OK); 1771 } 1772 1773 /* ARGSUSED */ 1774 static dladm_status_t 1775 dld_status_get(struct prop_desc *pd, datalink_id_t linkid, 1776 char **prop_val, uint_t *val_cnt, datalink_media_t media) 1777 { 1778 link_state_t link_state; 1779 dladm_status_t status; 1780 1781 if ((status = dladm_get_single_mac_stat(linkid, "link_state", 1782 KSTAT_DATA_UINT32, &link_state)) != 0) 1783 return (status); 1784 1785 switch (link_state) { 1786 case LINK_STATE_UP: 1787 (void) strcpy(*prop_val, "up"); 1788 break; 1789 case LINK_STATE_DOWN: 1790 (void) strcpy(*prop_val, "down"); 1791 break; 1792 default: 1793 (void) strcpy(*prop_val, "unknown"); 1794 break; 1795 } 1796 *val_cnt = 1; 1797 return (DLADM_STATUS_OK); 1798 } 1799 1800 /* ARGSUSED */ 1801 static dladm_status_t 1802 dld_binary_get(struct prop_desc *pd, datalink_id_t linkid, 1803 char **prop_val, uint_t *val_cnt, datalink_media_t media) 1804 { 1805 dld_ioc_prop_t *dip; 1806 dladm_status_t status; 1807 1808 if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL) 1809 return (status); 1810 if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) { 1811 free(dip); 1812 return (status); 1813 } 1814 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]); 1815 free(dip); 1816 *val_cnt = 1; 1817 return (DLADM_STATUS_OK); 1818 } 1819 1820 /* ARGSUSED */ 1821 static dladm_status_t 1822 dld_uint64_get(struct prop_desc *pd, datalink_id_t linkid, 1823 char **prop_val, uint_t *val_cnt, datalink_media_t media) 1824 { 1825 dld_ioc_prop_t *dip; 1826 uint64_t v = 0; 1827 uchar_t *cp; 1828 dladm_status_t status; 1829 1830 if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL) 1831 return (status); 1832 if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) { 1833 free(dip); 1834 return (status); 1835 } 1836 cp = (uchar_t *)dip->pr_val; 1837 (void) memcpy(&v, cp, sizeof (v)); 1838 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%" PRIu64, v); 1839 free(dip); 1840 *val_cnt = 1; 1841 return (DLADM_STATUS_OK); 1842 } 1843 1844 /* ARGSUSED */ 1845 static dladm_status_t 1846 dld_flowctl_get(struct prop_desc *pd, datalink_id_t linkid, 1847 char **prop_val, uint_t *val_cnt, datalink_media_t media) 1848 { 1849 dld_ioc_prop_t *dip; 1850 link_flowctrl_t v; 1851 dladm_status_t status; 1852 uchar_t *cp; 1853 1854 if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL) 1855 return (status); 1856 1857 if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) { 1858 free(dip); 1859 return (status); 1860 } 1861 cp = (uchar_t *)dip->pr_val; 1862 (void) memcpy(&v, cp, sizeof (v)); 1863 switch (v) { 1864 case LINK_FLOWCTRL_NONE: 1865 (void) sprintf(*prop_val, "no"); 1866 break; 1867 case LINK_FLOWCTRL_RX: 1868 (void) sprintf(*prop_val, "rx"); 1869 break; 1870 case LINK_FLOWCTRL_TX: 1871 (void) sprintf(*prop_val, "tx"); 1872 break; 1873 case LINK_FLOWCTRL_BI: 1874 (void) sprintf(*prop_val, "bi"); 1875 break; 1876 } 1877 free(dip); 1878 *val_cnt = 1; 1879 return (DLADM_STATUS_OK); 1880 } 1881 1882 1883 /* ARGSUSED */ 1884 static dladm_status_t 1885 dld_set_prop(datalink_id_t linkid, const char *prop_name, 1886 char **prop_val, uint_t val_cnt, uint_t flags) 1887 { 1888 int fd, i, slen; 1889 int bufsize = 0, dsize; 1890 dld_ioc_prop_t *dip = NULL; 1891 uchar_t *dp; 1892 dld_public_prop_t *p; 1893 dladm_status_t status; 1894 1895 if ((prop_name == NULL && prop_val != NULL) || 1896 (prop_val != NULL && val_cnt == 0)) 1897 return (DLADM_STATUS_BADARG); 1898 p = dladm_name2prop(prop_name); 1899 if (p->pp_id != DLD_PROP_PRIVATE) 1900 return (DLADM_STATUS_BADARG); 1901 1902 /* 1903 * private properties: all parsing is done in the kernel. 1904 * allocate a enough space for each property + its separator (','). 1905 */ 1906 for (i = 0; i < val_cnt; i++) { 1907 bufsize += strlen(prop_val[i]) + 1; 1908 } 1909 dip = dld_buf_alloc(bufsize + 1, linkid, prop_name, &status); 1910 if (dip == NULL) 1911 return (status); 1912 1913 dp = (uchar_t *)dip->pr_val; 1914 dsize = sizeof (dld_ioc_prop_t) + bufsize; 1915 slen = 0; 1916 for (i = 0; i < val_cnt; i++) { 1917 int plen = 0; 1918 1919 plen = strlen(prop_val[i]); 1920 bcopy(prop_val[i], dp, plen); 1921 slen += plen; 1922 /* 1923 * add a "," separator and update dp. 1924 */ 1925 if (i != (val_cnt -1)) 1926 dp[slen++] = ','; 1927 dp += (plen + 1); 1928 } 1929 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { 1930 free(dip); 1931 return (dladm_errno2status(errno)); 1932 } 1933 if ((status = i_dladm_ioctl(fd, DLDIOCSETPROP, dip, dsize)) < 0) { 1934 free(dip); 1935 return (status); 1936 } 1937 free(dip); 1938 (void) close(fd); 1939 return (DLADM_STATUS_OK); 1940 } 1941 1942 static dladm_status_t 1943 dld_get_prop(datalink_id_t linkid, const char *prop_name, 1944 char **prop_val, uint_t *val_cnt, dladm_prop_type_t type) 1945 { 1946 int fd; 1947 dladm_status_t status = DLADM_STATUS_OK; 1948 uint_t dsize; 1949 dld_ioc_prop_t *dip = NULL; 1950 dld_public_prop_t *p; 1951 char tmp = '\0'; 1952 1953 if ((prop_name == NULL && prop_val != NULL) || 1954 (prop_val != NULL && val_cnt == 0)) 1955 return (DLADM_STATUS_BADARG); 1956 1957 p = dladm_name2prop(prop_name); 1958 if (p->pp_id != DLD_PROP_PRIVATE) 1959 return (DLADM_STATUS_BADARG); 1960 1961 if (type == DLADM_PROP_VAL_DEFAULT || 1962 type == DLADM_PROP_VAL_MODIFIABLE) { 1963 *prop_val = &tmp; 1964 *val_cnt = 1; 1965 return (DLADM_STATUS_OK); 1966 } 1967 1968 /* 1969 * private properties: all parsing is done in the kernel. 1970 */ 1971 dip = dld_buf_alloc(1024, linkid, prop_name, &status); 1972 if (dip == NULL) 1973 return (status); 1974 dsize = DLD_PROPBUF_SIZE(dip->pr_valsize); 1975 1976 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 1977 return (DLADM_STATUS_BADARG); 1978 1979 if ((status = i_dladm_ioctl(fd, DLDIOCGETPROP, dip, dsize)) < 0) { 1980 status = dladm_errno2status(errno); 1981 } else { 1982 (void) strncpy(*prop_val, dip->pr_val, DLADM_PROP_VAL_MAX); 1983 *val_cnt = 1; 1984 } 1985 return (status); 1986 } 1987