1266936Sloos/*- 2266936Sloos * Copyright (c) 2014 Luiz Otavio O Souza <loos@FreeBSD.org> 3266936Sloos * All rights reserved. 4266936Sloos * 5266936Sloos * Redistribution and use in source and binary forms, with or without 6266936Sloos * modification, are permitted provided that the following conditions 7266936Sloos * are met: 8266936Sloos * 1. Redistributions of source code must retain the above copyright 9266936Sloos * notice, this list of conditions and the following disclaimer. 10266936Sloos * 2. Redistributions in binary form must reproduce the above copyright 11266936Sloos * notice, this list of conditions and the following disclaimer in the 12266936Sloos * documentation and/or other materials provided with the distribution. 13266936Sloos * 14266936Sloos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 15266936Sloos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16266936Sloos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17266936Sloos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 18266936Sloos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19266936Sloos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20266936Sloos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21266936Sloos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22266936Sloos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23266936Sloos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24266936Sloos * SUCH DAMAGE. 25266936Sloos */ 26266936Sloos 27266936Sloos#include <sys/cdefs.h> 28266936Sloos__FBSDID("$FreeBSD: releng/11.0/usr.sbin/bsnmpd/modules/snmp_lm75/snmp_lm75.c 267971 2014-06-27 18:58:22Z loos $"); 29266936Sloos 30266936Sloos#include <sys/param.h> 31266936Sloos#include <sys/queue.h> 32266936Sloos#include <sys/sysctl.h> 33266936Sloos 34266936Sloos#include <bsnmp/snmpmod.h> 35266936Sloos 36266936Sloos#include <stdio.h> 37266936Sloos#include <stdlib.h> 38266936Sloos#include <string.h> 39266936Sloos#include <syslog.h> 40266936Sloos 41266936Sloos#include "lm75_oid.h" 42266936Sloos#include "lm75_tree.h" 43266936Sloos 44266936Sloos#ifndef LM75BUF 45266936Sloos#define LM75BUF 64 46266936Sloos#endif 47266936Sloos#define TZ_ZEROC 2732 48266936Sloos#define UPDATE_INTERVAL 500 /* update interval in ticks */ 49266936Sloos 50266936Sloosstatic struct lmodule *module; 51266936Sloos 52266936Sloosstatic const struct asn_oid oid_lm75 = OIDX_begemotLm75; 53266936Sloos 54266936Sloos/* the Object Resource registration index */ 55266936Sloosstatic u_int lm75_index = 0; 56266936Sloos 57266936Sloos/* Number of available sensors in the system. */ 58266936Sloosstatic int lm75_sensors; 59266936Sloos 60266936Sloos/* 61266936Sloos * Structure that describes single sensor. 62266936Sloos */ 63266936Sloosstruct lm75_snmp_sensor { 64266936Sloos TAILQ_ENTRY(lm75_snmp_sensor) link; 65266936Sloos int32_t index; 66266936Sloos int32_t sysctlidx; 67266936Sloos int32_t temp; 68266936Sloos char desc[LM75BUF]; 69266936Sloos char location[LM75BUF]; 70266936Sloos char parent[LM75BUF]; 71266936Sloos char pnpinfo[LM75BUF]; 72266936Sloos}; 73266936Sloos 74266936Sloosstatic TAILQ_HEAD(, lm75_snmp_sensor) sensors = 75266936Sloos TAILQ_HEAD_INITIALIZER(sensors); 76266936Sloos 77266936Sloos/* Ticks of the last sensors reading. */ 78266936Sloosstatic uint64_t last_sensors_update; 79266936Sloos 80266936Sloosstatic void free_sensors(void); 81266936Sloosstatic int lm75_fini(void); 82266936Sloosstatic int lm75_init(struct lmodule *mod, int argc, char *argv[]); 83266936Sloosstatic void lm75_start(void); 84266936Sloosstatic int update_sensors(void); 85266936Sloos 86266936Sloosconst struct snmp_module config = { 87266936Sloos .comment = 88266936Sloos "This module implements the BEGEMOT MIB for reading LM75 sensors data.", 89266936Sloos .init = lm75_init, 90266936Sloos .start = lm75_start, 91266936Sloos .fini = lm75_fini, 92266936Sloos .tree = lm75_ctree, 93266936Sloos .tree_size = lm75_CTREE_SIZE, 94266936Sloos}; 95266936Sloos 96266936Sloosstatic int 97266936Slooslm75_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) 98266936Sloos{ 99266936Sloos 100266936Sloos module = mod; 101266936Sloos 102266936Sloos lm75_sensors = 0; 103266936Sloos openlog("snmp_lm75", LOG_NDELAY | LOG_PID, LOG_DAEMON); 104266936Sloos 105266936Sloos return(0); 106266936Sloos} 107266936Sloos 108266936Sloosstatic void 109266936Slooslm75_start(void) 110266936Sloos{ 111266936Sloos 112266936Sloos lm75_index = or_register(&oid_lm75, 113266936Sloos "The MIB module for reading lm75 sensors data.", module); 114266936Sloos} 115266936Sloos 116266936Sloosstatic int 117266936Slooslm75_fini(void) 118266936Sloos{ 119266936Sloos 120266936Sloos or_unregister(lm75_index); 121266936Sloos free_sensors(); 122266936Sloos closelog(); 123266936Sloos 124266936Sloos return (0); 125266936Sloos} 126266936Sloos 127266936Sloosstatic void 128266936Sloosfree_sensors(void) 129266936Sloos{ 130266936Sloos struct lm75_snmp_sensor *sensor; 131266936Sloos 132266936Sloos while ((sensor = TAILQ_FIRST(&sensors)) != NULL) { 133266936Sloos TAILQ_REMOVE(&sensors, sensor, link); 134266936Sloos free(sensor); 135266936Sloos } 136266936Sloos} 137266936Sloos 138266936Sloosstatic int 139266936Sloossysctlname(int *oid, int nlen, char *name, size_t len) 140266936Sloos{ 141266936Sloos int mib[12]; 142266936Sloos 143267969Sloos if (nlen > (int)(sizeof(mib) / sizeof(int) - 2)) 144266936Sloos return (-1); 145266936Sloos 146266936Sloos mib[0] = 0; 147266936Sloos mib[1] = 1; 148266936Sloos memcpy(mib + 2, oid, nlen * sizeof(int)); 149266936Sloos 150266936Sloos if (sysctl(mib, nlen + 2, name, &len, 0, 0) == -1) 151266936Sloos return (-1); 152266936Sloos 153266936Sloos return (0); 154266936Sloos} 155266936Sloos 156266936Sloosstatic int 157266936Sloossysctlgetnext(int *oid, int nlen, int *next, size_t *nextlen) 158266936Sloos{ 159266936Sloos int mib[12]; 160266936Sloos 161267969Sloos if (nlen > (int)(sizeof(mib) / sizeof(int) - 2)) 162266936Sloos return (-1); 163266936Sloos 164266936Sloos mib[0] = 0; 165266936Sloos mib[1] = 2; 166266936Sloos memcpy(mib + 2, oid, nlen * sizeof(int)); 167266936Sloos 168266936Sloos if (sysctl(mib, nlen + 2, next, nextlen, 0, 0) == -1) 169266936Sloos return (-1); 170266936Sloos 171266936Sloos return (0); 172266936Sloos} 173266936Sloos 174266936Sloosstatic int 175267971Sloosupdate_sensor_sysctl(void *obuf, size_t *obuflen, int idx, const char *name) 176266936Sloos{ 177266936Sloos char buf[LM75BUF]; 178266936Sloos int mib[5]; 179266936Sloos size_t len; 180266936Sloos 181266936Sloos /* Fill out the mib information. */ 182266936Sloos snprintf(buf, sizeof(buf) - 1, "dev.lm75.%d.%s", idx, name); 183267969Sloos len = sizeof(mib) / sizeof(int); 184266936Sloos if (sysctlnametomib(buf, mib, &len) == -1) 185266936Sloos return (-1); 186266936Sloos 187267969Sloos if (len != 4) 188267969Sloos return (-1); 189267969Sloos 190266936Sloos /* Read the sysctl data. */ 191266936Sloos if (sysctl(mib, len, obuf, obuflen, NULL, 0) == -1) 192266936Sloos return (-1); 193266936Sloos 194266936Sloos return (0); 195266936Sloos} 196266936Sloos 197266936Sloosstatic void 198266936Sloosupdate_sensor(struct lm75_snmp_sensor *sensor, int idx) 199266936Sloos{ 200266936Sloos size_t len; 201266936Sloos 202266936Sloos len = sizeof(sensor->desc); 203266936Sloos update_sensor_sysctl(sensor->desc, &len, idx, "%desc"); 204266936Sloos 205266936Sloos len = sizeof(sensor->location); 206266936Sloos update_sensor_sysctl(sensor->location, &len, idx, "%location"); 207266936Sloos 208266936Sloos len = sizeof(sensor->pnpinfo); 209266936Sloos update_sensor_sysctl(sensor->pnpinfo, &len, idx, "%pnpinfo"); 210266936Sloos 211266936Sloos len = sizeof(sensor->parent); 212266936Sloos update_sensor_sysctl(sensor->parent, &len, idx, "%parent"); 213266936Sloos} 214266936Sloos 215266936Sloosstatic int 216267971Sloosadd_sensor(char *buf) 217266936Sloos{ 218267971Sloos int idx, temp; 219266936Sloos size_t len; 220266936Sloos struct lm75_snmp_sensor *sensor; 221266936Sloos 222266936Sloos if (sscanf(buf, "dev.lm75.%d.temperature", &idx) != 1) 223266936Sloos return (-1); 224266936Sloos 225266936Sloos /* Read the sensor temperature. */ 226266936Sloos len = sizeof(temp); 227267971Sloos if (update_sensor_sysctl(&temp, &len, idx, "temperature") != 0) 228266936Sloos return (-1); 229266936Sloos 230266936Sloos /* Add the sensor data to the table. */ 231266936Sloos sensor = calloc(1, sizeof(*sensor)); 232266936Sloos if (sensor == NULL) { 233266936Sloos syslog(LOG_ERR, "Unable to allocate %zu bytes for resource", 234266936Sloos sizeof(*sensor)); 235266936Sloos return (-1); 236266936Sloos } 237266936Sloos sensor->index = ++lm75_sensors; 238266936Sloos sensor->sysctlidx = idx; 239266936Sloos sensor->temp = (temp - TZ_ZEROC) / 10; 240266936Sloos TAILQ_INSERT_TAIL(&sensors, sensor, link); 241266936Sloos 242266936Sloos update_sensor(sensor, idx); 243266936Sloos 244266936Sloos return (0); 245266936Sloos} 246266936Sloos 247266936Sloosstatic int 248266936Sloosupdate_sensors(void) 249266936Sloos{ 250266936Sloos char buf[LM75BUF]; 251266936Sloos int i, root[5], *next, *oid; 252266936Sloos size_t len, nextlen, rootlen; 253266936Sloos static uint64_t now; 254266936Sloos 255266936Sloos now = get_ticks(); 256266936Sloos if (now - last_sensors_update < UPDATE_INTERVAL) 257266936Sloos return (0); 258266936Sloos 259266936Sloos last_sensors_update = now; 260266936Sloos 261266936Sloos /* Reset the sensor data. */ 262266936Sloos free_sensors(); 263266936Sloos lm75_sensors = 0; 264266936Sloos 265266936Sloos /* Start from the lm75 default root node. */ 266266936Sloos rootlen = 2; 267266936Sloos if (sysctlnametomib("dev.lm75", root, &rootlen) == -1) 268266936Sloos return (0); 269266936Sloos 270266936Sloos oid = (int *)malloc(sizeof(int) * rootlen); 271266936Sloos if (oid == NULL) { 272266936Sloos perror("malloc"); 273266936Sloos return (-1); 274266936Sloos } 275266936Sloos memcpy(oid, root, rootlen * sizeof(int)); 276266936Sloos len = rootlen; 277266936Sloos 278266936Sloos /* Traverse the sysctl(3) interface and find the active sensors. */ 279266936Sloos for (;;) { 280266936Sloos 281266936Sloos /* Find the size of the next mib. */ 282266936Sloos nextlen = 0; 283266936Sloos if (sysctlgetnext(oid, len, NULL, &nextlen) == -1) { 284266936Sloos free(oid); 285266936Sloos return (0); 286266936Sloos } 287266936Sloos /* Alocate and read the next mib. */ 288266936Sloos next = (int *)malloc(nextlen); 289266936Sloos if (next == NULL) { 290266936Sloos syslog(LOG_ERR, 291266936Sloos "Unable to allocate %zu bytes for resource", 292266936Sloos nextlen); 293266936Sloos free(oid); 294266936Sloos return (-1); 295266936Sloos } 296266936Sloos if (sysctlgetnext(oid, len, next, &nextlen) == -1) { 297266936Sloos free(oid); 298266936Sloos free(next); 299266936Sloos return (0); 300266936Sloos } 301266936Sloos free(oid); 302266936Sloos /* Check if we care about the next mib. */ 303266936Sloos for (i = 0; i < (int)rootlen; i++) 304266936Sloos if (next[i] != root[i]) { 305266936Sloos free(next); 306266936Sloos return (0); 307266936Sloos } 308266936Sloos oid = (int *)malloc(nextlen); 309266936Sloos if (oid == NULL) { 310266936Sloos syslog(LOG_ERR, 311266936Sloos "Unable to allocate %zu bytes for resource", 312266936Sloos nextlen); 313266936Sloos free(next); 314266936Sloos return (-1); 315266936Sloos } 316266936Sloos memcpy(oid, next, nextlen); 317266936Sloos free(next); 318266936Sloos len = nextlen / sizeof(int); 319266936Sloos 320266936Sloos /* Find the mib name. */ 321266936Sloos if (sysctlname(oid, len, buf, sizeof(buf)) != 0) 322266936Sloos continue; 323266936Sloos 324266936Sloos if (strstr(buf, "temperature")) 325267971Sloos if (add_sensor(buf) != 0) { 326266936Sloos free(oid); 327266936Sloos return (-1); 328266936Sloos } 329266936Sloos } 330266936Sloos 331266936Sloos return (0); 332266936Sloos} 333266936Sloos 334266936Sloosint 335266936Sloosop_lm75Sensors(struct snmp_context *context __unused, struct snmp_value *value, 336266936Sloos u_int sub, u_int iidx __unused, enum snmp_op op) 337266936Sloos{ 338266936Sloos asn_subid_t which; 339266936Sloos 340266936Sloos if (update_sensors() == -1) 341266936Sloos return (SNMP_ERR_RES_UNAVAIL); 342266936Sloos 343266936Sloos which = value->var.subs[sub - 1]; 344266936Sloos 345266936Sloos switch (op) { 346266936Sloos case SNMP_OP_GET: 347266936Sloos switch (which) { 348266936Sloos case LEAF_lm75Sensors: 349266936Sloos value->v.integer = lm75_sensors; 350266936Sloos break; 351266936Sloos default: 352266936Sloos return (SNMP_ERR_RES_UNAVAIL); 353266936Sloos } 354266936Sloos break; 355266936Sloos case SNMP_OP_SET: 356266936Sloos return (SNMP_ERR_NOT_WRITEABLE); 357266936Sloos case SNMP_OP_GETNEXT: 358266936Sloos case SNMP_OP_ROLLBACK: 359266936Sloos case SNMP_OP_COMMIT: 360266936Sloos return (SNMP_ERR_NOERROR); 361266936Sloos default: 362266936Sloos return (SNMP_ERR_RES_UNAVAIL); 363266936Sloos } 364266936Sloos 365266936Sloos return (SNMP_ERR_NOERROR); 366266936Sloos} 367266936Sloos 368266936Sloosint 369266936Sloosop_lm75SensorTable(struct snmp_context *context __unused, 370266936Sloos struct snmp_value *value, u_int sub, u_int iidx __unused, enum snmp_op op) 371266936Sloos{ 372266936Sloos struct lm75_snmp_sensor *sensor; 373266936Sloos asn_subid_t which; 374266936Sloos int ret; 375266936Sloos 376266936Sloos if (update_sensors() == -1) 377266936Sloos return (SNMP_ERR_RES_UNAVAIL); 378266936Sloos 379266936Sloos which = value->var.subs[sub - 1]; 380266936Sloos 381266936Sloos switch (op) { 382266936Sloos case SNMP_OP_GETNEXT: 383266936Sloos sensor = NEXT_OBJECT_INT(&sensors, &value->var, sub); 384266936Sloos if (sensor == NULL) 385266936Sloos return (SNMP_ERR_NOSUCHNAME); 386266936Sloos value->var.len = sub + 1; 387266936Sloos value->var.subs[sub] = sensor->index; 388266936Sloos break; 389266936Sloos case SNMP_OP_GET: 390266936Sloos if (value->var.len - sub != 1) 391266936Sloos return (SNMP_ERR_NOSUCHNAME); 392266936Sloos sensor = FIND_OBJECT_INT(&sensors, &value->var, sub); 393266936Sloos if (sensor == NULL) 394266936Sloos return (SNMP_ERR_NOSUCHNAME); 395266936Sloos break; 396266936Sloos case SNMP_OP_SET: 397266936Sloos return (SNMP_ERR_NOT_WRITEABLE); 398266936Sloos case SNMP_OP_ROLLBACK: 399266936Sloos case SNMP_OP_COMMIT: 400266936Sloos return (SNMP_ERR_NOERROR); 401266936Sloos default: 402266936Sloos return (SNMP_ERR_RES_UNAVAIL); 403266936Sloos } 404266936Sloos 405266936Sloos ret = SNMP_ERR_NOERROR; 406266936Sloos 407266936Sloos switch (which) { 408266936Sloos case LEAF_lm75SensorIndex: 409266936Sloos value->v.integer = sensor->index; 410266936Sloos break; 411266936Sloos case LEAF_lm75SensorSysctlIndex: 412266936Sloos value->v.integer = sensor->sysctlidx; 413266936Sloos break; 414266936Sloos case LEAF_lm75SensorDesc: 415266936Sloos ret = string_get(value, sensor->desc, -1); 416266936Sloos break; 417266936Sloos case LEAF_lm75SensorLocation: 418266936Sloos ret = string_get(value, sensor->location, -1); 419266936Sloos break; 420266936Sloos case LEAF_lm75SensorPnpInfo: 421266936Sloos ret = string_get(value, sensor->pnpinfo, -1); 422266936Sloos break; 423266936Sloos case LEAF_lm75SensorParent: 424266936Sloos ret = string_get(value, sensor->parent, -1); 425266936Sloos break; 426266936Sloos case LEAF_lm75SensorTemperature: 427266936Sloos value->v.integer = sensor->temp; 428266936Sloos break; 429266936Sloos default: 430266936Sloos ret = SNMP_ERR_RES_UNAVAIL; 431266936Sloos break; 432266936Sloos } 433266936Sloos 434266936Sloos return (ret); 435266936Sloos} 436