2 * Copyright (c) 2014 Luiz Otavio O Souza <loos@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/queue.h>
32 #include <sys/sysctl.h>
34 #include <bsnmp/snmpmod.h>
42 #include "lm75_tree.h"
48 #define UPDATE_INTERVAL 500 /* update interval in ticks */
50 static struct lmodule *module;
52 static const struct asn_oid oid_lm75 = OIDX_begemotLm75;
54 /* the Object Resource registration index */
55 static u_int lm75_index = 0;
57 /* Number of available sensors in the system. */
58 static int lm75_sensors;
61 * Structure that describes single sensor.
63 struct lm75_snmp_sensor {
64 TAILQ_ENTRY(lm75_snmp_sensor) link;
69 char location[LM75BUF];
71 char pnpinfo[LM75BUF];
74 static TAILQ_HEAD(, lm75_snmp_sensor) sensors =
75 TAILQ_HEAD_INITIALIZER(sensors);
77 /* Ticks of the last sensors reading. */
78 static uint64_t last_sensors_update;
80 static void free_sensors(void);
81 static int lm75_fini(void);
82 static int lm75_init(struct lmodule *mod, int argc, char *argv[]);
83 static void lm75_start(void);
84 static int update_sensors(void);
86 const struct snmp_module config = {
88 "This module implements the BEGEMOT MIB for reading LM75 sensors data.",
93 .tree_size = lm75_CTREE_SIZE,
97 lm75_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
103 openlog("snmp_lm75", LOG_NDELAY | LOG_PID, LOG_DAEMON);
112 lm75_index = or_register(&oid_lm75,
113 "The MIB module for reading lm75 sensors data.", module);
120 or_unregister(lm75_index);
130 struct lm75_snmp_sensor *sensor;
132 while ((sensor = TAILQ_FIRST(&sensors)) != NULL) {
133 TAILQ_REMOVE(&sensors, sensor, link);
139 sysctlname(int *oid, int nlen, char *name, size_t len)
143 if (nlen > (int)(sizeof(mib) / sizeof(int) - 2))
148 memcpy(mib + 2, oid, nlen * sizeof(int));
150 if (sysctl(mib, nlen + 2, name, &len, 0, 0) == -1)
157 sysctlgetnext(int *oid, int nlen, int *next, size_t *nextlen)
161 if (nlen > (int)(sizeof(mib) / sizeof(int) - 2))
166 memcpy(mib + 2, oid, nlen * sizeof(int));
168 if (sysctl(mib, nlen + 2, next, nextlen, 0, 0) == -1)
175 update_sensor_sysctl(void *obuf, size_t *obuflen, int idx, const char *name)
181 /* Fill out the mib information. */
182 snprintf(buf, sizeof(buf) - 1, "dev.lm75.%d.%s", idx, name);
183 len = sizeof(mib) / sizeof(int);
184 if (sysctlnametomib(buf, mib, &len) == -1)
190 /* Read the sysctl data. */
191 if (sysctl(mib, len, obuf, obuflen, NULL, 0) == -1)
198 update_sensor(struct lm75_snmp_sensor *sensor, int idx)
202 len = sizeof(sensor->desc);
203 update_sensor_sysctl(sensor->desc, &len, idx, "%desc");
205 len = sizeof(sensor->location);
206 update_sensor_sysctl(sensor->location, &len, idx, "%location");
208 len = sizeof(sensor->pnpinfo);
209 update_sensor_sysctl(sensor->pnpinfo, &len, idx, "%pnpinfo");
211 len = sizeof(sensor->parent);
212 update_sensor_sysctl(sensor->parent, &len, idx, "%parent");
216 add_sensor(char *buf)
220 struct lm75_snmp_sensor *sensor;
222 if (sscanf(buf, "dev.lm75.%d.temperature", &idx) != 1)
225 /* Read the sensor temperature. */
227 if (update_sensor_sysctl(&temp, &len, idx, "temperature") != 0)
230 /* Add the sensor data to the table. */
231 sensor = calloc(1, sizeof(*sensor));
232 if (sensor == NULL) {
233 syslog(LOG_ERR, "Unable to allocate %zu bytes for resource",
237 sensor->index = ++lm75_sensors;
238 sensor->sysctlidx = idx;
239 sensor->temp = (temp - TZ_ZEROC) / 10;
240 TAILQ_INSERT_TAIL(&sensors, sensor, link);
242 update_sensor(sensor, idx);
251 int i, root[5], *next, *oid;
252 size_t len, nextlen, rootlen;
256 if (now - last_sensors_update < UPDATE_INTERVAL)
259 last_sensors_update = now;
261 /* Reset the sensor data. */
265 /* Start from the lm75 default root node. */
267 if (sysctlnametomib("dev.lm75", root, &rootlen) == -1)
270 oid = (int *)malloc(sizeof(int) * rootlen);
275 memcpy(oid, root, rootlen * sizeof(int));
278 /* Traverse the sysctl(3) interface and find the active sensors. */
281 /* Find the size of the next mib. */
283 if (sysctlgetnext(oid, len, NULL, &nextlen) == -1) {
287 /* Alocate and read the next mib. */
288 next = (int *)malloc(nextlen);
291 "Unable to allocate %zu bytes for resource",
296 if (sysctlgetnext(oid, len, next, &nextlen) == -1) {
302 /* Check if we care about the next mib. */
303 for (i = 0; i < (int)rootlen; i++)
304 if (next[i] != root[i]) {
308 oid = (int *)malloc(nextlen);
311 "Unable to allocate %zu bytes for resource",
316 memcpy(oid, next, nextlen);
318 len = nextlen / sizeof(int);
320 /* Find the mib name. */
321 if (sysctlname(oid, len, buf, sizeof(buf)) != 0)
324 if (strstr(buf, "temperature"))
325 if (add_sensor(buf) != 0) {
335 op_lm75Sensors(struct snmp_context *context __unused, struct snmp_value *value,
336 u_int sub, u_int iidx __unused, enum snmp_op op)
340 if (update_sensors() == -1)
341 return (SNMP_ERR_RES_UNAVAIL);
343 which = value->var.subs[sub - 1];
348 case LEAF_lm75Sensors:
349 value->v.integer = lm75_sensors;
352 return (SNMP_ERR_RES_UNAVAIL);
356 return (SNMP_ERR_NOT_WRITEABLE);
357 case SNMP_OP_GETNEXT:
358 case SNMP_OP_ROLLBACK:
360 return (SNMP_ERR_NOERROR);
362 return (SNMP_ERR_RES_UNAVAIL);
365 return (SNMP_ERR_NOERROR);
369 op_lm75SensorTable(struct snmp_context *context __unused,
370 struct snmp_value *value, u_int sub, u_int iidx __unused, enum snmp_op op)
372 struct lm75_snmp_sensor *sensor;
376 if (update_sensors() == -1)
377 return (SNMP_ERR_RES_UNAVAIL);
379 which = value->var.subs[sub - 1];
382 case SNMP_OP_GETNEXT:
383 sensor = NEXT_OBJECT_INT(&sensors, &value->var, sub);
385 return (SNMP_ERR_NOSUCHNAME);
386 value->var.len = sub + 1;
387 value->var.subs[sub] = sensor->index;
390 if (value->var.len - sub != 1)
391 return (SNMP_ERR_NOSUCHNAME);
392 sensor = FIND_OBJECT_INT(&sensors, &value->var, sub);
394 return (SNMP_ERR_NOSUCHNAME);
397 return (SNMP_ERR_NOT_WRITEABLE);
398 case SNMP_OP_ROLLBACK:
400 return (SNMP_ERR_NOERROR);
402 return (SNMP_ERR_RES_UNAVAIL);
405 ret = SNMP_ERR_NOERROR;
408 case LEAF_lm75SensorIndex:
409 value->v.integer = sensor->index;
411 case LEAF_lm75SensorSysctlIndex:
412 value->v.integer = sensor->sysctlidx;
414 case LEAF_lm75SensorDesc:
415 ret = string_get(value, sensor->desc, -1);
417 case LEAF_lm75SensorLocation:
418 ret = string_get(value, sensor->location, -1);
420 case LEAF_lm75SensorPnpInfo:
421 ret = string_get(value, sensor->pnpinfo, -1);
423 case LEAF_lm75SensorParent:
424 ret = string_get(value, sensor->parent, -1);
426 case LEAF_lm75SensorTemperature:
427 value->v.integer = sensor->temp;
430 ret = SNMP_ERR_RES_UNAVAIL;