]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bsnmpd/modules/snmp_lm75/snmp_lm75.c
Import Intel Processor Trace decoder library from
[FreeBSD/FreeBSD.git] / usr.sbin / bsnmpd / modules / snmp_lm75 / snmp_lm75.c
1 /*-
2  * Copyright (c) 2014 Luiz Otavio O Souza <loos@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/queue.h>
32 #include <sys/sysctl.h>
33
34 #include <bsnmp/snmpmod.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <syslog.h>
40
41 #include "lm75_oid.h"
42 #include "lm75_tree.h"
43
44 #ifndef LM75BUF
45 #define LM75BUF         64
46 #endif
47 #define TZ_ZEROC        2732
48 #define UPDATE_INTERVAL 500     /* update interval in ticks */
49
50 static struct lmodule *module;
51
52 static const struct asn_oid oid_lm75 = OIDX_begemotLm75;
53
54 /* the Object Resource registration index */
55 static u_int lm75_index = 0;
56
57 /* Number of available sensors in the system. */
58 static int lm75_sensors;
59
60 /*
61  * Structure that describes single sensor.
62  */
63 struct lm75_snmp_sensor {
64         TAILQ_ENTRY(lm75_snmp_sensor) link;
65         int32_t         index;
66         int32_t         sysctlidx;
67         int32_t         temp;
68         char            desc[LM75BUF];
69         char            location[LM75BUF];
70         char            parent[LM75BUF];
71         char            pnpinfo[LM75BUF];
72 };
73
74 static TAILQ_HEAD(, lm75_snmp_sensor) sensors =
75     TAILQ_HEAD_INITIALIZER(sensors);
76
77 /* Ticks of the last sensors reading. */
78 static uint64_t last_sensors_update;
79
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);
85
86 const struct snmp_module config = {
87     .comment   =
88         "This module implements the BEGEMOT MIB for reading LM75 sensors data.",
89     .init      = lm75_init,
90     .start     = lm75_start,
91     .fini      = lm75_fini,
92     .tree      = lm75_ctree,
93     .tree_size = lm75_CTREE_SIZE,
94 };
95
96 static int
97 lm75_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
98 {
99
100         module = mod;
101
102         lm75_sensors = 0;
103         openlog("snmp_lm75", LOG_NDELAY | LOG_PID, LOG_DAEMON);
104
105         return(0);
106 }
107
108 static void
109 lm75_start(void)
110 {
111
112         lm75_index = or_register(&oid_lm75,
113             "The MIB module for reading lm75 sensors data.", module);
114 }
115
116 static int
117 lm75_fini(void)
118 {
119
120         or_unregister(lm75_index);
121         free_sensors();
122         closelog();
123
124         return (0);
125 }
126
127 static void
128 free_sensors(void)
129 {
130         struct lm75_snmp_sensor *sensor;
131
132         while ((sensor = TAILQ_FIRST(&sensors)) != NULL) {
133                 TAILQ_REMOVE(&sensors, sensor, link);
134                 free(sensor);
135         }
136 }
137
138 static int
139 sysctlname(int *oid, int nlen, char *name, size_t len)
140 {
141         int mib[12];
142
143         if (nlen > (int)(sizeof(mib) / sizeof(int) - 2))
144                 return (-1);
145
146         mib[0] = 0;
147         mib[1] = 1;
148         memcpy(mib + 2, oid, nlen * sizeof(int));
149
150         if (sysctl(mib, nlen + 2, name, &len, 0, 0) == -1)
151                 return (-1);
152
153         return (0);
154 }
155
156 static int
157 sysctlgetnext(int *oid, int nlen, int *next, size_t *nextlen)
158 {
159         int mib[12];
160
161         if (nlen > (int)(sizeof(mib) / sizeof(int) - 2))
162                 return (-1);
163
164         mib[0] = 0;
165         mib[1] = 2;
166         memcpy(mib + 2, oid, nlen * sizeof(int));
167
168         if (sysctl(mib, nlen + 2, next, nextlen, 0, 0) == -1)
169                 return (-1);
170
171         return (0);
172 }
173
174 static int
175 update_sensor_sysctl(void *obuf, size_t *obuflen, int idx, const char *name)
176 {
177         char buf[LM75BUF];
178         int mib[5];
179         size_t len;
180
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)
185                 return (-1);
186
187         if (len != 4)
188                 return (-1);
189
190         /* Read the sysctl data. */
191         if (sysctl(mib, len, obuf, obuflen, NULL, 0) == -1)
192                 return (-1);
193
194         return (0);
195 }
196
197 static void
198 update_sensor(struct lm75_snmp_sensor *sensor, int idx)
199 {
200         size_t len;
201
202         len = sizeof(sensor->desc);
203         update_sensor_sysctl(sensor->desc, &len, idx, "%desc");
204
205         len = sizeof(sensor->location);
206         update_sensor_sysctl(sensor->location, &len, idx, "%location");
207
208         len = sizeof(sensor->pnpinfo);
209         update_sensor_sysctl(sensor->pnpinfo, &len, idx, "%pnpinfo");
210
211         len = sizeof(sensor->parent);
212         update_sensor_sysctl(sensor->parent, &len, idx, "%parent");
213 }
214
215 static int
216 add_sensor(char *buf)
217 {
218         int idx, temp;
219         size_t len;
220         struct lm75_snmp_sensor *sensor;
221
222         if (sscanf(buf, "dev.lm75.%d.temperature", &idx) != 1)
223                 return (-1);
224
225         /* Read the sensor temperature. */
226         len = sizeof(temp);
227         if (update_sensor_sysctl(&temp, &len, idx, "temperature") != 0)
228                 return (-1);
229
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",
234                     sizeof(*sensor));
235                 return (-1);
236         }
237         sensor->index = ++lm75_sensors;
238         sensor->sysctlidx = idx;
239         sensor->temp = (temp - TZ_ZEROC) / 10;
240         TAILQ_INSERT_TAIL(&sensors, sensor, link);
241
242         update_sensor(sensor, idx);
243
244         return (0);
245 }
246
247 static int
248 update_sensors(void)
249 {
250         char buf[LM75BUF];
251         int i, root[5], *next, *oid;
252         size_t len, nextlen, rootlen;
253         static uint64_t now;
254
255         now = get_ticks();
256         if (now - last_sensors_update < UPDATE_INTERVAL)
257                 return (0);
258
259         last_sensors_update = now;
260
261         /* Reset the sensor data. */
262         free_sensors();
263         lm75_sensors = 0;
264
265         /* Start from the lm75 default root node. */
266         rootlen = 2;
267         if (sysctlnametomib("dev.lm75", root, &rootlen) == -1)
268                 return (0);
269
270         oid = (int *)malloc(sizeof(int) * rootlen);
271         if (oid == NULL) {
272                 perror("malloc");
273                 return (-1);
274         }
275         memcpy(oid, root, rootlen * sizeof(int));
276         len = rootlen;
277
278         /* Traverse the sysctl(3) interface and find the active sensors. */
279         for (;;) {
280
281                 /* Find the size of the next mib. */
282                 nextlen = 0;
283                 if (sysctlgetnext(oid, len, NULL, &nextlen) == -1) {
284                         free(oid);
285                         return (0);
286                 }
287                 /* Alocate and read the next mib. */
288                 next = (int *)malloc(nextlen);
289                 if (next == NULL) {
290                         syslog(LOG_ERR,
291                             "Unable to allocate %zu bytes for resource",
292                             nextlen);
293                         free(oid);
294                         return (-1);
295                 }
296                 if (sysctlgetnext(oid, len, next, &nextlen) == -1) {
297                         free(oid);
298                         free(next);
299                         return (0);
300                 }
301                 free(oid);
302                 /* Check if we care about the next mib. */
303                 for (i = 0; i < (int)rootlen; i++)
304                         if (next[i] != root[i]) {
305                                 free(next);
306                                 return (0);
307                         }
308                 oid = (int *)malloc(nextlen);
309                 if (oid == NULL) {
310                         syslog(LOG_ERR,
311                             "Unable to allocate %zu bytes for resource",
312                             nextlen);
313                         free(next);
314                         return (-1);
315                 }
316                 memcpy(oid, next, nextlen);
317                 free(next);
318                 len = nextlen / sizeof(int);
319
320                 /* Find the mib name. */
321                 if (sysctlname(oid, len, buf, sizeof(buf)) != 0)
322                         continue;
323
324                 if (strstr(buf, "temperature"))
325                         if (add_sensor(buf) != 0) {
326                                 free(oid);
327                                 return (-1);
328                         }
329         }
330
331         return (0);
332 }
333
334 int
335 op_lm75Sensors(struct snmp_context *context __unused, struct snmp_value *value,
336     u_int sub, u_int iidx __unused, enum snmp_op op)
337 {
338         asn_subid_t which;
339
340         if (update_sensors() == -1)
341                 return (SNMP_ERR_RES_UNAVAIL);
342
343         which = value->var.subs[sub - 1];
344
345         switch (op) {
346         case SNMP_OP_GET:
347                 switch (which) {
348                 case LEAF_lm75Sensors:
349                         value->v.integer = lm75_sensors;
350                         break;
351                 default:
352                         return (SNMP_ERR_RES_UNAVAIL);
353                 }
354                 break;
355         case SNMP_OP_SET:
356                 return (SNMP_ERR_NOT_WRITEABLE);
357         case SNMP_OP_GETNEXT:
358         case SNMP_OP_ROLLBACK:
359         case SNMP_OP_COMMIT:
360                 return (SNMP_ERR_NOERROR);
361         default:
362                 return (SNMP_ERR_RES_UNAVAIL);
363         }
364
365         return (SNMP_ERR_NOERROR);
366 }
367
368 int
369 op_lm75SensorTable(struct snmp_context *context __unused,
370     struct snmp_value *value, u_int sub, u_int iidx __unused, enum snmp_op op)
371 {
372         struct lm75_snmp_sensor *sensor;
373         asn_subid_t which;
374         int ret;
375
376         if (update_sensors() == -1)
377                 return (SNMP_ERR_RES_UNAVAIL);
378
379         which = value->var.subs[sub - 1];
380
381         switch (op) {
382         case SNMP_OP_GETNEXT:
383                 sensor = NEXT_OBJECT_INT(&sensors, &value->var, sub);
384                 if (sensor == NULL)
385                         return (SNMP_ERR_NOSUCHNAME);
386                 value->var.len = sub + 1;
387                 value->var.subs[sub] = sensor->index;
388                 break;
389         case SNMP_OP_GET:
390                 if (value->var.len - sub != 1)
391                         return (SNMP_ERR_NOSUCHNAME);
392                 sensor = FIND_OBJECT_INT(&sensors, &value->var, sub);
393                 if (sensor == NULL)
394                         return (SNMP_ERR_NOSUCHNAME);
395                 break;
396         case SNMP_OP_SET:
397                 return (SNMP_ERR_NOT_WRITEABLE);
398         case SNMP_OP_ROLLBACK:
399         case SNMP_OP_COMMIT:
400                 return (SNMP_ERR_NOERROR);
401         default:
402                 return (SNMP_ERR_RES_UNAVAIL);
403         }
404
405         ret = SNMP_ERR_NOERROR;
406
407         switch (which) {
408         case LEAF_lm75SensorIndex:
409                 value->v.integer = sensor->index;
410                 break;
411         case LEAF_lm75SensorSysctlIndex:
412                 value->v.integer = sensor->sysctlidx;
413                 break;
414         case LEAF_lm75SensorDesc:
415                 ret = string_get(value, sensor->desc, -1);
416                 break;
417         case LEAF_lm75SensorLocation:
418                 ret = string_get(value, sensor->location, -1);
419                 break;
420         case LEAF_lm75SensorPnpInfo:
421                 ret = string_get(value, sensor->pnpinfo, -1);
422                 break;
423         case LEAF_lm75SensorParent:
424                 ret = string_get(value, sensor->parent, -1);
425                 break;
426         case LEAF_lm75SensorTemperature:
427                 value->v.integer = sensor->temp;
428                 break;
429         default:
430                 ret = SNMP_ERR_RES_UNAVAIL;
431                 break;
432         }
433
434         return (ret);
435 }