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 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * The SNMP picl plugin connects to the agent on the SP and creates 31 * and populates the /physical-platform subtree in picl tree for use 32 * by picl consumers. 33 */ 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <syslog.h> 39 #include <stdarg.h> 40 #include <libgen.h> 41 #include <libintl.h> 42 #include <thread.h> 43 #include <synch.h> 44 #include <errno.h> 45 46 #include <picldefs.h> 47 #include <picl.h> 48 #include <picltree.h> 49 50 #include "picloids.h" 51 #include "libpiclsnmp.h" 52 #include "snmpplugin.h" 53 54 #pragma init(snmpplugin_register) /* place in .init section */ 55 56 picld_plugin_reg_t snmpplugin_reg = { 57 PICLD_PLUGIN_VERSION_1, 58 PICLD_PLUGIN_NON_CRITICAL, 59 "snmp_plugin", 60 snmpplugin_init, 61 snmpplugin_fini 62 }; 63 64 static picl_snmphdl_t hdl; 65 66 /* 67 * The stale_tree_rwlp protects the stale_xxx vars. The 'stale_tree' flag 68 * and the 'rebuild_tree' flag below are both initialized to B_TRUE to 69 * let the tree_builder() thread build the initial tree without blocking. 70 */ 71 static rwlock_t stale_tree_rwlp; 72 static boolean_t stale_tree = B_TRUE; 73 74 /* 75 * vol_props, volprop_ndx and n_vol_props are protected by the stale_tree 76 * flag. They are read only when the stale_tree flag is B_FALSE and written 77 * to only when the flag is B_TRUE. 78 * 79 * The change_time (last changed time) is read by only one thread at a 80 * time when stale_tree is B_FALSE (protected by stale_tree_rwlp). It is 81 * written by only one thread (the tree builder) when stale_tree is B_TRUE. 82 * 83 * Note that strictly speaking, change_time should be uint_t (timeticks32). 84 * But keeping it as int is fine, since we don't do any arithmetic on it 85 * except equality check. 86 */ 87 static vol_prophdl_t *vol_props = NULL; 88 static int volprop_ndx = 0, n_vol_props = 0; 89 static int change_time = 0; 90 91 /* 92 * The rebuild_tree_lock and cv are used by the tree builder thread. 93 * rebuild_tree has to be initialized to B_TRUE to let the tree_builder 94 * do the first build without blocking. 95 */ 96 static mutex_t rebuild_tree_lock; 97 static cond_t rebuild_tree_cv; 98 static boolean_t rebuild_tree = B_TRUE; 99 100 /* 101 * These two should really not be global 102 */ 103 static picl_nodehdl_t *physplat_nodes = NULL; 104 static int n_physplat_nodes = 0; 105 106 static char *group1[] = { 107 OID_entPhysicalDescr, 108 OID_entPhysicalContainedIn, 109 OID_entPhysicalClass, 110 OID_entPhysicalName, 111 OID_entPhysicalHardwareRev, 112 OID_entPhysicalFirmwareRev, 113 OID_entPhysicalSerialNum, 114 OID_entPhysicalMfgName, 115 OID_entPhysicalModelName, 116 OID_entPhysicalIsFRU, 117 0 118 }; 119 120 static char *group2[] = { 121 OID_sunPlatEquipmentHolderAcceptableTypes, 122 OID_sunPlatCircuitPackReplaceable, 123 OID_sunPlatCircuitPackHotSwappable, 124 OID_sunPlatPhysicalClass, 125 OID_sunPlatSensorClass, 126 OID_sunPlatSensorType, 127 OID_sunPlatAlarmType, 128 OID_sunPlatPowerSupplyClass, 129 0 130 }; 131 132 static char *volgroup1[] = { 133 OID_sunPlatBinarySensorCurrent, 134 OID_sunPlatBinarySensorExpected, 135 OID_sunPlatBinarySensorInterpretTrue, 136 OID_sunPlatBinarySensorInterpretFalse, 137 0 138 }; 139 140 static char *volgroup2[] = { 141 OID_sunPlatNumericSensorBaseUnits, 142 OID_sunPlatNumericSensorExponent, 143 OID_sunPlatNumericSensorRateUnits, 144 OID_sunPlatNumericSensorCurrent, 145 OID_sunPlatNumericSensorLowerThresholdFatal, 146 OID_sunPlatNumericSensorLowerThresholdCritical, 147 OID_sunPlatNumericSensorLowerThresholdNonCritical, 148 OID_sunPlatNumericSensorUpperThresholdNonCritical, 149 OID_sunPlatNumericSensorUpperThresholdCritical, 150 OID_sunPlatNumericSensorUpperThresholdFatal, 151 0 152 }; 153 154 /* 155 * The following two items must match the Sun Platform MIB specification 156 * in their indices and values. 157 */ 158 static char *sensor_baseunits[] = { 159 "", "other", "unknown", "degC", "degF", "degK", "volts", "amps", 160 "watts", "joules", "coulombs", "va", "nits", "lumens", "lux", 161 "candelas", "kPa", "psi", "newtons", "cfm", "rpm", "hertz", 162 "seconds", "minutes", "hours", "days", "weeks", "mils", "inches", 163 "feet", "cubicInches", "cubicFeet", "meters", "cubicCentimeters", 164 "cubicMeters", "liters", "fluidOunces", "radians", "steradians", 165 "revolutions", "cycles", "gravities", "ounces", "pounds", "footPounds", 166 "ounceInches", "gauss", "gilberts", "henries", "farads", "ohms", 167 "siemens", "moles", "becquerels", "ppm", "decibels", "dBA", "dbC", 168 "grays", "sieverts", "colorTemperatureDegK", "bits", "bytes", "words", 169 "doubleWords", "quadWords", "percentage" 170 }; 171 static const int n_baseunits = sizeof (sensor_baseunits) / sizeof (char *); 172 173 static char *sensor_rateunits[] = { 174 "", 175 "none", 176 "perMicroSecond", 177 "perMilliSecond", 178 "perSecond", 179 "perMinute", 180 "perHour", 181 "perDay", 182 "perWeek", 183 "perMonth", 184 "perYear" 185 }; 186 static const int n_rateunits = sizeof (sensor_rateunits) / sizeof (char *); 187 188 /* 189 * Local declarations 190 */ 191 static void snmpplugin_register(void); 192 static void register_group(char **g, int is_volatile); 193 static void *tree_builder(void *arg); 194 static int build_physplat(picl_nodehdl_t *subtree_rootp); 195 static void free_resources(picl_nodehdl_t subtree_root); 196 197 static picl_nodehdl_t make_node(picl_nodehdl_t subtree_root, int row, 198 int *snmp_syserr_p); 199 static void save_nodeh(picl_nodehdl_t nodeh, int row); 200 static picl_nodehdl_t lookup_nodeh(int row); 201 202 static void save_volprop(picl_prophdl_t prop, char *oidstr, int row, 203 int proptype); 204 static void check_for_stale_data(void); 205 static int read_volprop(ptree_rarg_t *parg, void *buf); 206 207 static void threshold(picl_nodehdl_t node, char *oidstr, int row, 208 char *propname, int *snmp_syserr_p); 209 static void add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p); 210 211 static char *get_slot_type(int row, int *snmp_syserr_p); 212 static int add_volatile_prop(picl_nodehdl_t nodeh, char *name, 213 int type, int access, int size, int (*rdfunc)(ptree_rarg_t *, void *), 214 int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp); 215 static int add_string_prop(picl_nodehdl_t node, char *propname, char *propval); 216 static int add_void_prop(picl_nodehdl_t node, char *propname); 217 static int add_int_prop(picl_nodehdl_t node, char *propname, int val); 218 static void add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label, 219 int row, sp_propid_t pp, int *snmp_syserr_p); 220 221 static void log_msg(int pri, const char *fmt, ...); 222 223 #ifdef SNMPPLUGIN_DEBUG 224 static mutex_t snmpplugin_dbuf_lock; 225 static char *snmpplugin_dbuf = NULL; 226 static char *snmpplugin_dbuf_curp = NULL; 227 static int snmpplugin_dbuf_sz = 0; 228 static int snmpplugin_dbuf_overflow = 0; 229 static char snmpplugin_lbuf[SNMPPLUGIN_DMAX_LINE]; 230 231 static void snmpplugin_log_init(void); 232 static void snmpplugin_log(const char *fmt, ...); 233 static void snmpplugin_log_append(void); 234 static void snmpplugin_dbuf_realloc(void); 235 #endif 236 237 static void 238 snmpplugin_register(void) 239 { 240 (void) picld_plugin_register(&snmpplugin_reg); 241 } 242 243 static void 244 register_group(char **g, int is_volatile) 245 { 246 int i, len = 0; 247 int n_oids; 248 char *p, *oidstrs; 249 250 for (i = 0; g[i]; i++) 251 len += strlen(g[i]) + 1; 252 n_oids = i; 253 254 if ((oidstrs = (char *)calloc(1, len)) == NULL) 255 return; 256 257 for (p = oidstrs, i = 0; g[i]; i++) { 258 (void) strcpy(p, g[i]); 259 p += strlen(g[i]) + 1; 260 } 261 262 snmp_register_group(hdl, oidstrs, n_oids, is_volatile); 263 } 264 265 void 266 snmpplugin_init(void) 267 { 268 int ret; 269 270 (void) mutex_init(&rebuild_tree_lock, USYNC_THREAD, NULL); 271 (void) cond_init(&rebuild_tree_cv, USYNC_THREAD, NULL); 272 (void) rwlock_init(&stale_tree_rwlp, USYNC_THREAD, NULL); 273 LOGINIT(); 274 275 /* 276 * Create the tree-builder thread and let it take over 277 */ 278 LOGPRINTF("Tree-builder thread being created.\n"); 279 if ((ret = thr_create(NULL, NULL, tree_builder, NULL, 280 THR_BOUND, NULL)) < 0) { 281 log_msg(LOG_ERR, SNMPP_CANT_CREATE_TREE_BUILDER, ret); 282 snmp_fini(hdl); 283 return; 284 } 285 } 286 287 void 288 snmpplugin_fini(void) 289 { 290 snmp_fini(hdl); 291 292 (void) rwlock_destroy(&stale_tree_rwlp); 293 (void) cond_destroy(&rebuild_tree_cv); 294 (void) mutex_destroy(&rebuild_tree_lock); 295 } 296 297 /*ARGSUSED*/ 298 static void * 299 tree_builder(void *arg) 300 { 301 int ret, rv; 302 picl_nodehdl_t root_node; 303 picl_nodehdl_t physplat_root; 304 picl_nodehdl_t old_physplat_root; 305 306 /* 307 * Initialize SNMP service 308 */ 309 LOGPRINTF("Initializing SNMP service.\n"); 310 if ((hdl = snmp_init()) == NULL) { 311 log_msg(LOG_ERR, SNMPP_CANT_INIT); 312 return ((void *)-1); 313 } 314 315 /* 316 * Register OID groupings for BULKGET optimizations 317 */ 318 LOGPRINTF("Registering OID groups.\n"); 319 register_group(group1, 0); 320 register_group(group2, 0); 321 register_group(volgroup1, 1); 322 register_group(volgroup2, 1); 323 324 (void) mutex_lock(&rebuild_tree_lock); 325 326 for (;;) { 327 LOGPRINTF("tree_builder: check whether to rebuild subtree\n"); 328 while (rebuild_tree == B_FALSE) 329 (void) cond_wait(&rebuild_tree_cv, &rebuild_tree_lock); 330 331 LOGPRINTF("tree_builder: woke up\n"); 332 333 old_physplat_root = NULL; 334 physplat_root = NULL; 335 336 LOGPRINTF("tree_builder: getting root node\n"); 337 if ((ret = ptree_get_root(&root_node)) != PICL_SUCCESS) { 338 log_msg(LOG_ERR, SNMPP_NO_ROOT, ret); 339 return ((void *)-2); 340 } 341 342 LOGPRINTF("tree_builder: getting existing physplat node\n"); 343 rv = ptree_find_node(root_node, PICL_PROP_NAME, 344 PICL_PTYPE_CHARSTRING, PICL_NODE_PHYSPLAT, 345 sizeof (PICL_NODE_PHYSPLAT), &old_physplat_root); 346 347 LOGPRINTF("tree_builder: building physical-platform\n"); 348 if ((ret = build_physplat(&physplat_root)) < 0) { 349 log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret); 350 snmp_fini(hdl); 351 return ((void *)-3); 352 } 353 354 if (rv == PICL_SUCCESS && old_physplat_root != NULL) { 355 LOGPRINTF("tree_builder: destroying existing nodes\n"); 356 ptree_delete_node(old_physplat_root); 357 ptree_destroy_node(old_physplat_root); 358 } 359 360 LOGPRINTF("tree_builder: attaching new subtree\n"); 361 if ((ret = ptree_add_node(root_node, physplat_root)) < 0) { 362 free_resources(physplat_root); 363 log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret); 364 snmp_fini(hdl); 365 return ((void *)-4); 366 } 367 368 LOGPRINTF("tree_builder: setting stale_tree to FALSE\n"); 369 (void) rw_wrlock(&stale_tree_rwlp); 370 stale_tree = B_FALSE; 371 (void) rw_unlock(&stale_tree_rwlp); 372 373 LOGPRINTF("tree_builder: setting rebuild_tree to FALSE\n"); 374 rebuild_tree = B_FALSE; 375 } 376 377 /*NOTREACHED*/ 378 return (NULL); 379 } 380 381 static int 382 build_physplat(picl_nodehdl_t *subtree_rootp) 383 { 384 int change_time1; 385 int row, nxtrow; 386 int clr_linkreset = 0; 387 int ret = 0; 388 int snmp_syserr = 0; 389 390 retry: 391 (void) snmp_reinit(hdl, clr_linkreset); 392 clr_linkreset = 0; 393 394 /* 395 * Record LastChangeTime before we start building the tree 396 */ 397 ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, 398 &change_time1, &snmp_syserr); 399 if (ret < 0) { 400 if (snmp_syserr == ECANCELED) { 401 log_msg(LOG_WARNING, SNMPP_LINK_RESET); 402 clr_linkreset = 1; 403 goto retry; 404 } else 405 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret); 406 } 407 408 /* 409 * Create the physical-platform node 410 */ 411 ret = ptree_create_node(PICL_NODE_PHYSPLAT, PICL_CLASS_PICL, 412 subtree_rootp); 413 if (ret != PICL_SUCCESS) 414 return (-1); 415 416 /* 417 * Scan entPhysicalTable and build the "physical-platform" subtree 418 */ 419 ret = 0; 420 for (row = -1; ret == 0; row = nxtrow) { 421 ret = snmp_get_nextrow(hdl, OID_entPhysicalDescr, 422 row, &nxtrow, &snmp_syserr); 423 if (ret == 0) { 424 (void) make_node(*subtree_rootp, nxtrow, &snmp_syserr); 425 } 426 427 if (snmp_syserr == ECANCELED) { 428 /* 429 * If we get this error, a link reset must've 430 * happened and we need to throw away everything 431 * we have now and rebuild the tree again. 432 */ 433 log_msg(LOG_WARNING, SNMPP_LINK_RESET); 434 free_resources(*subtree_rootp); 435 clr_linkreset = 1; 436 goto retry; 437 } 438 } 439 440 /* 441 * Record LastChangeTime after we're done building the tree 442 */ 443 ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, 444 &change_time, &snmp_syserr); 445 if (ret < 0) { 446 if (snmp_syserr == ECANCELED) { 447 log_msg(LOG_WARNING, SNMPP_LINK_RESET); 448 free_resources(*subtree_rootp); 449 clr_linkreset = 1; 450 goto retry; 451 } else 452 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret); 453 } 454 455 /* 456 * If they don't match, some hotplugging must've happened, 457 * free resources we've created and still holding, then go 458 * back and retry 459 */ 460 if (change_time != change_time1) { 461 LOGPRINTF("build_physplat: entLastChangeTime has changed!\n"); 462 free_resources(*subtree_rootp); 463 change_time1 = change_time; 464 goto retry; 465 } 466 467 /* 468 * The physplat_nodes table is no longer needed, free it 469 */ 470 if (physplat_nodes) { 471 free(physplat_nodes); 472 physplat_nodes = NULL; 473 n_physplat_nodes = 0; 474 } 475 476 return (0); 477 } 478 479 /* 480 * Destroy all resources that were created during the building 481 * of the subtree 482 */ 483 static void 484 free_resources(picl_nodehdl_t subtree_root) 485 { 486 if (physplat_nodes) { 487 free(physplat_nodes); 488 physplat_nodes = NULL; 489 n_physplat_nodes = 0; 490 } 491 492 if (subtree_root) { 493 (void) ptree_delete_node(subtree_root); 494 (void) ptree_destroy_node(subtree_root); 495 } 496 497 if (vol_props) { 498 free(vol_props); 499 n_vol_props = 0; 500 volprop_ndx = 0; 501 } 502 } 503 504 static picl_nodehdl_t 505 make_node(picl_nodehdl_t subtree_root, int row, int *snmp_syserr_p) 506 { 507 picl_nodehdl_t nodeh, parenth; 508 picl_prophdl_t proph; 509 char *phys_name, *node_name; 510 int parent_row; 511 int ent_physclass, sunplat_physclass; 512 int sensor_class, sensor_type; 513 int alarm_type; 514 int ps_class; 515 int ret; 516 517 /* 518 * If we've already created this picl node, just return it 519 */ 520 if ((nodeh = lookup_nodeh(row)) != NULL) 521 return (nodeh); 522 523 /* 524 * If we are creating it only now, make sure we have the parent 525 * created first; if there's no parent, then parent it to the 526 * subtree's root node 527 */ 528 ret = snmp_get_int(hdl, OID_entPhysicalContainedIn, row, 529 &parent_row, snmp_syserr_p); 530 CHECK_LINKRESET(snmp_syserr_p, NULL) 531 if (ret < 0 || parent_row <= 0) 532 parenth = subtree_root; 533 else { 534 parenth = make_node(subtree_root, parent_row, snmp_syserr_p); 535 CHECK_LINKRESET(snmp_syserr_p, NULL) 536 if (parenth == NULL) 537 parenth = subtree_root; 538 } 539 540 /* 541 * Figure out the physical-platform node name from entPhysicalName; 542 * all rows in the MIB that have a valid entPhysicalIndex should 543 * have a physical name. 544 */ 545 ret = snmp_get_str(hdl, OID_entPhysicalName, row, 546 &phys_name, snmp_syserr_p); 547 CHECK_LINKRESET(snmp_syserr_p, NULL) 548 if (ret < 0 || phys_name == NULL) { 549 log_msg(LOG_WARNING, SNMPP_NO_ENTPHYSNAME, row); 550 return (NULL); 551 } 552 553 node_name = basename(phys_name); 554 555 ret = snmp_get_int(hdl, OID_entPhysicalClass, row, 556 &ent_physclass, snmp_syserr_p); 557 CHECK_LINKRESET(snmp_syserr_p, NULL) 558 if (ret < 0) { 559 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret); 560 free(phys_name); 561 return (NULL); 562 } 563 564 switch (ent_physclass) { 565 case SPC_OTHER: 566 ret = snmp_get_int(hdl, OID_sunPlatPhysicalClass, row, 567 &sunplat_physclass, snmp_syserr_p); 568 CHECK_LINKRESET(snmp_syserr_p, NULL) 569 if (ret < 0) { 570 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret); 571 free(phys_name); 572 return (NULL); 573 } 574 575 if (sunplat_physclass == SSPC_ALARM) { 576 ret = snmp_get_int(hdl, OID_sunPlatAlarmType, 577 row, &alarm_type, snmp_syserr_p); 578 CHECK_LINKRESET(snmp_syserr_p, NULL) 579 if (ret < 0) { 580 log_msg(LOG_WARNING, 581 SNMPP_CANT_FETCH_OBJECT_VAL, ret); 582 free(phys_name); 583 return (NULL); 584 } 585 586 if (alarm_type == SSAT_VISIBLE) { 587 ADD_NODE(PICL_CLASS_LED) 588 } else { 589 ADD_NODE(PICL_CLASS_ALARM) 590 } 591 592 add_prop(nodeh, &proph, node_name, row, PP_STATE, 593 snmp_syserr_p); 594 CHECK_LINKRESET(snmp_syserr_p, NULL) 595 } else { 596 ADD_NODE(PICL_CLASS_OTHER) 597 } 598 599 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 600 snmp_syserr_p); 601 CHECK_LINKRESET(snmp_syserr_p, NULL) 602 break; 603 604 case SPC_UNKNOWN: 605 ADD_NODE(PICL_CLASS_UNKNOWN) 606 break; 607 608 case SPC_CHASSIS: 609 ADD_NODE(PICL_CLASS_CHASSIS) 610 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 611 snmp_syserr_p); 612 CHECK_LINKRESET(snmp_syserr_p, NULL) 613 break; 614 615 case SPC_BACKPLANE: 616 ADD_NODE(PICL_CLASS_BACKPLANE) 617 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 618 snmp_syserr_p); 619 CHECK_LINKRESET(snmp_syserr_p, NULL) 620 break; 621 622 case SPC_CONTAINER: 623 ADD_NODE(PICL_CLASS_CONTAINER) 624 625 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 626 snmp_syserr_p); 627 CHECK_LINKRESET(snmp_syserr_p, NULL) 628 629 add_prop(nodeh, &proph, node_name, row, PP_SLOT_TYPE, 630 snmp_syserr_p); 631 CHECK_LINKRESET(snmp_syserr_p, NULL) 632 break; 633 634 case SPC_POWERSUPPLY: 635 ret = snmp_get_int(hdl, OID_sunPlatPowerSupplyClass, 636 row, &ps_class, snmp_syserr_p); 637 CHECK_LINKRESET(snmp_syserr_p, NULL) 638 if (ret < 0) { 639 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret); 640 free(phys_name); 641 return (NULL); 642 } 643 644 if (ps_class == SSPSC_BATTERY) { 645 ADD_NODE(PICL_CLASS_BATTERY) 646 add_prop(nodeh, &proph, node_name, row, 647 PP_BATT_STATUS, snmp_syserr_p); 648 CHECK_LINKRESET(snmp_syserr_p, NULL) 649 } else { 650 ADD_NODE(PICL_CLASS_POWERSUPPLY) 651 } 652 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 653 snmp_syserr_p); 654 CHECK_LINKRESET(snmp_syserr_p, NULL) 655 break; 656 657 case SPC_FAN: 658 ADD_NODE(PICL_CLASS_FAN) 659 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 660 snmp_syserr_p); 661 CHECK_LINKRESET(snmp_syserr_p, NULL) 662 break; 663 664 case SPC_SENSOR: 665 ret = snmp_get_int(hdl, OID_sunPlatSensorClass, 666 row, &sensor_class, snmp_syserr_p); 667 CHECK_LINKRESET(snmp_syserr_p, NULL) 668 if (ret < 0) { 669 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret); 670 free(phys_name); 671 return (NULL); 672 } 673 674 ret = snmp_get_int(hdl, OID_sunPlatSensorType, 675 row, &sensor_type, snmp_syserr_p); 676 CHECK_LINKRESET(snmp_syserr_p, NULL) 677 if (ret < 0) { 678 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret); 679 free(phys_name); 680 return (NULL); 681 } 682 683 if (sensor_class == SSSC_NUMERIC) { 684 if (sensor_type == SSST_TEMPERATURE) { 685 ADD_NODE(PICL_CLASS_TEMPERATURE_SENSOR) 686 add_prop(nodeh, &proph, node_name, row, 687 PP_TEMPERATURE, snmp_syserr_p); 688 } else if (sensor_type == SSST_VOLTAGE) { 689 ADD_NODE(PICL_CLASS_VOLTAGE_SENSOR) 690 add_prop(nodeh, &proph, node_name, row, 691 PP_VOLTAGE, snmp_syserr_p); 692 } else if (sensor_type == SSST_CURRENT) { 693 ADD_NODE(PICL_CLASS_CURRENT_SENSOR) 694 add_prop(nodeh, &proph, node_name, row, 695 PP_CURRENT, snmp_syserr_p); 696 } else if (sensor_type == SSST_TACHOMETER) { 697 ADD_NODE(PICL_CLASS_RPM_SENSOR) 698 add_prop(nodeh, &proph, node_name, row, 699 PP_SPEED, snmp_syserr_p); 700 } else { 701 ADD_NODE(PICL_CLASS_SENSOR) 702 add_prop(nodeh, &proph, node_name, row, 703 PP_SENSOR_VALUE, snmp_syserr_p); 704 } 705 CHECK_LINKRESET(snmp_syserr_p, NULL) 706 707 add_prop(nodeh, &proph, node_name, row, 708 PP_OPSTATUS, snmp_syserr_p); 709 CHECK_LINKRESET(snmp_syserr_p, NULL) 710 711 add_prop(nodeh, &proph, node_name, row, 712 PP_BASE_UNITS, snmp_syserr_p); 713 CHECK_LINKRESET(snmp_syserr_p, NULL) 714 715 add_prop(nodeh, &proph, node_name, row, 716 PP_EXPONENT, snmp_syserr_p); 717 CHECK_LINKRESET(snmp_syserr_p, NULL) 718 719 add_prop(nodeh, &proph, node_name, row, 720 PP_RATE_UNITS, snmp_syserr_p); 721 CHECK_LINKRESET(snmp_syserr_p, NULL) 722 723 add_thresholds(nodeh, row, snmp_syserr_p); 724 CHECK_LINKRESET(snmp_syserr_p, NULL) 725 726 } else if (sensor_class == SSSC_BINARY) { 727 if (sensor_type == SSST_TEMPERATURE) { 728 ADD_NODE(PICL_CLASS_TEMPERATURE_INDICATOR) 729 } else if (sensor_type == SSST_VOLTAGE) { 730 ADD_NODE(PICL_CLASS_VOLTAGE_INDICATOR) 731 } else if (sensor_type == SSST_CURRENT) { 732 ADD_NODE(PICL_CLASS_CURRENT_INDICATOR) 733 } else if (sensor_type == SSST_TACHOMETER) { 734 ADD_NODE(PICL_CLASS_RPM_INDICATOR) 735 } else if (sensor_type == SSST_PRESENCE) { 736 ADD_NODE(PICL_CLASS_PRESENCE_INDICATOR) 737 } else { 738 ADD_NODE(PICL_CLASS_INDICATOR) 739 } 740 741 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 742 snmp_syserr_p); 743 CHECK_LINKRESET(snmp_syserr_p, NULL) 744 745 add_prop(nodeh, &proph, node_name, row, PP_CONDITION, 746 snmp_syserr_p); 747 CHECK_LINKRESET(snmp_syserr_p, NULL) 748 749 add_prop(nodeh, &proph, node_name, row, PP_EXPECTED, 750 snmp_syserr_p); 751 CHECK_LINKRESET(snmp_syserr_p, NULL) 752 } else { 753 log_msg(LOG_ERR, 754 SNMPP_UNSUPP_SENSOR_CLASS, sensor_class, row); 755 return (NULL); 756 } 757 break; 758 759 case SPC_MODULE: 760 ADD_NODE(PICL_CLASS_MODULE) 761 762 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 763 snmp_syserr_p); 764 CHECK_LINKRESET(snmp_syserr_p, NULL) 765 766 add_prop(nodeh, &proph, node_name, row, PP_REPLACEABLE, 767 snmp_syserr_p); 768 CHECK_LINKRESET(snmp_syserr_p, NULL) 769 770 add_prop(nodeh, &proph, node_name, row, PP_HOTSWAPPABLE, 771 snmp_syserr_p); 772 CHECK_LINKRESET(snmp_syserr_p, NULL) 773 break; 774 775 case SPC_PORT: 776 ADD_NODE(PICL_CLASS_PORT) 777 break; 778 779 case SPC_STACK: 780 ADD_NODE(PICL_CLASS_STACK) 781 break; 782 783 default: 784 log_msg(LOG_WARNING, 785 SNMPP_UNKNOWN_ENTPHYSCLASS, ent_physclass, row); 786 free(phys_name); 787 return (NULL); 788 } 789 790 add_prop(nodeh, &proph, node_name, row, PP_DESCRIPTION, snmp_syserr_p); 791 CHECK_LINKRESET(snmp_syserr_p, NULL) 792 793 add_prop(nodeh, &proph, node_name, row, PP_LABEL, snmp_syserr_p); 794 CHECK_LINKRESET(snmp_syserr_p, NULL) 795 796 add_prop(nodeh, &proph, node_name, row, PP_HW_REVISION, snmp_syserr_p); 797 CHECK_LINKRESET(snmp_syserr_p, NULL) 798 799 add_prop(nodeh, &proph, node_name, row, PP_FW_REVISION, snmp_syserr_p); 800 CHECK_LINKRESET(snmp_syserr_p, NULL) 801 802 add_prop(nodeh, &proph, node_name, row, PP_SERIAL_NUM, snmp_syserr_p); 803 CHECK_LINKRESET(snmp_syserr_p, NULL) 804 805 add_prop(nodeh, &proph, node_name, row, PP_MFG_NAME, snmp_syserr_p); 806 CHECK_LINKRESET(snmp_syserr_p, NULL) 807 808 add_prop(nodeh, &proph, node_name, row, PP_MODEL_NAME, snmp_syserr_p); 809 CHECK_LINKRESET(snmp_syserr_p, NULL) 810 811 add_prop(nodeh, &proph, node_name, row, PP_IS_FRU, snmp_syserr_p); 812 CHECK_LINKRESET(snmp_syserr_p, NULL) 813 814 free(phys_name); 815 save_nodeh(nodeh, row); 816 817 return (nodeh); 818 } 819 820 /* 821 * Saves the node handle and the row id into physplat_nodes[]. If we're 822 * doing this in response to a hotplug event, we should've freed the 823 * old physplat_nodes before entering here to save the first node of the 824 * new physplat subtree. 825 */ 826 static void 827 save_nodeh(picl_nodehdl_t nodeh, int row) 828 { 829 size_t sz, count; 830 picl_nodehdl_t *p; 831 832 if (row >= n_physplat_nodes) { 833 count = (((size_t)row >> NODE_BLOCK_SHIFT) + 1) * 834 N_ELEMS_IN_NODE_BLOCK; 835 sz = count * sizeof (picl_nodehdl_t); 836 837 p = (picl_nodehdl_t *)calloc(count, sizeof (picl_nodehdl_t)); 838 if (p == NULL) { 839 log_msg(LOG_ERR, SNMPP_NO_MEM, sz); 840 return; 841 } 842 843 if (physplat_nodes) { 844 (void) memcpy((void *) p, (void *) physplat_nodes, 845 n_physplat_nodes * sizeof (picl_nodehdl_t)); 846 free((void *) physplat_nodes); 847 } 848 849 physplat_nodes = p; 850 n_physplat_nodes = count; 851 } 852 853 physplat_nodes[row] = nodeh; 854 } 855 856 static picl_nodehdl_t 857 lookup_nodeh(int row) 858 { 859 if (row >= n_physplat_nodes) 860 return (NULL); 861 862 return (physplat_nodes[row]); 863 } 864 865 /* 866 * We enter this routine only when we are building the physical-platform 867 * subtree, whether for the first time or in response to a hotplug event. 868 * If we're here for rebuilding the tree, we have already set stale_tree 869 * to be B_TRUE, so no one else would be accessing vol_props, n_vol_props 870 * or volprop_ndx. If we're here to build the tree for the first time, 871 * picld hasn't yet created doors and is running single-threaded, so no 872 * one else would be accessing them anyway. 873 */ 874 static void 875 save_volprop(picl_prophdl_t prop, char *oidstr, int row, int proptype) 876 { 877 vol_prophdl_t *p; 878 int count; 879 880 if (volprop_ndx == n_vol_props) { 881 count = n_vol_props + N_ELEMS_IN_VOLPROP_BLOCK; 882 p = (vol_prophdl_t *)calloc(count, sizeof (vol_prophdl_t)); 883 if (p == NULL) { 884 log_msg(LOG_ERR, SNMPP_NO_MEM, 885 count * sizeof (vol_prophdl_t)); 886 return; 887 } 888 889 if (vol_props) { 890 (void) memcpy((void *) p, (void *) vol_props, 891 n_vol_props * sizeof (vol_prophdl_t)); 892 free((void *) vol_props); 893 } 894 895 vol_props = p; 896 n_vol_props += N_ELEMS_IN_VOLPROP_BLOCK; 897 } 898 899 vol_props[volprop_ndx].prop = prop; 900 vol_props[volprop_ndx].oidstr = oidstr; 901 vol_props[volprop_ndx].row = row; 902 vol_props[volprop_ndx].proptype = proptype; 903 904 volprop_ndx++; 905 } 906 907 static void 908 check_for_stale_data(void) 909 { 910 int cur_change_time; 911 int ret; 912 int snmp_syserr; 913 914 (void) rw_wrlock(&stale_tree_rwlp); 915 916 /* 917 * Check if some other thread beat us to it 918 */ 919 if (stale_tree == B_TRUE) { 920 (void) rw_unlock(&stale_tree_rwlp); 921 return; 922 } 923 924 /* 925 * Check if mib data has changed (hotplug? link-reset?) 926 */ 927 ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, &cur_change_time, 928 &snmp_syserr); 929 if ((ret == 0) && (cur_change_time == change_time)) { 930 (void) rw_unlock(&stale_tree_rwlp); 931 return; 932 } 933 934 /* 935 * If we can't read entLastChangeTime we assume we need to rebuild 936 * the tree. This will also cover the case when we need to rebuild 937 * the tree because a link reset had happened. 938 */ 939 LOGPRINTF2("check_for_stale_data: LastChange times have changed, " 940 "(%#x != %#x)\n", change_time, cur_change_time); 941 942 /* 943 * If the mib data has changed, we need to rebuild the physical-platform 944 * subtree. To do this, we set a flag to mark the tree stale, 945 * so that any future reads to get value of volatile properties will 946 * return PICL_PROPVALUNAVAILABLE, until the stale_tree flag 947 * is reset by the tree builder thread. 948 */ 949 stale_tree = B_TRUE; 950 if (vol_props) { 951 free(vol_props); 952 } 953 vol_props = NULL; 954 volprop_ndx = 0; 955 n_vol_props = 0; 956 957 (void) rw_unlock(&stale_tree_rwlp); 958 959 (void) mutex_lock(&rebuild_tree_lock); 960 rebuild_tree = B_TRUE; 961 (void) cond_signal(&rebuild_tree_cv); 962 LOGPRINTF("check_for_stale_data: signalled tree builder\n"); 963 (void) mutex_unlock(&rebuild_tree_lock); 964 } 965 966 /* 967 * This is the critical routine. This callback is invoked by picl whenever 968 * it needs to fetch the value of a volatile property. The first thing we 969 * must do, however, is to see if there has been a hotplug or a link-reset 970 * event since the last time we built the tree and whether we need to 971 * rebuild the tree. If so, we do whatever is necessary to make that happen, 972 * but return PICL_PROPVALUNAVAILABLE for now, without making any further 973 * snmp requests or accessing any globals. 974 */ 975 static int 976 read_volprop(ptree_rarg_t *parg, void *buf) 977 { 978 char *pstr; 979 int propval; 980 int i, ndx; 981 int ret; 982 int snmp_syserr = 0; 983 984 /* 985 * First check for any event that would make us throw away 986 * the existing /physical-platform subtree and rebuild 987 * another one. If we are rebuilding the subtree, we just 988 * return the stale value until the tree is fully built. 989 */ 990 check_for_stale_data(); 991 992 (void) rw_rdlock(&stale_tree_rwlp); 993 994 if (stale_tree == B_TRUE) { 995 (void) rw_unlock(&stale_tree_rwlp); 996 return (PICL_PROPVALUNAVAILABLE); 997 } 998 999 for (i = 0; i < volprop_ndx; i++) { 1000 if (vol_props[i].prop == parg->proph) { 1001 ndx = i; 1002 break; 1003 } 1004 } 1005 if (i == volprop_ndx) { 1006 log_msg(LOG_ERR, SNMPP_CANT_FIND_VOLPROP, parg->proph); 1007 return (PICL_FAILURE); 1008 } 1009 1010 /* 1011 * If we can't read the value, return failure. Even if this was 1012 * due to a link reset, between the check for stale data and now, 1013 * the next volatile callback by picl will initiate a tree-rebuild. 1014 */ 1015 ret = snmp_get_int(hdl, vol_props[ndx].oidstr, vol_props[ndx].row, 1016 &propval, &snmp_syserr); 1017 if (ret < 0) { 1018 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, ret); 1019 return (PICL_FAILURE); 1020 } 1021 1022 switch (vol_props[ndx].proptype) { 1023 case VPT_PLATOPSTATE: 1024 if (propval == SSOS_DISABLED) { 1025 (void) strlcpy(buf, STR_SSOS_DISABLED, MAX_OPSTATE_LEN); 1026 } else if (propval == SSOS_ENABLED) { 1027 (void) strlcpy(buf, STR_SSOS_ENABLED, MAX_OPSTATE_LEN); 1028 } else { 1029 log_msg(LOG_ERR, SNMPP_INV_PLAT_EQUIP_OPSTATE, 1030 propval, vol_props[ndx].row); 1031 return (PICL_FAILURE); 1032 } 1033 break; 1034 1035 case VPT_NUMSENSOR: 1036 (void) memcpy(buf, &propval, sizeof (propval)); 1037 break; 1038 1039 case VPT_BINSENSOR: 1040 if (propval == ST_TRUE) { 1041 ret = snmp_get_str(hdl, 1042 OID_sunPlatBinarySensorInterpretTrue, 1043 vol_props[ndx].row, &pstr, &snmp_syserr); 1044 if (snmp_syserr == ECANCELED) 1045 return (PICL_FAILURE); 1046 if (ret < 0 || pstr == NULL) { 1047 (void) strlcpy(buf, STR_ST_TRUE, 1048 MAX_TRUTHVAL_LEN); 1049 } else { 1050 (void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN); 1051 free(pstr); 1052 } 1053 } else if (propval == ST_FALSE) { 1054 ret = snmp_get_str(hdl, 1055 OID_sunPlatBinarySensorInterpretFalse, 1056 vol_props[ndx].row, &pstr, &snmp_syserr); 1057 if (snmp_syserr == ECANCELED) 1058 return (PICL_FAILURE); 1059 if (ret < 0 || pstr == NULL) { 1060 (void) strlcpy(buf, STR_ST_FALSE, 1061 MAX_TRUTHVAL_LEN); 1062 } else { 1063 (void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN); 1064 free(pstr); 1065 } 1066 } else { 1067 log_msg(LOG_ERR, SNMPP_INV_PLAT_BINSNSR_CURRENT, 1068 propval, vol_props[ndx].row); 1069 return (PICL_FAILURE); 1070 } 1071 break; 1072 1073 case VPT_ALARMSTATE: 1074 if (propval == SSAS_OFF) { 1075 (void) strlcpy(buf, STR_SSAS_OFF, MAX_ALARMSTATE_LEN); 1076 } else if (propval == SSAS_STEADY) { 1077 (void) strlcpy(buf, STR_SSAS_STEADY, 1078 MAX_ALARMSTATE_LEN); 1079 } else if (propval == SSAS_ALTERNATING) { 1080 (void) strlcpy(buf, STR_SSAS_ALTERNATING, 1081 MAX_ALARMSTATE_LEN); 1082 } else { 1083 (void) strlcpy(buf, STR_SSAS_UNKNOWN, 1084 MAX_ALARMSTATE_LEN); 1085 } 1086 break; 1087 1088 case VPT_BATTERYSTATUS: 1089 switch (propval) { 1090 case SSBS_OTHER: 1091 (void) strlcpy(buf, STR_SSBS_OTHER, 1092 MAX_BATTERYSTATUS_LEN); 1093 break; 1094 case SSBS_FULLYCHARGED: 1095 (void) strlcpy(buf, STR_SSBS_FULLYCHARGED, 1096 MAX_BATTERYSTATUS_LEN); 1097 break; 1098 case SSBS_LOW: 1099 (void) strlcpy(buf, STR_SSBS_LOW, 1100 MAX_BATTERYSTATUS_LEN); 1101 break; 1102 case SSBS_CRITICAL: 1103 (void) strlcpy(buf, STR_SSBS_CRITICAL, 1104 MAX_BATTERYSTATUS_LEN); 1105 break; 1106 case SSBS_CHARGING: 1107 (void) strlcpy(buf, STR_SSBS_CHARGING, 1108 MAX_BATTERYSTATUS_LEN); 1109 break; 1110 case SSBS_CHARGING_AND_LOW: 1111 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_LOW, 1112 MAX_BATTERYSTATUS_LEN); 1113 break; 1114 case SSBS_CHARGING_AND_HIGH: 1115 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_HIGH, 1116 MAX_BATTERYSTATUS_LEN); 1117 break; 1118 case SSBS_CHARGING_AND_CRITICAL: 1119 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_CRITICAL, 1120 MAX_BATTERYSTATUS_LEN); 1121 break; 1122 case SSBS_UNDEFINED: 1123 (void) strlcpy(buf, STR_SSBS_UNDEFINED, 1124 MAX_BATTERYSTATUS_LEN); 1125 break; 1126 case SSBS_PARTIALLY_CHARGED: 1127 (void) strlcpy(buf, STR_SSBS_PARTIALLY_CHARGED, 1128 MAX_BATTERYSTATUS_LEN); 1129 break; 1130 case SSBS_UNKNOWN: 1131 default: 1132 (void) strlcpy(buf, STR_SSBS_UNKNOWN, 1133 MAX_BATTERYSTATUS_LEN); 1134 break; 1135 } 1136 break; 1137 } 1138 1139 (void) rw_unlock(&stale_tree_rwlp); 1140 1141 return (PICL_SUCCESS); 1142 } 1143 1144 static void 1145 threshold(picl_nodehdl_t node, char *oidstr, int row, char *propname, 1146 int *snmp_syserr_p) 1147 { 1148 picl_prophdl_t prop; 1149 int err; 1150 int val; 1151 1152 if (snmp_get_int(hdl, oidstr, row, &val, snmp_syserr_p) != -1) { 1153 err = add_volatile_prop(node, propname, PICL_PTYPE_INT, 1154 PICL_READ, sizeof (int), read_volprop, NULL, &prop); 1155 if (err == PICL_SUCCESS) 1156 save_volprop(prop, oidstr, row, VPT_NUMSENSOR); 1157 } 1158 } 1159 1160 static void 1161 add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p) 1162 { 1163 uchar_t *bitstr = NULL; 1164 uchar_t enabled; 1165 uint_t nbytes; 1166 int ret; 1167 1168 ret = snmp_get_bitstr(hdl, OID_sunPlatNumericSensorEnabledThresholds, 1169 row, &bitstr, &nbytes, snmp_syserr_p); 1170 CHECK_LINKRESET_VOID(snmp_syserr_p) 1171 1172 if (ret < 0 || bitstr == NULL || nbytes > 2) 1173 enabled = 0xff; 1174 else if (nbytes == 1) { 1175 /* 1176 * The ALOM snmp agent doesn't adhere to the BER rules for 1177 * encoding bit strings. While the BER states that bitstrings 1178 * must begin from the second octet after length, and the 1179 * first octet after length must indicate the number of unused 1180 * bits in the last octet, the snmp agent simply sends the 1181 * bitstring data as if it were octet string -- that is, the 1182 * "unused bits" octet is missing. 1183 */ 1184 enabled = bitstr[0]; 1185 } else if (nbytes == 2) 1186 enabled = bitstr[1]; 1187 1188 if (bitstr) { 1189 free(bitstr); 1190 } 1191 1192 if (enabled & LOWER_FATAL) { 1193 threshold(node, 1194 OID_sunPlatNumericSensorLowerThresholdFatal, row, 1195 PICL_PROP_LOW_POWER_OFF, snmp_syserr_p); 1196 CHECK_LINKRESET_VOID(snmp_syserr_p) 1197 } 1198 if (enabled & LOWER_CRITICAL) { 1199 threshold(node, 1200 OID_sunPlatNumericSensorLowerThresholdCritical, row, 1201 PICL_PROP_LOW_SHUTDOWN, snmp_syserr_p); 1202 CHECK_LINKRESET_VOID(snmp_syserr_p) 1203 } 1204 if (enabled & LOWER_NON_CRITICAL) { 1205 threshold(node, 1206 OID_sunPlatNumericSensorLowerThresholdNonCritical, row, 1207 PICL_PROP_LOW_WARNING, snmp_syserr_p); 1208 CHECK_LINKRESET_VOID(snmp_syserr_p) 1209 } 1210 if (enabled & UPPER_NON_CRITICAL) { 1211 threshold(node, 1212 OID_sunPlatNumericSensorUpperThresholdNonCritical, row, 1213 PICL_PROP_HIGH_POWER_OFF, snmp_syserr_p); 1214 CHECK_LINKRESET_VOID(snmp_syserr_p) 1215 } 1216 if (enabled & UPPER_CRITICAL) { 1217 threshold(node, 1218 OID_sunPlatNumericSensorUpperThresholdCritical, row, 1219 PICL_PROP_HIGH_SHUTDOWN, snmp_syserr_p); 1220 CHECK_LINKRESET_VOID(snmp_syserr_p) 1221 } 1222 if (enabled & UPPER_FATAL) { 1223 threshold(node, 1224 OID_sunPlatNumericSensorUpperThresholdFatal, row, 1225 PICL_PROP_HIGH_WARNING, snmp_syserr_p); 1226 CHECK_LINKRESET_VOID(snmp_syserr_p) 1227 } 1228 } 1229 1230 static char * 1231 get_slot_type(int row, int *snmp_syserr_p) 1232 { 1233 char *p; 1234 char *slott = NULL; 1235 int ret; 1236 1237 ret = snmp_get_str(hdl, OID_sunPlatEquipmentHolderAcceptableTypes, 1238 row, &p, snmp_syserr_p); 1239 CHECK_LINKRESET(snmp_syserr_p, NULL) 1240 1241 if ((ret == 0) && p && *p) { 1242 slott = p; 1243 if ((p = strchr(slott, '\n')) != NULL) 1244 *p = 0; 1245 } else { 1246 log_msg(LOG_WARNING, SNMPP_NO_SLOT_TYPE, row); 1247 if (p) { 1248 free(p); 1249 } 1250 } 1251 1252 return (slott); 1253 } 1254 1255 /* 1256 * Create and add the specified volatile property 1257 */ 1258 static int 1259 add_volatile_prop(picl_nodehdl_t node, char *name, int type, int access, 1260 int size, int (*rdfunc)(ptree_rarg_t *, void *), 1261 int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp) 1262 { 1263 ptree_propinfo_t propinfo; 1264 picl_prophdl_t prop; 1265 int err; 1266 1267 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1268 type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc); 1269 if (err != PICL_SUCCESS) { 1270 log_msg(LOG_ERR, SNMPP_CANT_INIT_PROPINFO, err); 1271 return (err); 1272 } 1273 1274 err = ptree_create_and_add_prop(node, &propinfo, NULL, &prop); 1275 if (err != PICL_SUCCESS) { 1276 log_msg(LOG_ERR, SNMPP_CANT_ADD_PROP, err, node); 1277 return (err); 1278 } 1279 1280 if (propp) 1281 *propp = prop; 1282 1283 return (PICL_SUCCESS); 1284 } 1285 1286 /* 1287 * Add the specified string property to the node 1288 */ 1289 static int 1290 add_string_prop(picl_nodehdl_t node, char *propname, char *propval) 1291 { 1292 ptree_propinfo_t propinfo; 1293 int err; 1294 1295 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1296 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(propval) + 1, 1297 propname, NULL, NULL); 1298 if (err != PICL_SUCCESS) { 1299 log_msg(LOG_ERR, SNMPP_CANT_INIT_STR_PROPINFO, err); 1300 return (err); 1301 } 1302 1303 err = ptree_create_and_add_prop(node, &propinfo, propval, NULL); 1304 if (err != PICL_SUCCESS) { 1305 log_msg(LOG_ERR, SNMPP_CANT_ADD_STR_PROP, err, node); 1306 return (err); 1307 } 1308 1309 return (PICL_SUCCESS); 1310 } 1311 1312 /* 1313 * Add the specified void property to the node 1314 */ 1315 static int 1316 add_void_prop(picl_nodehdl_t node, char *propname) 1317 { 1318 ptree_propinfo_t propinfo; 1319 int err; 1320 1321 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1322 PICL_PTYPE_VOID, PICL_READ, 0, propname, NULL, NULL); 1323 if (err != PICL_SUCCESS) { 1324 log_msg(LOG_ERR, SNMPP_CANT_INIT_VOID_PROPINFO, err); 1325 return (err); 1326 } 1327 1328 err = ptree_create_and_add_prop(node, &propinfo, NULL, NULL); 1329 if (err != PICL_SUCCESS) { 1330 log_msg(LOG_ERR, SNMPP_CANT_ADD_VOID_PROP, err, node); 1331 return (err); 1332 } 1333 1334 return (PICL_SUCCESS); 1335 } 1336 1337 static int 1338 add_int_prop(picl_nodehdl_t node, char *propname, int val) 1339 { 1340 ptree_propinfo_t propinfo; 1341 int propval = val; 1342 int err; 1343 1344 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1345 PICL_PTYPE_INT, PICL_READ, sizeof (int), 1346 propname, NULL, NULL); 1347 if (err != PICL_SUCCESS) { 1348 log_msg(LOG_ERR, SNMPP_CANT_INIT_INT_PROPINFO, err); 1349 return (err); 1350 } 1351 1352 err = ptree_create_and_add_prop(node, &propinfo, &propval, NULL); 1353 if (err != PICL_SUCCESS) { 1354 log_msg(LOG_ERR, SNMPP_CANT_ADD_INT_PROP, err, node); 1355 return (err); 1356 } 1357 1358 return (PICL_SUCCESS); 1359 } 1360 1361 static void 1362 add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label, 1363 int row, sp_propid_t pp, int *snmp_syserr_p) 1364 { 1365 char *serial_num; 1366 char *slot_type; 1367 char *fw_revision, *hw_revision; 1368 char *mfg_name, *model_name; 1369 char *phys_descr; 1370 int val; 1371 int ret; 1372 1373 switch (pp) { 1374 case PP_SERIAL_NUM: 1375 ret = snmp_get_str(hdl, OID_entPhysicalSerialNum, 1376 row, &serial_num, snmp_syserr_p); 1377 CHECK_LINKRESET_VOID(snmp_syserr_p) 1378 if ((ret == 0) && serial_num && *serial_num) { 1379 (void) add_string_prop(nodeh, 1380 PICL_PROP_SERIAL_NUMBER, serial_num); 1381 free((void *) serial_num); 1382 } 1383 break; 1384 1385 case PP_SLOT_TYPE: 1386 if ((slot_type = get_slot_type(row, snmp_syserr_p)) == NULL) { 1387 CHECK_LINKRESET_VOID(snmp_syserr_p) 1388 (void) add_string_prop(nodeh, 1389 PICL_PROP_SLOT_TYPE, DEFAULT_SLOT_TYPE); 1390 } else { 1391 (void) add_string_prop(nodeh, 1392 PICL_PROP_SLOT_TYPE, slot_type); 1393 free((void *) slot_type); 1394 } 1395 break; 1396 1397 case PP_STATE: 1398 ret = add_volatile_prop(nodeh, PICL_PROP_STATE, 1399 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_ALARMSTATE_LEN, 1400 read_volprop, NULL, php); 1401 if (ret == PICL_SUCCESS) { 1402 save_volprop(*php, OID_sunPlatAlarmState, row, 1403 VPT_ALARMSTATE); 1404 } 1405 break; 1406 1407 case PP_OPSTATUS: 1408 ret = add_volatile_prop(nodeh, PICL_PROP_OPERATIONAL_STATUS, 1409 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_OPSTATE_LEN, 1410 read_volprop, NULL, php); 1411 if (ret == PICL_SUCCESS) { 1412 save_volprop(*php, 1413 OID_sunPlatEquipmentOperationalState, row, 1414 VPT_PLATOPSTATE); 1415 } 1416 break; 1417 1418 case PP_BATT_STATUS: 1419 ret = add_volatile_prop(nodeh, PICL_PROP_BATTERY_STATUS, 1420 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_BATTERYSTATUS_LEN, 1421 read_volprop, NULL, php); 1422 if (ret == PICL_SUCCESS) { 1423 save_volprop(*php, OID_sunPlatBatteryStatus, row, 1424 VPT_BATTERYSTATUS); 1425 } 1426 break; 1427 1428 case PP_TEMPERATURE: 1429 ret = add_volatile_prop(nodeh, PICL_PROP_TEMPERATURE, 1430 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1431 NULL, php); 1432 if (ret == PICL_SUCCESS) { 1433 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1434 row, VPT_NUMSENSOR); 1435 } 1436 break; 1437 1438 case PP_VOLTAGE: 1439 ret = add_volatile_prop(nodeh, PICL_PROP_VOLTAGE, 1440 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1441 NULL, php); 1442 if (ret == PICL_SUCCESS) { 1443 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1444 row, VPT_NUMSENSOR); 1445 } 1446 break; 1447 1448 case PP_CURRENT: 1449 ret = add_volatile_prop(nodeh, PICL_PROP_CURRENT, 1450 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1451 NULL, php); 1452 if (ret == PICL_SUCCESS) { 1453 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1454 row, VPT_NUMSENSOR); 1455 } 1456 break; 1457 1458 case PP_SPEED: 1459 ret = add_volatile_prop(nodeh, PICL_PROP_SPEED, PICL_PTYPE_INT, 1460 PICL_READ, sizeof (int), read_volprop, NULL, php); 1461 if (ret == PICL_SUCCESS) { 1462 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1463 row, VPT_NUMSENSOR); 1464 } 1465 break; 1466 1467 case PP_SENSOR_VALUE: 1468 ret = add_volatile_prop(nodeh, PICL_PROP_SENSOR_VALUE, 1469 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1470 NULL, php); 1471 if (ret == PICL_SUCCESS) { 1472 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1473 row, VPT_NUMSENSOR); 1474 } 1475 break; 1476 1477 case PP_CONDITION: 1478 ret = add_volatile_prop(nodeh, PICL_PROP_CONDITION, 1479 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN, 1480 read_volprop, NULL, php); 1481 if (ret == PICL_SUCCESS) { 1482 save_volprop(*php, OID_sunPlatBinarySensorCurrent, 1483 row, VPT_BINSENSOR); 1484 } 1485 break; 1486 1487 case PP_EXPECTED: 1488 ret = add_volatile_prop(nodeh, PICL_PROP_EXPECTED, 1489 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN, 1490 read_volprop, NULL, php); 1491 if (ret == PICL_SUCCESS) { 1492 save_volprop(*php, OID_sunPlatBinarySensorExpected, 1493 row, VPT_BINSENSOR); 1494 } 1495 break; 1496 1497 case PP_REPLACEABLE: 1498 ret = snmp_get_int(hdl, OID_sunPlatCircuitPackReplaceable, 1499 row, &val, snmp_syserr_p); 1500 CHECK_LINKRESET_VOID(snmp_syserr_p) 1501 if ((ret == 0) && (val == ST_TRUE)) 1502 (void) add_void_prop(nodeh, PICL_PROP_IS_REPLACEABLE); 1503 break; 1504 1505 case PP_HOTSWAPPABLE: 1506 ret = snmp_get_int(hdl, OID_sunPlatCircuitPackHotSwappable, 1507 row, &val, snmp_syserr_p); 1508 CHECK_LINKRESET_VOID(snmp_syserr_p) 1509 if ((ret == 0) && (val == ST_TRUE)) 1510 (void) add_void_prop(nodeh, PICL_PROP_IS_HOT_SWAPPABLE); 1511 break; 1512 1513 case PP_IS_FRU: 1514 ret = snmp_get_int(hdl, OID_entPhysicalIsFRU, row, 1515 &val, snmp_syserr_p); 1516 CHECK_LINKRESET_VOID(snmp_syserr_p) 1517 if ((ret == 0) && (val == ST_TRUE)) 1518 (void) add_void_prop(nodeh, PICL_PROP_IS_FRU); 1519 break; 1520 1521 case PP_HW_REVISION: 1522 ret = snmp_get_str(hdl, OID_entPhysicalHardwareRev, 1523 row, &hw_revision, snmp_syserr_p); 1524 CHECK_LINKRESET_VOID(snmp_syserr_p) 1525 if ((ret == 0) && hw_revision && *hw_revision) { 1526 (void) add_string_prop(nodeh, 1527 PICL_PROP_HW_REVISION, hw_revision); 1528 free((void *) hw_revision); 1529 } 1530 break; 1531 1532 case PP_FW_REVISION: 1533 ret = snmp_get_str(hdl, OID_entPhysicalFirmwareRev, 1534 row, &fw_revision, snmp_syserr_p); 1535 CHECK_LINKRESET_VOID(snmp_syserr_p) 1536 if ((ret == 0) && fw_revision && *fw_revision) { 1537 (void) add_string_prop(nodeh, 1538 PICL_PROP_FW_REVISION, fw_revision); 1539 free((void *) fw_revision); 1540 } 1541 break; 1542 1543 case PP_MFG_NAME: 1544 ret = snmp_get_str(hdl, OID_entPhysicalMfgName, 1545 row, &mfg_name, snmp_syserr_p); 1546 CHECK_LINKRESET_VOID(snmp_syserr_p) 1547 if ((ret == 0) && mfg_name && *mfg_name) { 1548 (void) add_string_prop(nodeh, 1549 PICL_PROP_MFG_NAME, mfg_name); 1550 free((void *) mfg_name); 1551 } 1552 break; 1553 1554 case PP_MODEL_NAME: 1555 ret = snmp_get_str(hdl, OID_entPhysicalModelName, 1556 row, &model_name, snmp_syserr_p); 1557 CHECK_LINKRESET_VOID(snmp_syserr_p) 1558 if ((ret == 0) && model_name && *model_name) { 1559 (void) add_string_prop(nodeh, 1560 PICL_PROP_MODEL_NAME, model_name); 1561 free((void *) model_name); 1562 } 1563 break; 1564 1565 case PP_DESCRIPTION: 1566 ret = snmp_get_str(hdl, OID_entPhysicalDescr, 1567 row, &phys_descr, snmp_syserr_p); 1568 CHECK_LINKRESET_VOID(snmp_syserr_p) 1569 if ((ret == 0) && phys_descr && *phys_descr) { 1570 (void) add_string_prop(nodeh, 1571 PICL_PROP_PHYS_DESCRIPTION, phys_descr); 1572 free((void *) phys_descr); 1573 } 1574 break; 1575 1576 case PP_LABEL: 1577 if (label && *label) 1578 (void) add_string_prop(nodeh, PICL_PROP_LABEL, label); 1579 break; 1580 1581 case PP_BASE_UNITS: 1582 ret = snmp_get_int(hdl, OID_sunPlatNumericSensorBaseUnits, 1583 row, &val, snmp_syserr_p); 1584 CHECK_LINKRESET_VOID(snmp_syserr_p) 1585 if ((ret == 0) && (val > 0) && (val < n_baseunits)) { 1586 (void) add_string_prop(nodeh, 1587 PICL_PROP_BASE_UNITS, sensor_baseunits[val]); 1588 } 1589 break; 1590 1591 case PP_RATE_UNITS: 1592 ret = snmp_get_int(hdl, OID_sunPlatNumericSensorRateUnits, 1593 row, &val, snmp_syserr_p); 1594 CHECK_LINKRESET_VOID(snmp_syserr_p) 1595 if ((ret == 0) && (val > 0) && (val < n_rateunits)) { 1596 (void) add_string_prop(nodeh, 1597 PICL_PROP_RATE_UNITS, sensor_rateunits[val]); 1598 } 1599 break; 1600 1601 case PP_EXPONENT: 1602 ret = snmp_get_int(hdl, OID_sunPlatNumericSensorExponent, 1603 row, &val, snmp_syserr_p); 1604 CHECK_LINKRESET_VOID(snmp_syserr_p) 1605 if (ret == 0) 1606 (void) add_int_prop(nodeh, PICL_PROP_EXPONENT, val); 1607 break; 1608 } 1609 } 1610 1611 /*VARARGS2*/ 1612 static void 1613 log_msg(int pri, const char *fmt, ...) 1614 { 1615 va_list ap; 1616 1617 va_start(ap, fmt); 1618 vsyslog(pri, fmt, ap); 1619 va_end(ap); 1620 } 1621 1622 #ifdef SNMPPLUGIN_DEBUG 1623 1624 static void 1625 snmpplugin_log_init(void) 1626 { 1627 (void) mutex_init(&snmpplugin_dbuf_lock, USYNC_THREAD, NULL); 1628 } 1629 1630 static void 1631 snmpplugin_log(const char *fmt, ...) 1632 { 1633 va_list ap; 1634 1635 (void) mutex_lock(&snmpplugin_dbuf_lock); 1636 1637 va_start(ap, fmt); 1638 (void) vsnprintf(snmpplugin_lbuf, SNMPPLUGIN_DMAX_LINE, fmt, ap); 1639 snmpplugin_log_append(); 1640 va_end(ap); 1641 1642 (void) mutex_unlock(&snmpplugin_dbuf_lock); 1643 } 1644 1645 static void 1646 snmpplugin_log_append(void) 1647 { 1648 int len; 1649 1650 len = strlen(snmpplugin_lbuf); 1651 1652 if ((snmpplugin_dbuf_curp + len) >= 1653 (snmpplugin_dbuf + snmpplugin_dbuf_sz)) { 1654 snmpplugin_dbuf_realloc(); 1655 if (snmpplugin_dbuf == NULL) { 1656 (void) mutex_unlock(&snmpplugin_dbuf_lock); 1657 return; 1658 } 1659 } 1660 1661 (void) strcpy(snmpplugin_dbuf_curp, snmpplugin_lbuf); 1662 snmpplugin_dbuf_curp += len; 1663 } 1664 1665 static void 1666 snmpplugin_dbuf_realloc(void) 1667 { 1668 char *p; 1669 size_t offset = 0; 1670 size_t count; 1671 1672 count = snmpplugin_dbuf_sz + SNMPPLUGIN_DBLOCK_SZ; 1673 if ((p = (char *)calloc(count, 1)) == NULL) { 1674 snmpplugin_dbuf_overflow++; 1675 snmpplugin_dbuf_curp = snmpplugin_dbuf; 1676 return; 1677 } 1678 1679 if (snmpplugin_dbuf) { 1680 offset = snmpplugin_dbuf_curp - snmpplugin_dbuf; 1681 (void) memcpy(p, snmpplugin_dbuf, snmpplugin_dbuf_sz); 1682 free(snmpplugin_dbuf); 1683 } 1684 1685 snmpplugin_dbuf = p; 1686 snmpplugin_dbuf_sz += SNMPPLUGIN_DBLOCK_SZ; 1687 1688 snmpplugin_dbuf_curp = snmpplugin_dbuf + offset; 1689 } 1690 #endif 1691