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