11303Swesolows /* 21303Swesolows * CDDL HEADER START 31303Swesolows * 41303Swesolows * The contents of this file are subject to the terms of the 51303Swesolows * Common Development and Distribution License (the "License"). 61303Swesolows * You may not use this file except in compliance with the License. 71303Swesolows * 81303Swesolows * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91303Swesolows * or http://www.opensolaris.org/os/licensing. 101303Swesolows * See the License for the specific language governing permissions 111303Swesolows * and limitations under the License. 121303Swesolows * 131303Swesolows * When distributing Covered Code, include this CDDL HEADER in each 141303Swesolows * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151303Swesolows * If applicable, add the following below this CDDL HEADER, with the 161303Swesolows * fields enclosed by brackets "[]" replaced with your own identifying 171303Swesolows * information: Portions Copyright [yyyy] [name of copyright owner] 181303Swesolows * 191303Swesolows * CDDL HEADER END 201303Swesolows */ 211303Swesolows 221303Swesolows /* 23*7275Sstephh * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241303Swesolows * Use is subject to license terms. 251303Swesolows */ 261303Swesolows 271303Swesolows #pragma ident "%Z%%M% %I% %E% SMI" 281303Swesolows 291303Swesolows #include <sys/fm/protocol.h> 301303Swesolows #include <fm/fmd_adm.h> 311303Swesolows #include <fm/fmd_snmp.h> 321303Swesolows #include <net-snmp/net-snmp-config.h> 331303Swesolows #include <net-snmp/net-snmp-includes.h> 341303Swesolows #include <net-snmp/agent/net-snmp-agent-includes.h> 351303Swesolows #include <pthread.h> 361303Swesolows #include <stddef.h> 371303Swesolows #include <errno.h> 381303Swesolows #include <alloca.h> 391303Swesolows #include <locale.h> 401303Swesolows #include <libuutil.h> 411303Swesolows #include <libnvpair.h> 421303Swesolows #include "sunFM_impl.h" 431303Swesolows #include "problem.h" 441303Swesolows 451303Swesolows /* 461303Swesolows * We assume that the number of suspect fault events associated with a 471303Swesolows * particular case will generally be sufficiently small that the overhead 481303Swesolows * associated with indexing them in a tree would exceed the gain from 491303Swesolows * not traversing the fault list for each request. 501303Swesolows */ 511303Swesolows static uu_avl_pool_t *problem_uuid_avl_pool; 521303Swesolows static uu_avl_t *problem_uuid_avl; 531303Swesolows 541303Swesolows #define VALID_AVL_STATE (problem_uuid_avl_pool != NULL && \ 551303Swesolows problem_uuid_avl != NULL) 561303Swesolows 571303Swesolows #define UPDATE_WAIT_MILLIS 10 /* poll interval in milliseconds */ 581303Swesolows 591303Swesolows /* 601303Swesolows * Update types. Single-index and all are mutually exclusive. 611303Swesolows */ 621303Swesolows #define UCT_INDEX 0x1 631303Swesolows #define UCT_ALL 0x2 641303Swesolows #define UCT_FLAGS 0x3 651303Swesolows 661303Swesolows /* 671303Swesolows * Locking strategy is described in module.c. 681303Swesolows */ 691303Swesolows static int valid_stamp; 701303Swesolows static pthread_mutex_t update_lock; 711303Swesolows static pthread_cond_t update_cv; 721303Swesolows static volatile enum { US_QUIET, US_NEEDED, US_INPROGRESS } update_status; 731303Swesolows 741303Swesolows static Netsnmp_Node_Handler sunFmProblemTable_handler; 751303Swesolows static Netsnmp_Node_Handler sunFmFaultEventTable_handler; 761303Swesolows 771303Swesolows static sunFmProblem_data_t * 781303Swesolows problem_key_build(const char *uuid) 791303Swesolows { 801303Swesolows static sunFmProblem_data_t key; 811303Swesolows 821303Swesolows key.d_aci_uuid = uuid; 831303Swesolows 841303Swesolows return (&key); 851303Swesolows } 861303Swesolows 871303Swesolows static sunFmProblem_data_t * 881303Swesolows problem_lookup_uuid_exact(const char *uuid) 891303Swesolows { 901303Swesolows sunFmProblem_data_t *key, *data; 911303Swesolows 921303Swesolows key = problem_key_build(uuid); 931303Swesolows 941303Swesolows DEBUGMSGTL((MODNAME_STR, "lookup_exact for uuid %s\n", uuid)); 951303Swesolows data = uu_avl_find(problem_uuid_avl, key, NULL, NULL); 961303Swesolows 971303Swesolows return (data); 981303Swesolows } 991303Swesolows 1001303Swesolows static sunFmProblem_data_t * 1011303Swesolows problem_lookup_uuid_next(const char *uuid) 1021303Swesolows { 1031303Swesolows sunFmProblem_data_t *key, *data; 1041303Swesolows uu_avl_index_t idx; 1051303Swesolows 1061303Swesolows key = problem_key_build(uuid); 1071303Swesolows 1081303Swesolows DEBUGMSGTL((MODNAME_STR, "lookup_next for uuid %s\n", uuid)); 1091303Swesolows (void) uu_avl_find(problem_uuid_avl, key, NULL, &idx); 1101303Swesolows 1111303Swesolows data = uu_avl_nearest_next(problem_uuid_avl, idx); 1121303Swesolows 1131303Swesolows DEBUGMSGTL((MODNAME_STR, "lookup_next: entry is %p\n", data)); 1141303Swesolows 1151303Swesolows return (data); 1161303Swesolows } 1171303Swesolows 1181303Swesolows static sunFmFaultEvent_data_t * 1191303Swesolows faultevent_lookup_index_exact(sunFmProblem_data_t *data, ulong_t index) 1201303Swesolows { 1211303Swesolows if (index > data->d_nsuspects) 1221303Swesolows return (NULL); 1231303Swesolows 1241303Swesolows if (data->d_suspects == NULL) 1251303Swesolows return (NULL); 1261303Swesolows 1271303Swesolows return (data->d_suspects[index - 1]); 1281303Swesolows } 1291303Swesolows 130*7275Sstephh static sunFmFaultStatus_data_t 131*7275Sstephh faultstatus_lookup_index_exact(sunFmProblem_data_t *data, ulong_t index) 132*7275Sstephh { 133*7275Sstephh if (index > data->d_nsuspects) 134*7275Sstephh return (NULL); 135*7275Sstephh 136*7275Sstephh if (data->d_statuses == NULL) 137*7275Sstephh return (NULL); 138*7275Sstephh 139*7275Sstephh return (data->d_statuses[index - 1]); 140*7275Sstephh } 141*7275Sstephh 1422134Swesolows /*ARGSUSED*/ 1431303Swesolows static int 1441303Swesolows problem_update_one(const fmd_adm_caseinfo_t *acp, void *arg) 1451303Swesolows { 1461303Swesolows sunFmProblem_data_t *data; 1471303Swesolows nvlist_t *nvl; 1481303Swesolows int64_t *diag_time; 1491303Swesolows uint_t nelem; 1501303Swesolows uint32_t nsusp; 1511303Swesolows int err; 1521303Swesolows 1531303Swesolows DEBUGMSGTL((MODNAME_STR, "update_one\n")); 1541303Swesolows 1551303Swesolows ASSERT(acp->aci_uuid != NULL); 1561303Swesolows 1571303Swesolows if ((data = problem_lookup_uuid_exact(acp->aci_uuid)) == NULL) { 1581303Swesolows uu_avl_index_t idx; 1591303Swesolows 1601303Swesolows DEBUGMSGTL((MODNAME_STR, "found new problem %s\n", 1611303Swesolows acp->aci_uuid)); 1621303Swesolows if ((data = SNMP_MALLOC_TYPEDEF(sunFmProblem_data_t)) == NULL) { 1631303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": Out of memory for " 1641303Swesolows "new problem data at %s:%d\n", __FILE__, __LINE__); 1651303Swesolows return (0); 1661303Swesolows } 1671303Swesolows if ((err = nvlist_dup(acp->aci_event, &data->d_aci_event, 0)) 1681303Swesolows != 0) { 1691303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": Problem data setup " 1701303Swesolows "failed: %s\n", strerror(err)); 1711303Swesolows SNMP_FREE(data); 1721303Swesolows return (0); 1731303Swesolows } 1741303Swesolows 1751303Swesolows data->d_aci_uuid = data->d_aci_code = data->d_aci_url = "-"; 1761303Swesolows (void) nvlist_lookup_string(data->d_aci_event, FM_SUSPECT_UUID, 1771303Swesolows (char **)&data->d_aci_uuid); 1781303Swesolows (void) nvlist_lookup_string(data->d_aci_event, 1791303Swesolows FM_SUSPECT_DIAG_CODE, (char **)&data->d_aci_code); 1801303Swesolows data->d_aci_url = strdup(acp->aci_url); 1811303Swesolows 1821303Swesolows if (nvlist_lookup_nvlist(data->d_aci_event, FM_SUSPECT_DE, 1831303Swesolows &nvl) == 0) 1841303Swesolows if ((data->d_diag_engine = sunFm_nvl2str(nvl)) == NULL) 1851303Swesolows data->d_diag_engine = "-"; 1861303Swesolows 1871303Swesolows if (nvlist_lookup_int64_array(data->d_aci_event, 1881303Swesolows FM_SUSPECT_DIAG_TIME, &diag_time, &nelem) == 0 && 1891303Swesolows nelem >= 2) { 1901303Swesolows data->d_diag_time.tv_sec = (long)diag_time[0]; 1911303Swesolows data->d_diag_time.tv_usec = (long)diag_time[1]; 1921303Swesolows } 1931303Swesolows 1941303Swesolows (void) nvlist_lookup_uint32(data->d_aci_event, 1951303Swesolows FM_SUSPECT_FAULT_SZ, &nsusp); 1961303Swesolows data->d_nsuspects = (ulong_t)nsusp; 1971303Swesolows 1981303Swesolows (void) nvlist_lookup_nvlist_array(data->d_aci_event, 1991303Swesolows FM_SUSPECT_FAULT_LIST, &data->d_suspects, &nelem); 2001303Swesolows 2011303Swesolows ASSERT(nelem == data->d_nsuspects); 2021303Swesolows 203*7275Sstephh (void) nvlist_lookup_uint8_array(data->d_aci_event, 204*7275Sstephh FM_SUSPECT_FAULT_STATUS, &data->d_statuses, &nelem); 205*7275Sstephh 206*7275Sstephh ASSERT(nelem == data->d_nsuspects); 207*7275Sstephh 2081303Swesolows uu_avl_node_init(data, &data->d_uuid_avl, 2091303Swesolows problem_uuid_avl_pool); 2101303Swesolows (void) uu_avl_find(problem_uuid_avl, data, NULL, &idx); 2111303Swesolows uu_avl_insert(problem_uuid_avl, data, idx); 2121303Swesolows 2131303Swesolows data->d_valid = valid_stamp; 2141303Swesolows 2151303Swesolows DEBUGMSGTL((MODNAME_STR, "completed new problem %s@%p\n", 2161303Swesolows data->d_aci_uuid, data)); 2171303Swesolows } 2181303Swesolows 2191303Swesolows /* 2201303Swesolows * We don't touch problems we've seen before; they shouldn't change 2211303Swesolows * in any way we care about, since they've already been solved. The 2221303Swesolows * state, however, could change, and if we later expose that to the 2231303Swesolows * client we need to update it here. 2241303Swesolows */ 2251303Swesolows 2261303Swesolows return (0); 2271303Swesolows } 2281303Swesolows 2291303Swesolows static int 2301303Swesolows problem_update(sunFmProblem_update_ctx_t *update_ctx) 2311303Swesolows { 2321303Swesolows fmd_adm_t *adm; 2331303Swesolows 2341303Swesolows ASSERT(update_ctx != NULL); 2351303Swesolows ASSERT((update_ctx->uc_type & (UCT_INDEX|UCT_ALL)) != 2361303Swesolows (UCT_INDEX|UCT_ALL)); 2371303Swesolows ASSERT((update_ctx->uc_type & ~UCT_FLAGS) == 0); 2381303Swesolows ASSERT(VALID_AVL_STATE); 2391303Swesolows 2401303Swesolows if ((adm = fmd_adm_open(update_ctx->uc_host, update_ctx->uc_prog, 2411303Swesolows update_ctx->uc_version)) == NULL) { 2421303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": Communication with fmd " 2431303Swesolows "failed: %s\n", strerror(errno)); 2441303Swesolows return (SNMP_ERR_RESOURCEUNAVAILABLE); 2451303Swesolows } 2461303Swesolows 2471303Swesolows ++valid_stamp; 2481303Swesolows if (fmd_adm_case_iter(adm, SNMP_URL_MSG, problem_update_one, 2491303Swesolows update_ctx) != 0) { 2501303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": fmd case information update " 2511303Swesolows "failed: %s\n", fmd_adm_errmsg(adm)); 2521303Swesolows fmd_adm_close(adm); 2531303Swesolows return (SNMP_ERR_RESOURCEUNAVAILABLE); 2541303Swesolows } 2551303Swesolows 2561303Swesolows DEBUGMSGTL((MODNAME_STR, "case iteration completed\n")); 2571303Swesolows 2581303Swesolows fmd_adm_close(adm); 2591303Swesolows return (SNMP_ERR_NOERROR); 2601303Swesolows } 2611303Swesolows 2621303Swesolows /*ARGSUSED*/ 2631303Swesolows static void 2641303Swesolows update_thread(void *arg) 2651303Swesolows { 2661303Swesolows /* 2671303Swesolows * The current problem_update implementation offers minimal savings 2681303Swesolows * for the use of index-only updates; therefore we always do a full 2691303Swesolows * update. If it becomes advantageous to limit updates to a single 2701303Swesolows * index, the contexts can be queued by the handler instead. 2711303Swesolows */ 2721303Swesolows sunFmProblem_update_ctx_t uc; 2731303Swesolows 2741303Swesolows uc.uc_host = NULL; 2751303Swesolows uc.uc_prog = FMD_ADM_PROGRAM; 2761303Swesolows uc.uc_version = FMD_ADM_VERSION; 2771303Swesolows 2781303Swesolows uc.uc_index = NULL; 2791303Swesolows uc.uc_type = UCT_ALL; 2801303Swesolows 2811303Swesolows for (;;) { 2821303Swesolows (void) pthread_mutex_lock(&update_lock); 2831303Swesolows update_status = US_QUIET; 2841303Swesolows while (update_status == US_QUIET) 2851303Swesolows (void) pthread_cond_wait(&update_cv, &update_lock); 2861303Swesolows update_status = US_INPROGRESS; 2871303Swesolows (void) pthread_mutex_unlock(&update_lock); 2881303Swesolows (void) problem_update(&uc); 2891303Swesolows } 2901303Swesolows } 2911303Swesolows 2921303Swesolows static void 2931303Swesolows request_update(void) 2941303Swesolows { 2951303Swesolows (void) pthread_mutex_lock(&update_lock); 2961303Swesolows if (update_status != US_QUIET) { 2971303Swesolows (void) pthread_mutex_unlock(&update_lock); 2981303Swesolows return; 2991303Swesolows } 3001303Swesolows update_status = US_NEEDED; 3011303Swesolows (void) pthread_cond_signal(&update_cv); 3021303Swesolows (void) pthread_mutex_unlock(&update_lock); 3031303Swesolows } 3041303Swesolows 3051303Swesolows /*ARGSUSED*/ 3061303Swesolows static int 3071303Swesolows problem_compare_uuid(const void *l, const void *r, void *private) 3081303Swesolows { 3091303Swesolows sunFmProblem_data_t *l_data = (sunFmProblem_data_t *)l; 3101303Swesolows sunFmProblem_data_t *r_data = (sunFmProblem_data_t *)r; 3111303Swesolows 3121303Swesolows ASSERT(l_data != NULL && r_data != NULL); 3131303Swesolows 3141303Swesolows return (strcmp(l_data->d_aci_uuid, r_data->d_aci_uuid)); 3151303Swesolows } 3161303Swesolows 3171303Swesolows int 3181303Swesolows sunFmProblemTable_init(void) 3191303Swesolows { 3201303Swesolows static oid sunFmProblemTable_oid[] = { SUNFMPROBLEMTABLE_OID }; 3211303Swesolows netsnmp_table_registration_info *table_info; 3221303Swesolows netsnmp_handler_registration *handler; 3231303Swesolows int err; 3241303Swesolows 3251303Swesolows if ((err = pthread_mutex_init(&update_lock, NULL)) != 0) { 3261303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": mutex_init failure: %s\n", 3271303Swesolows strerror(err)); 3281303Swesolows return (MIB_REGISTRATION_FAILED); 3291303Swesolows } 3301303Swesolows if ((err = pthread_cond_init(&update_cv, NULL)) != 0) { 3311303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": cond_init failure: %s\n", 3321303Swesolows strerror(err)); 3331303Swesolows return (MIB_REGISTRATION_FAILED); 3341303Swesolows } 3351303Swesolows 3361303Swesolows if ((err = pthread_create(NULL, NULL, (void *(*)(void *))update_thread, 3371303Swesolows NULL)) != 0) { 3381303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": error creating update " 3391303Swesolows "thread: %s\n", strerror(err)); 3401303Swesolows return (MIB_REGISTRATION_FAILED); 3411303Swesolows } 3421303Swesolows 3431303Swesolows if ((table_info = 3441303Swesolows SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL) 3451303Swesolows return (MIB_REGISTRATION_FAILED); 3461303Swesolows 3471303Swesolows if ((handler = netsnmp_create_handler_registration("sunFmProblemTable", 3481303Swesolows sunFmProblemTable_handler, sunFmProblemTable_oid, 3491303Swesolows OID_LENGTH(sunFmProblemTable_oid), HANDLER_CAN_RONLY)) == NULL) { 3501303Swesolows SNMP_FREE(table_info); 3511303Swesolows return (MIB_REGISTRATION_FAILED); 3521303Swesolows } 3531303Swesolows 3541303Swesolows /* 3551303Swesolows * The Net-SNMP template uses add_indexes here, but that 3561303Swesolows * function is unsafe because it does not check for failure. 3571303Swesolows */ 3581303Swesolows if (netsnmp_table_helper_add_index(table_info, ASN_OCTET_STR) == NULL) { 3591303Swesolows SNMP_FREE(table_info); 3601303Swesolows SNMP_FREE(handler); 3611303Swesolows return (MIB_REGISTRATION_FAILED); 3621303Swesolows } 3631303Swesolows 3641303Swesolows table_info->min_column = SUNFMPROBLEM_COLMIN; 3651303Swesolows table_info->max_column = SUNFMPROBLEM_COLMAX; 3661303Swesolows 3671303Swesolows if ((problem_uuid_avl_pool = uu_avl_pool_create("problem_uuid", 3681303Swesolows sizeof (sunFmProblem_data_t), 3691303Swesolows offsetof(sunFmProblem_data_t, d_uuid_avl), problem_compare_uuid, 3701303Swesolows UU_AVL_DEBUG)) == NULL) { 3711303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": problem_uuid avl pool " 3721303Swesolows "creation failed: %s\n", uu_strerror(uu_error())); 3731303Swesolows snmp_free_varbind(table_info->indexes); 3741303Swesolows SNMP_FREE(table_info); 3751303Swesolows SNMP_FREE(handler); 3761303Swesolows return (MIB_REGISTRATION_FAILED); 3771303Swesolows } 3781303Swesolows 3791303Swesolows if ((problem_uuid_avl = uu_avl_create(problem_uuid_avl_pool, NULL, 3801303Swesolows UU_AVL_DEBUG)) == NULL) { 3811303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": problem_uuid avl creation " 3821303Swesolows "failed: %s\n", uu_strerror(uu_error())); 3831303Swesolows snmp_free_varbind(table_info->indexes); 3841303Swesolows SNMP_FREE(table_info); 3851303Swesolows SNMP_FREE(handler); 3861303Swesolows uu_avl_pool_destroy(problem_uuid_avl_pool); 3871303Swesolows return (MIB_REGISTRATION_FAILED); 3881303Swesolows } 3891303Swesolows 3901303Swesolows if ((err = netsnmp_register_table(handler, table_info)) != 3911303Swesolows MIB_REGISTERED_OK) { 3921303Swesolows snmp_free_varbind(table_info->indexes); 3931303Swesolows SNMP_FREE(table_info); 3941303Swesolows SNMP_FREE(handler); 3951303Swesolows uu_avl_destroy(problem_uuid_avl); 3961303Swesolows uu_avl_pool_destroy(problem_uuid_avl_pool); 3971303Swesolows return (err); 3981303Swesolows } 3991303Swesolows 4001303Swesolows return (MIB_REGISTERED_OK); 4011303Swesolows } 4021303Swesolows 4031303Swesolows int 4041303Swesolows sunFmFaultEventTable_init(void) 4051303Swesolows { 4061303Swesolows static oid sunFmFaultEventTable_oid[] = { SUNFMFAULTEVENTTABLE_OID }; 4071303Swesolows netsnmp_table_registration_info *table_info; 4081303Swesolows netsnmp_handler_registration *handler; 4091303Swesolows int err; 4101303Swesolows 4111303Swesolows if ((table_info = 4121303Swesolows SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL) 4131303Swesolows return (MIB_REGISTRATION_FAILED); 4141303Swesolows 4151303Swesolows if ((handler = 4161303Swesolows netsnmp_create_handler_registration("sunFmFaultEventTable", 4171303Swesolows sunFmFaultEventTable_handler, sunFmFaultEventTable_oid, 4181303Swesolows OID_LENGTH(sunFmFaultEventTable_oid), HANDLER_CAN_RONLY)) == NULL) { 4191303Swesolows SNMP_FREE(table_info); 4201303Swesolows return (MIB_REGISTRATION_FAILED); 4211303Swesolows } 4221303Swesolows 4231303Swesolows /* 4241303Swesolows * The Net-SNMP template uses add_indexes here, but that 4251303Swesolows * function is unsafe because it does not check for failure. 4261303Swesolows */ 4271303Swesolows if (netsnmp_table_helper_add_index(table_info, ASN_OCTET_STR) == NULL) { 4281303Swesolows SNMP_FREE(table_info); 4291303Swesolows SNMP_FREE(handler); 4301303Swesolows return (MIB_REGISTRATION_FAILED); 4311303Swesolows } 4321303Swesolows if (netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED) == NULL) { 4331303Swesolows snmp_free_varbind(table_info->indexes); 4341303Swesolows SNMP_FREE(table_info); 4351303Swesolows SNMP_FREE(handler); 4361303Swesolows return (MIB_REGISTRATION_FAILED); 4371303Swesolows } 4381303Swesolows 4391303Swesolows table_info->min_column = SUNFMFAULTEVENT_COLMIN; 4401303Swesolows table_info->max_column = SUNFMFAULTEVENT_COLMAX; 4411303Swesolows 4421303Swesolows if ((err = netsnmp_register_table(handler, table_info)) != 4431303Swesolows MIB_REGISTERED_OK) { 4441303Swesolows snmp_free_varbind(table_info->indexes); 4451303Swesolows SNMP_FREE(table_info); 4461303Swesolows SNMP_FREE(handler); 4471303Swesolows return (err); 4481303Swesolows } 4491303Swesolows 4501303Swesolows return (MIB_REGISTERED_OK); 4511303Swesolows } 4521303Swesolows 4531303Swesolows /* 4541303Swesolows * Returns the problem data for the problem whose uuid is next according 4551303Swesolows * to ASN.1 lexical ordering after the request in table_info. Indexes are 4561303Swesolows * updated to reflect the OID of the value being returned. This allows 4571303Swesolows * us to implement GETNEXT. 4581303Swesolows */ 4591303Swesolows static sunFmProblem_data_t * 4601303Swesolows sunFmProblemTable_nextpr(netsnmp_handler_registration *reginfo, 4611303Swesolows netsnmp_table_request_info *table_info) 4621303Swesolows { 4631303Swesolows sunFmProblem_data_t *data; 4641303Swesolows char *uuid = ""; 4651303Swesolows 4661303Swesolows if (table_info->number_indexes < 1) { 4671303Swesolows oid tmpoid[MAX_OID_LEN]; 4681303Swesolows 4691303Swesolows DEBUGMSGTL((MODNAME_STR, "nextpr: no indexes given\n")); 4701303Swesolows 4712134Swesolows snmp_free_varbind(table_info->indexes); 4721303Swesolows table_info->indexes = 4731303Swesolows SNMP_MALLOC_TYPEDEF(netsnmp_variable_list); 4741303Swesolows snmp_set_var_typed_value(table_info->indexes, ASN_OCTET_STR, 4751303Swesolows (const uchar_t *)uuid, 0); 4762134Swesolows (void) memcpy(tmpoid, reginfo->rootoid, 4771303Swesolows reginfo->rootoid_len * sizeof (oid)); 4781303Swesolows tmpoid[reginfo->rootoid_len] = 1; 4791303Swesolows tmpoid[reginfo->rootoid_len + 1] = table_info->colnum; 4801303Swesolows if (build_oid_segment(table_info->indexes) != SNMPERR_SUCCESS) { 4811303Swesolows snmp_free_varbind(table_info->indexes); 4821303Swesolows return (NULL); 4831303Swesolows } 4841303Swesolows table_info->number_indexes = 1; 4851303Swesolows table_info->index_oid_len = table_info->indexes->name_length; 4862134Swesolows (void) memcpy(table_info->index_oid, table_info->indexes->name, 4871303Swesolows table_info->indexes->name_length); 4881303Swesolows 4891303Swesolows DEBUGMSGTL((MODNAME_STR, "nextpr: built fake index:\n")); 4901303Swesolows DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 4911303Swesolows DEBUGMSG((MODNAME_STR, "\n")); 4921303Swesolows } else { 4931303Swesolows /* 4941303Swesolows * Construct the next possible UUID to look for. We can 4951303Swesolows * simply increment the least significant byte of the last 4961303Swesolows * UUID because (a) that preserves SNMP lex order and (b) 4971303Swesolows * the characters that may appear in a UUID do not include 4981303Swesolows * 127 nor 255. 4991303Swesolows */ 5001303Swesolows uuid = alloca(table_info->indexes->val_len + 1); 5011303Swesolows (void) strlcpy(uuid, 5021303Swesolows (const char *)table_info->indexes->val.string, 5031303Swesolows table_info->indexes->val_len + 1); 5041303Swesolows ++uuid[table_info->indexes->val_len - 1]; 5051303Swesolows 5061303Swesolows DEBUGMSGTL((MODNAME_STR, "nextpr: received index:\n")); 5071303Swesolows DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 5081303Swesolows DEBUGMSG((MODNAME_STR, "\n")); 5091303Swesolows } 5101303Swesolows 5111303Swesolows if ((data = problem_lookup_uuid_next(uuid)) == NULL) { 5121303Swesolows DEBUGMSGTL((MODNAME_STR, "nextpr: next match not found for " 5131303Swesolows "%s; trying next column\n", uuid)); 5142134Swesolows if (table_info->colnum >= 5152134Swesolows netsnmp_find_table_registration_info(reginfo)->max_column) { 5161303Swesolows snmp_free_varbind(table_info->indexes); 5171303Swesolows table_info->indexes = NULL; 5181303Swesolows table_info->number_indexes = 0; 5191303Swesolows DEBUGMSGTL((MODNAME_STR, "nextpr: out of columns\n")); 5201303Swesolows return (NULL); 5211303Swesolows } 5221303Swesolows table_info->colnum++; 5231303Swesolows DEBUGMSGTL((MODNAME_STR, "nextpr: search for col %u empty " 5241303Swesolows "uuid\n", table_info->colnum, uuid)); 5251303Swesolows 5261303Swesolows if ((data = problem_lookup_uuid_next("")) == NULL) { 5271303Swesolows DEBUGMSGTL((MODNAME_STR, "nextpr: next match not found " 5281303Swesolows "for empty uuid; stopping\n")); 5291303Swesolows snmp_free_varbind(table_info->indexes); 5301303Swesolows table_info->indexes = NULL; 5311303Swesolows table_info->number_indexes = 0; 5321303Swesolows return (NULL); 5331303Swesolows } 5341303Swesolows } 5351303Swesolows 5361303Swesolows snmp_set_var_typed_value(table_info->indexes, ASN_OCTET_STR, 5371303Swesolows (uchar_t *)data->d_aci_uuid, strlen(data->d_aci_uuid)); 5381303Swesolows table_info->number_indexes = 1; 5391303Swesolows 5401303Swesolows DEBUGMSGTL((MODNAME_STR, "matching data is %s@%p\n", data->d_aci_uuid, 5411303Swesolows data)); 5421303Swesolows 5431303Swesolows return (data); 5441303Swesolows } 5451303Swesolows 5461303Swesolows /* 5471303Swesolows * Returns the problem data corresponding to the request in table_info. 5481303Swesolows * All request parameters are unmodified. 5491303Swesolows */ 5502134Swesolows /*ARGSUSED*/ 5511303Swesolows static sunFmProblem_data_t * 5521303Swesolows sunFmProblemTable_pr(netsnmp_handler_registration *reginfo, 5531303Swesolows netsnmp_table_request_info *table_info) 5541303Swesolows { 5551303Swesolows char *uuid; 5561303Swesolows 5571303Swesolows ASSERT(table_info->number_indexes >= 1); 5581303Swesolows 5591303Swesolows uuid = alloca(table_info->indexes->val_len + 1); 5601303Swesolows (void) strlcpy(uuid, (const char *)table_info->indexes->val.string, 5611303Swesolows table_info->indexes->val_len + 1); 5621303Swesolows 5631303Swesolows return (problem_lookup_uuid_exact(uuid)); 5641303Swesolows } 5651303Swesolows 5661303Swesolows /* 5671303Swesolows * Returns the ASN.1 lexicographically first fault event after the one 5681303Swesolows * identified by table_info. Indexes are updated to reflect the OID 5691303Swesolows * of the data returned. This allows us to implement GETNEXT. 5701303Swesolows */ 5711303Swesolows static sunFmFaultEvent_data_t * 5721303Swesolows sunFmFaultEventTable_nextfe(netsnmp_handler_registration *reginfo, 5731303Swesolows netsnmp_table_request_info *table_info) 5741303Swesolows { 5751303Swesolows sunFmProblem_data_t *data; 5761303Swesolows sunFmFaultEvent_data_t *rv; 5771303Swesolows netsnmp_variable_list *var; 5781303Swesolows ulong_t index; 5791303Swesolows 5801303Swesolows for (;;) { 5811303Swesolows switch (table_info->number_indexes) { 5821303Swesolows case 2: 5831303Swesolows default: 5841303Swesolows DEBUGMSGTL((MODNAME_STR, "nextfe: 2 indices:\n")); 5851303Swesolows DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 5861303Swesolows DEBUGMSG((MODNAME_STR, "\n")); 5871303Swesolows DEBUGMSGVAR((MODNAME_STR, 5881303Swesolows table_info->indexes->next_variable)); 5891303Swesolows DEBUGMSG((MODNAME_STR, "\n")); 5901303Swesolows index = *(ulong_t *) 5911303Swesolows table_info->indexes->next_variable->val.integer + 1; 5921303Swesolows 5931303Swesolows if ((data = sunFmProblemTable_pr(reginfo, 5941303Swesolows table_info)) != NULL && 5951303Swesolows (rv = faultevent_lookup_index_exact(data, index)) != 5961303Swesolows NULL) { 5971303Swesolows snmp_set_var_typed_value( 5981303Swesolows table_info->indexes->next_variable, 5991303Swesolows ASN_UNSIGNED, (uchar_t *)&index, 6001303Swesolows sizeof (index)); 6011303Swesolows return (rv); 6021303Swesolows } 6031303Swesolows 6041303Swesolows if (sunFmProblemTable_nextpr(reginfo, table_info) == 6051303Swesolows NULL) 6061303Swesolows return (NULL); 6071303Swesolows break; 6081303Swesolows case 1: 6091303Swesolows if ((data = sunFmProblemTable_pr(reginfo, 6101303Swesolows table_info)) != NULL) { 6111303Swesolows oid tmpoid[MAX_OID_LEN]; 6121303Swesolows index = 0; 6131303Swesolows 6141303Swesolows DEBUGMSGTL((MODNAME_STR, "nextfe: 1 index:\n")); 6151303Swesolows DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 6161303Swesolows DEBUGMSG((MODNAME_STR, "\n")); 6171303Swesolows var = 6181303Swesolows SNMP_MALLOC_TYPEDEF(netsnmp_variable_list); 6191303Swesolows snmp_set_var_typed_value(var, ASN_UNSIGNED, 6201303Swesolows (uchar_t *)&index, sizeof (index)); 6212134Swesolows (void) memcpy(tmpoid, reginfo->rootoid, 6221303Swesolows reginfo->rootoid_len * sizeof (oid)); 6231303Swesolows tmpoid[reginfo->rootoid_len] = 1; 6241303Swesolows tmpoid[reginfo->rootoid_len + 1] = 6251303Swesolows table_info->colnum; 6261303Swesolows if (build_oid_segment(var) != SNMPERR_SUCCESS) { 6271303Swesolows snmp_free_varbind(var); 6281303Swesolows return (NULL); 6291303Swesolows } 6302134Swesolows snmp_free_varbind( 6312134Swesolows table_info->indexes->next_variable); 6321303Swesolows table_info->indexes->next_variable = var; 6331303Swesolows table_info->number_indexes = 2; 6341303Swesolows DEBUGMSGTL((MODNAME_STR, "nextfe: built fake " 6351303Swesolows "index:\n")); 6361303Swesolows DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 6371303Swesolows DEBUGMSG((MODNAME_STR, "\n")); 6381303Swesolows DEBUGMSGVAR((MODNAME_STR, 6391303Swesolows table_info->indexes->next_variable)); 6401303Swesolows DEBUGMSG((MODNAME_STR, "\n")); 6411303Swesolows } else { 6421303Swesolows if (sunFmProblemTable_nextpr(reginfo, 6431303Swesolows table_info) == NULL) 6441303Swesolows return (NULL); 6451303Swesolows } 6461303Swesolows break; 6471303Swesolows case 0: 6481303Swesolows if (sunFmProblemTable_nextpr(reginfo, table_info) == 6491303Swesolows NULL) 6501303Swesolows return (NULL); 6511303Swesolows break; 6521303Swesolows } 6531303Swesolows } 6541303Swesolows } 6551303Swesolows 656*7275Sstephh /* 657*7275Sstephh * Returns the ASN.1 lexicographically first fault event after the one 658*7275Sstephh * identified by table_info. Indexes are updated to reflect the OID 659*7275Sstephh * of the data returned. This allows us to implement GETNEXT. 660*7275Sstephh */ 661*7275Sstephh static sunFmFaultStatus_data_t 662*7275Sstephh sunFmFaultStatusTable_nextfe(netsnmp_handler_registration *reginfo, 663*7275Sstephh netsnmp_table_request_info *table_info) 664*7275Sstephh { 665*7275Sstephh sunFmProblem_data_t *data; 666*7275Sstephh sunFmFaultStatus_data_t rv; 667*7275Sstephh netsnmp_variable_list *var; 668*7275Sstephh ulong_t index; 669*7275Sstephh 670*7275Sstephh for (;;) { 671*7275Sstephh switch (table_info->number_indexes) { 672*7275Sstephh case 2: 673*7275Sstephh default: 674*7275Sstephh DEBUGMSGTL((MODNAME_STR, "nextfe: 2 indices:\n")); 675*7275Sstephh DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 676*7275Sstephh DEBUGMSG((MODNAME_STR, "\n")); 677*7275Sstephh DEBUGMSGVAR((MODNAME_STR, 678*7275Sstephh table_info->indexes->next_variable)); 679*7275Sstephh DEBUGMSG((MODNAME_STR, "\n")); 680*7275Sstephh index = *(ulong_t *) 681*7275Sstephh table_info->indexes->next_variable->val.integer + 1; 682*7275Sstephh 683*7275Sstephh if ((data = sunFmProblemTable_pr(reginfo, 684*7275Sstephh table_info)) != NULL && 685*7275Sstephh (rv = faultstatus_lookup_index_exact(data, 686*7275Sstephh index)) != NULL) { 687*7275Sstephh snmp_set_var_typed_value( 688*7275Sstephh table_info->indexes->next_variable, 689*7275Sstephh ASN_UNSIGNED, (uchar_t *)&index, 690*7275Sstephh sizeof (index)); 691*7275Sstephh return (rv); 692*7275Sstephh } 693*7275Sstephh 694*7275Sstephh if (sunFmProblemTable_nextpr(reginfo, table_info) == 695*7275Sstephh NULL) 696*7275Sstephh return (NULL); 697*7275Sstephh break; 698*7275Sstephh case 1: 699*7275Sstephh if ((data = sunFmProblemTable_pr(reginfo, 700*7275Sstephh table_info)) != NULL) { 701*7275Sstephh oid tmpoid[MAX_OID_LEN]; 702*7275Sstephh index = 0; 703*7275Sstephh 704*7275Sstephh DEBUGMSGTL((MODNAME_STR, "nextfe: 1 index:\n")); 705*7275Sstephh DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 706*7275Sstephh DEBUGMSG((MODNAME_STR, "\n")); 707*7275Sstephh var = 708*7275Sstephh SNMP_MALLOC_TYPEDEF(netsnmp_variable_list); 709*7275Sstephh snmp_set_var_typed_value(var, ASN_UNSIGNED, 710*7275Sstephh (uchar_t *)&index, sizeof (index)); 711*7275Sstephh (void) memcpy(tmpoid, reginfo->rootoid, 712*7275Sstephh reginfo->rootoid_len * sizeof (oid)); 713*7275Sstephh tmpoid[reginfo->rootoid_len] = 1; 714*7275Sstephh tmpoid[reginfo->rootoid_len + 1] = 715*7275Sstephh table_info->colnum; 716*7275Sstephh if (build_oid_segment(var) != SNMPERR_SUCCESS) { 717*7275Sstephh snmp_free_varbind(var); 718*7275Sstephh return (NULL); 719*7275Sstephh } 720*7275Sstephh snmp_free_varbind( 721*7275Sstephh table_info->indexes->next_variable); 722*7275Sstephh table_info->indexes->next_variable = var; 723*7275Sstephh table_info->number_indexes = 2; 724*7275Sstephh DEBUGMSGTL((MODNAME_STR, "nextfe: built fake " 725*7275Sstephh "index:\n")); 726*7275Sstephh DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 727*7275Sstephh DEBUGMSG((MODNAME_STR, "\n")); 728*7275Sstephh DEBUGMSGVAR((MODNAME_STR, 729*7275Sstephh table_info->indexes->next_variable)); 730*7275Sstephh DEBUGMSG((MODNAME_STR, "\n")); 731*7275Sstephh } else { 732*7275Sstephh if (sunFmProblemTable_nextpr(reginfo, 733*7275Sstephh table_info) == NULL) 734*7275Sstephh return (NULL); 735*7275Sstephh } 736*7275Sstephh break; 737*7275Sstephh case 0: 738*7275Sstephh if (sunFmProblemTable_nextpr(reginfo, table_info) == 739*7275Sstephh NULL) 740*7275Sstephh return (NULL); 741*7275Sstephh break; 742*7275Sstephh } 743*7275Sstephh } 744*7275Sstephh } 745*7275Sstephh 7461303Swesolows static sunFmFaultEvent_data_t * 7471303Swesolows sunFmFaultEventTable_fe(netsnmp_handler_registration *reginfo, 7481303Swesolows netsnmp_table_request_info *table_info) 7491303Swesolows { 7501303Swesolows sunFmProblem_data_t *data; 7511303Swesolows 7521303Swesolows ASSERT(table_info->number_indexes == 2); 7531303Swesolows 7541303Swesolows if ((data = sunFmProblemTable_pr(reginfo, table_info)) == NULL) 7551303Swesolows return (NULL); 7561303Swesolows 7571303Swesolows return (faultevent_lookup_index_exact(data, 7581303Swesolows *(ulong_t *)table_info->indexes->next_variable->val.integer)); 7591303Swesolows } 7601303Swesolows 761*7275Sstephh static sunFmFaultStatus_data_t 762*7275Sstephh sunFmFaultStatusTable_fe(netsnmp_handler_registration *reginfo, 763*7275Sstephh netsnmp_table_request_info *table_info) 764*7275Sstephh { 765*7275Sstephh sunFmProblem_data_t *data; 766*7275Sstephh 767*7275Sstephh ASSERT(table_info->number_indexes == 2); 768*7275Sstephh 769*7275Sstephh if ((data = sunFmProblemTable_pr(reginfo, table_info)) == NULL) 770*7275Sstephh return (NULL); 771*7275Sstephh 772*7275Sstephh return (faultstatus_lookup_index_exact(data, 773*7275Sstephh *(ulong_t *)table_info->indexes->next_variable->val.integer)); 774*7275Sstephh } 775*7275Sstephh 7762134Swesolows /*ARGSUSED*/ 7771303Swesolows static void 7781303Swesolows sunFmProblemTable_return(unsigned int reg, void *arg) 7791303Swesolows { 7801303Swesolows netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *)arg; 7811303Swesolows netsnmp_request_info *request; 7821303Swesolows netsnmp_agent_request_info *reqinfo; 7831303Swesolows netsnmp_handler_registration *reginfo; 7841303Swesolows netsnmp_table_request_info *table_info; 7851303Swesolows sunFmProblem_data_t *data; 7861303Swesolows 7871303Swesolows ASSERT(netsnmp_handler_check_cache(cache) != NULL); 7881303Swesolows 7891303Swesolows (void) pthread_mutex_lock(&update_lock); 7901303Swesolows if (update_status != US_QUIET) { 7911303Swesolows struct timeval tv; 7921303Swesolows 7931303Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 7941303Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 7951303Swesolows 7961303Swesolows (void) snmp_alarm_register_hr(tv, 0, sunFmProblemTable_return, 7971303Swesolows cache); 7981303Swesolows (void) pthread_mutex_unlock(&update_lock); 7991303Swesolows return; 8001303Swesolows } 8011303Swesolows 8021303Swesolows request = cache->requests; 8031303Swesolows reqinfo = cache->reqinfo; 8041303Swesolows reginfo = cache->reginfo; 8051303Swesolows 8061303Swesolows table_info = netsnmp_extract_table_info(request); 8071303Swesolows request->delegated = 0; 8081303Swesolows 8091303Swesolows ASSERT(table_info->colnum >= SUNFMPROBLEM_COLMIN); 8101303Swesolows ASSERT(table_info->colnum <= SUNFMPROBLEM_COLMAX); 8111303Swesolows 8121303Swesolows /* 8131303Swesolows * table_info->colnum contains the column number requested. 8141303Swesolows * table_info->indexes contains a linked list of snmp variable 8151303Swesolows * bindings for the indexes of the table. Values in the list 8161303Swesolows * have been set corresponding to the indexes of the 8171303Swesolows * request. We have other guarantees as well: 8181303Swesolows * 8191303Swesolows * - The column number is always within range. 8201303Swesolows * - If we have no index data, table_info->index_oid_len is 0. 8211303Swesolows * - We will never receive requests outside our table nor 8221303Swesolows * those with the first subid anything other than 1 (Entry) 8231303Swesolows * nor those without a column number. This is true even 8241303Swesolows * for GETNEXT requests. 8251303Swesolows */ 8261303Swesolows 8271303Swesolows switch (reqinfo->mode) { 8281303Swesolows case MODE_GET: 8291303Swesolows if ((data = sunFmProblemTable_pr(reginfo, table_info)) == 8301303Swesolows NULL) { 8311303Swesolows netsnmp_free_delegated_cache(cache); 8321303Swesolows (void) pthread_mutex_unlock(&update_lock); 8331303Swesolows return; 8341303Swesolows } 8351303Swesolows break; 8361303Swesolows case MODE_GETNEXT: 8371303Swesolows case MODE_GETBULK: 8381303Swesolows if ((data = sunFmProblemTable_nextpr(reginfo, table_info)) == 8391303Swesolows NULL) { 8401303Swesolows netsnmp_free_delegated_cache(cache); 8411303Swesolows (void) pthread_mutex_unlock(&update_lock); 8421303Swesolows return; 8431303Swesolows } 8441303Swesolows break; 8451303Swesolows default: 8461303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request mode %d\n", 8471303Swesolows reqinfo->mode); 8481303Swesolows netsnmp_free_delegated_cache(cache); 8491303Swesolows (void) pthread_mutex_unlock(&update_lock); 8501303Swesolows return; 8511303Swesolows } 8521303Swesolows 8531303Swesolows switch (table_info->colnum) { 8541303Swesolows case SUNFMPROBLEM_COL_UUID: 8551303Swesolows { 8561303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 8571303Swesolows ASN_OCTET_STR, (uchar_t *)data->d_aci_uuid, 8581303Swesolows strlen(data->d_aci_uuid)); 8591303Swesolows break; 8601303Swesolows } 8611303Swesolows case SUNFMPROBLEM_COL_CODE: 8621303Swesolows { 8631303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 8641303Swesolows ASN_OCTET_STR, (uchar_t *)data->d_aci_code, 8651303Swesolows strlen(data->d_aci_code)); 8661303Swesolows break; 8671303Swesolows } 8681303Swesolows case SUNFMPROBLEM_COL_URL: 8691303Swesolows { 8701303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 8711303Swesolows ASN_OCTET_STR, (uchar_t *)data->d_aci_url, 8721303Swesolows strlen(data->d_aci_url)); 8731303Swesolows break; 8741303Swesolows } 8751303Swesolows case SUNFMPROBLEM_COL_DIAGENGINE: 8761303Swesolows { 8771303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 8781303Swesolows ASN_OCTET_STR, (uchar_t *)data->d_diag_engine, 8791303Swesolows strlen(data->d_diag_engine)); 8801303Swesolows break; 8811303Swesolows } 8821303Swesolows case SUNFMPROBLEM_COL_DIAGTIME: 8831303Swesolows { 8841303Swesolows /* 8851303Swesolows * The date_n_time function is not Y2038-safe; this may 8861303Swesolows * need to be updated when a suitable Y2038-safe Net-SNMP 8871303Swesolows * API is available. 8881303Swesolows */ 8891303Swesolows size_t dt_size; 8901303Swesolows time_t dt_time = (time_t)data->d_diag_time.tv_sec; 8911303Swesolows uchar_t *dt = date_n_time(&dt_time, &dt_size); 8921303Swesolows 8931303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 8941303Swesolows ASN_OCTET_STR, dt, dt_size); 8951303Swesolows break; 8961303Swesolows } 8971303Swesolows case SUNFMPROBLEM_COL_SUSPECTCOUNT: 8981303Swesolows { 8991303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 9001303Swesolows ASN_UNSIGNED, (uchar_t *)&data->d_nsuspects, 9011303Swesolows sizeof (data->d_nsuspects)); 9021303Swesolows break; 9031303Swesolows } 9041303Swesolows default: 9051303Swesolows break; 9061303Swesolows } 9071303Swesolows 9081303Swesolows netsnmp_free_delegated_cache(cache); 9091303Swesolows (void) pthread_mutex_unlock(&update_lock); 9101303Swesolows } 9111303Swesolows 9121303Swesolows static int 9131303Swesolows sunFmProblemTable_handler(netsnmp_mib_handler *handler, 9141303Swesolows netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, 9151303Swesolows netsnmp_request_info *requests) 9161303Swesolows { 9171303Swesolows netsnmp_request_info *request; 9181303Swesolows struct timeval tv; 9191303Swesolows 9201303Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 9211303Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 9221303Swesolows 9231303Swesolows request_update(); 9241303Swesolows 9251303Swesolows for (request = requests; request; request = request->next) { 9261303Swesolows if (request->processed != 0) 9271303Swesolows continue; 9281303Swesolows 9291303Swesolows if (netsnmp_extract_table_info(request) == NULL) 9301303Swesolows continue; 9311303Swesolows 9321303Swesolows request->delegated = 1; 9331303Swesolows (void) snmp_alarm_register_hr(tv, 0, 9341303Swesolows sunFmProblemTable_return, 9351303Swesolows (void *) netsnmp_create_delegated_cache(handler, reginfo, 9361303Swesolows reqinfo, request, NULL)); 9371303Swesolows } 9381303Swesolows 9391303Swesolows return (SNMP_ERR_NOERROR); 9401303Swesolows } 9411303Swesolows 9422134Swesolows /*ARGSUSED*/ 9431303Swesolows static void 9441303Swesolows sunFmFaultEventTable_return(unsigned int reg, void *arg) 9451303Swesolows { 9461303Swesolows netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *)arg; 9471303Swesolows netsnmp_request_info *request; 9481303Swesolows netsnmp_agent_request_info *reqinfo; 9491303Swesolows netsnmp_handler_registration *reginfo; 9501303Swesolows netsnmp_table_request_info *table_info; 9511303Swesolows sunFmProblem_data_t *pdata; 9521303Swesolows sunFmFaultEvent_data_t *data; 953*7275Sstephh sunFmFaultStatus_data_t status; 9541303Swesolows 9551303Swesolows ASSERT(netsnmp_handler_check_cache(cache) != NULL); 9561303Swesolows 9571303Swesolows (void) pthread_mutex_lock(&update_lock); 9581303Swesolows if (update_status != US_QUIET) { 9591303Swesolows struct timeval tv; 9601303Swesolows 9611303Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 9621303Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 9631303Swesolows 9641303Swesolows (void) snmp_alarm_register_hr(tv, 0, 9651303Swesolows sunFmFaultEventTable_return, cache); 9661303Swesolows (void) pthread_mutex_unlock(&update_lock); 9671303Swesolows return; 9681303Swesolows } 9691303Swesolows 9701303Swesolows request = cache->requests; 9711303Swesolows reqinfo = cache->reqinfo; 9721303Swesolows reginfo = cache->reginfo; 9731303Swesolows 9741303Swesolows table_info = netsnmp_extract_table_info(request); 9751303Swesolows request->delegated = 0; 9761303Swesolows 9771303Swesolows ASSERT(table_info->colnum >= SUNFMFAULTEVENT_COLMIN); 9781303Swesolows ASSERT(table_info->colnum <= SUNFMFAULTEVENT_COLMAX); 9791303Swesolows 9801303Swesolows /* 9811303Swesolows * table_info->colnum contains the column number requested. 9821303Swesolows * table_info->indexes contains a linked list of snmp variable 9831303Swesolows * bindings for the indexes of the table. Values in the list 9841303Swesolows * have been set corresponding to the indexes of the 9851303Swesolows * request. We have other guarantees as well: 9861303Swesolows * 9871303Swesolows * - The column number is always within range. 9881303Swesolows * - If we have no index data, table_info->index_oid_len is 0. 9891303Swesolows * - We will never receive requests outside our table nor 9901303Swesolows * those with the first subid anything other than 1 (Entry) 9911303Swesolows * nor those without a column number. This is true even 9921303Swesolows * for GETNEXT requests. 9931303Swesolows */ 9941303Swesolows 995*7275Sstephh if (table_info->colnum == SUNFMFAULTEVENT_COL_STATUS) { 996*7275Sstephh switch (reqinfo->mode) { 997*7275Sstephh case MODE_GET: 998*7275Sstephh if ((status = sunFmFaultStatusTable_fe(reginfo, 999*7275Sstephh table_info)) == NULL) { 1000*7275Sstephh netsnmp_free_delegated_cache(cache); 1001*7275Sstephh (void) pthread_mutex_unlock(&update_lock); 1002*7275Sstephh return; 1003*7275Sstephh } 1004*7275Sstephh break; 1005*7275Sstephh case MODE_GETNEXT: 1006*7275Sstephh case MODE_GETBULK: 1007*7275Sstephh if ((status = sunFmFaultStatusTable_nextfe(reginfo, 1008*7275Sstephh table_info)) == NULL) { 1009*7275Sstephh netsnmp_free_delegated_cache(cache); 1010*7275Sstephh (void) pthread_mutex_unlock(&update_lock); 1011*7275Sstephh return; 1012*7275Sstephh } 1013*7275Sstephh break; 1014*7275Sstephh default: 1015*7275Sstephh snmp_log(LOG_ERR, MODNAME_STR 1016*7275Sstephh ": Unsupported request mode %d\n", reqinfo->mode); 10171303Swesolows netsnmp_free_delegated_cache(cache); 10181303Swesolows (void) pthread_mutex_unlock(&update_lock); 10191303Swesolows return; 10201303Swesolows } 1021*7275Sstephh } else { 1022*7275Sstephh switch (reqinfo->mode) { 1023*7275Sstephh case MODE_GET: 1024*7275Sstephh if ((data = sunFmFaultEventTable_fe(reginfo, 1025*7275Sstephh table_info)) == NULL) { 1026*7275Sstephh netsnmp_free_delegated_cache(cache); 1027*7275Sstephh (void) pthread_mutex_unlock(&update_lock); 1028*7275Sstephh return; 1029*7275Sstephh } 1030*7275Sstephh break; 1031*7275Sstephh case MODE_GETNEXT: 1032*7275Sstephh case MODE_GETBULK: 1033*7275Sstephh if ((data = sunFmFaultEventTable_nextfe(reginfo, 1034*7275Sstephh table_info)) == NULL) { 1035*7275Sstephh netsnmp_free_delegated_cache(cache); 1036*7275Sstephh (void) pthread_mutex_unlock(&update_lock); 1037*7275Sstephh return; 1038*7275Sstephh } 1039*7275Sstephh break; 1040*7275Sstephh default: 1041*7275Sstephh snmp_log(LOG_ERR, MODNAME_STR 1042*7275Sstephh ": Unsupported request mode %d\n", reqinfo->mode); 10431303Swesolows netsnmp_free_delegated_cache(cache); 10441303Swesolows (void) pthread_mutex_unlock(&update_lock); 10451303Swesolows return; 10461303Swesolows } 10471303Swesolows } 10481303Swesolows 10491303Swesolows switch (table_info->colnum) { 10501303Swesolows case SUNFMFAULTEVENT_COL_PROBLEMUUID: 10511303Swesolows { 10521303Swesolows if ((pdata = sunFmProblemTable_pr(reginfo, table_info)) 10531303Swesolows == NULL) { 10541303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 10551303Swesolows ASN_OCTET_STR, NULL, 0); 10561303Swesolows break; 10571303Swesolows } 10581303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 10591303Swesolows ASN_OCTET_STR, (uchar_t *)pdata->d_aci_uuid, 10601303Swesolows strlen(pdata->d_aci_uuid)); 10611303Swesolows break; 10621303Swesolows } 10631303Swesolows case SUNFMFAULTEVENT_COL_CLASS: 10641303Swesolows { 10651303Swesolows char *class = "-"; 10661303Swesolows 10671303Swesolows (void) nvlist_lookup_string(data, FM_CLASS, &class); 10681303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 10691303Swesolows ASN_OCTET_STR, (uchar_t *)class, strlen(class)); 10701303Swesolows break; 10711303Swesolows } 10721303Swesolows case SUNFMFAULTEVENT_COL_CERTAINTY: 10731303Swesolows { 10741303Swesolows uint8_t pct = 0; 10751303Swesolows ulong_t pl; 10761303Swesolows 10771303Swesolows (void) nvlist_lookup_uint8(data, FM_FAULT_CERTAINTY, 10781303Swesolows &pct); 10791303Swesolows pl = (ulong_t)pct; 10801303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 10811303Swesolows ASN_UNSIGNED, (uchar_t *)&pl, sizeof (pl)); 10821303Swesolows break; 10831303Swesolows } 10841303Swesolows case SUNFMFAULTEVENT_COL_ASRU: 10851303Swesolows { 10861303Swesolows nvlist_t *asru = NULL; 10872134Swesolows char *fmri, *str; 10881303Swesolows 10891303Swesolows (void) nvlist_lookup_nvlist(data, FM_FAULT_ASRU, &asru); 10902134Swesolows if ((str = sunFm_nvl2str(asru)) == NULL) 10911303Swesolows fmri = "-"; 10922134Swesolows else 10932134Swesolows fmri = str; 10942134Swesolows 10951303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 10961303Swesolows ASN_OCTET_STR, (uchar_t *)fmri, strlen(fmri)); 10972134Swesolows free(str); 10981303Swesolows break; 10991303Swesolows } 11001303Swesolows case SUNFMFAULTEVENT_COL_FRU: 11011303Swesolows { 11021303Swesolows nvlist_t *fru = NULL; 11032134Swesolows char *fmri, *str; 11041303Swesolows 11051303Swesolows (void) nvlist_lookup_nvlist(data, FM_FAULT_FRU, &fru); 11062134Swesolows if ((str = sunFm_nvl2str(fru)) == NULL) 11071303Swesolows fmri = "-"; 11082134Swesolows else 11092134Swesolows fmri = str; 11102134Swesolows 11111303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 11121303Swesolows ASN_OCTET_STR, (uchar_t *)fmri, strlen(fmri)); 11132134Swesolows free(str); 11141303Swesolows break; 11151303Swesolows } 11161303Swesolows case SUNFMFAULTEVENT_COL_RESOURCE: 11171303Swesolows { 11181303Swesolows nvlist_t *rsrc = NULL; 11192134Swesolows char *fmri, *str; 11201303Swesolows 11212134Swesolows (void) nvlist_lookup_nvlist(data, FM_FAULT_RESOURCE, &rsrc); 11222134Swesolows if ((str = sunFm_nvl2str(rsrc)) == NULL) 11231303Swesolows fmri = "-"; 11242134Swesolows else 11252134Swesolows fmri = str; 11262134Swesolows 11271303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 11281303Swesolows ASN_OCTET_STR, (uchar_t *)fmri, strlen(fmri)); 11292134Swesolows free(str); 11301303Swesolows break; 11311303Swesolows } 1132*7275Sstephh case SUNFMFAULTEVENT_COL_STATUS: 1133*7275Sstephh { 1134*7275Sstephh ulong_t pl; 1135*7275Sstephh 1136*7275Sstephh if (status & FM_SUSPECT_FAULTY) 1137*7275Sstephh pl = SUNFMFAULTEVENT_STATE_FAULTY; 1138*7275Sstephh else if (status & FM_SUSPECT_NOT_PRESENT) 1139*7275Sstephh pl = SUNFMFAULTEVENT_STATE_REMOVED; 1140*7275Sstephh else if (status & FM_SUSPECT_REPLACED) 1141*7275Sstephh pl = SUNFMFAULTEVENT_STATE_REPLACED; 1142*7275Sstephh else if (status & FM_SUSPECT_REPAIRED) 1143*7275Sstephh pl = SUNFMFAULTEVENT_STATE_REPAIRED; 1144*7275Sstephh else if (status & FM_SUSPECT_ACQUITTED) 1145*7275Sstephh pl = SUNFMFAULTEVENT_STATE_ACQUITTED; 1146*7275Sstephh netsnmp_table_build_result(reginfo, request, table_info, 1147*7275Sstephh ASN_UNSIGNED, (uchar_t *)&pl, sizeof (pl)); 1148*7275Sstephh break; 1149*7275Sstephh } 1150*7275Sstephh case SUNFMFAULTEVENT_COL_LOCATION: 1151*7275Sstephh { 1152*7275Sstephh char *location = "-"; 1153*7275Sstephh 1154*7275Sstephh (void) nvlist_lookup_string(data, FM_FAULT_LOCATION, &location); 1155*7275Sstephh netsnmp_table_build_result(reginfo, request, table_info, 1156*7275Sstephh ASN_OCTET_STR, (uchar_t *)location, strlen(location)); 1157*7275Sstephh break; 1158*7275Sstephh } 11591303Swesolows default: 11601303Swesolows break; 11611303Swesolows } 11621303Swesolows 11631303Swesolows netsnmp_free_delegated_cache(cache); 11641303Swesolows (void) pthread_mutex_unlock(&update_lock); 11651303Swesolows } 11661303Swesolows 11671303Swesolows static int 11681303Swesolows sunFmFaultEventTable_handler(netsnmp_mib_handler *handler, 11691303Swesolows netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, 11701303Swesolows netsnmp_request_info *requests) 11711303Swesolows { 11721303Swesolows netsnmp_request_info *request; 11731303Swesolows struct timeval tv; 11741303Swesolows 11751303Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 11761303Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 11771303Swesolows 11781303Swesolows request_update(); 11791303Swesolows 11801303Swesolows for (request = requests; request; request = request->next) { 11811303Swesolows if (request->processed != 0) 11821303Swesolows continue; 11831303Swesolows 11841303Swesolows if (netsnmp_extract_table_info(request) == NULL) 11851303Swesolows continue; 11861303Swesolows 11871303Swesolows request->delegated = 1; 11881303Swesolows (void) snmp_alarm_register_hr(tv, 0, 11891303Swesolows sunFmFaultEventTable_return, 11901303Swesolows (void *) netsnmp_create_delegated_cache(handler, reginfo, 11911303Swesolows reqinfo, request, NULL)); 11921303Swesolows } 11931303Swesolows 11941303Swesolows return (SNMP_ERR_NOERROR); 11951303Swesolows } 1196