• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file
3  * lwip Private MIB
4  *
5  * @todo create MIB file for this example
6  * @note the lwip enterprise tree root (26381) is owned by the lwIP project.
7  * It is NOT allowed to allocate new objects under this ID (26381) without our,
8  * the lwip developers, permission!
9  *
10  * Please apply for your own ID with IANA: http://www.iana.org/numbers.html
11  *
12  * lwip        OBJECT IDENTIFIER ::= { enterprises 26381 }
13  * example     OBJECT IDENTIFIER ::= { lwip 1 }
14  */
15 
16 /*
17  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
18  * All rights reserved.
19  *
20  * Redistribution and use in source and binary forms, with or without modification,
21  * are permitted provided that the following conditions are met:
22  *
23  * 1. Redistributions of source code must retain the above copyright notice,
24  *    this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright notice,
26  *    this list of conditions and the following disclaimer in the documentation
27  *    and/or other materials provided with the distribution.
28  * 3. The name of the author may not be used to endorse or promote products
29  *    derived from this software without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
32  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
33  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
34  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
35  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
36  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
39  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
40  * OF SUCH DAMAGE.
41  *
42  * Author: Christiaan Simons <christiaan.simons@axon.tv>
43  */
44 
45 #include "private_mib.h"
46 
47 #if LWIP_SNMP
48 
49 /** Directory where the sensor files are */
50 #define SENSORS_DIR           "w:\\sensors"
51 /** Set to 1 to read sensor values from files (in directory defined by SENSORS_DIR) */
52 #define SENSORS_USE_FILES     0
53 /** Set to 1 to search sensor files at startup (in directory defined by SENSORS_DIR) */
54 #define SENSORS_SEARCH_FILES  0
55 
56 #if SENSORS_SEARCH_FILES
57 #include <sys/stat.h>
58 #include <sys/types.h>
59 #include <unistd.h>
60 #include <fcntl.h>
61 #include <dirent.h>
62 #endif /* SENSORS_SEARCH_FILES */
63 
64 #include <string.h>
65 #include <stdio.h>
66 
67 #include "lwip/apps/snmp_table.h"
68 #include "lwip/apps/snmp_scalar.h"
69 
70 #if !SENSORS_USE_FILES || !SENSORS_SEARCH_FILES
71 /** When not using & searching files, defines the number of sensors */
72 #define SENSOR_COUNT 4
73 #endif /* !SENSORS_USE_FILES || !SENSORS_SEARCH_FILES */
74 
75 /*
76   This example presents a table for a few (at most 10) sensors.
77   Sensor detection takes place at initialization (once only).
78   Sensors may and can not be added or removed after agent
79   has started. Note this is only a limitation of this crude example,
80   the agent does support dynamic object insertions and removals.
81 
82   You'll need to manually create a directory called "sensors" and
83   a few single line text files with an integer temperature value.
84   The files must be called [0..9].txt.
85 
86   ./sensors/0.txt [content: 20]
87   ./sensors/3.txt [content: 75]
88 
89   The sensor values may be changed in runtime by editing the
90   text files in the "sensors" directory.
91 */
92 
93 #define SENSOR_MAX      10
94 #define SENSOR_NAME_LEN 20
95 
96 struct sensor_inf
97 {
98   u8_t num;
99 
100   char file[SENSOR_NAME_LEN + 1];
101 
102 #if !SENSORS_USE_FILES
103   /** When not using files, contains the value of the sensor */
104   s32_t value;
105 #endif /* !SENSORS_USE_FILES */
106 };
107 
108 static struct sensor_inf sensors[SENSOR_MAX];
109 
110 static s16_t      sensor_count_get_value(struct snmp_node_instance* instance, void* value);
111 static snmp_err_t sensor_table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance);
112 static snmp_err_t sensor_table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance);
113 static s16_t      sensor_table_get_value(struct snmp_node_instance* instance, void* value);
114 static snmp_err_t sensor_table_set_value(struct snmp_node_instance* instance, u16_t len, void *value);
115 
116 /* sensorentry .1.3.6.1.4.1.26381.1.1.1 (.level0.level1)
117    where level 0 is the table column (temperature/file name)
118    and level 1 the table row (sensor index) */
119 static const struct snmp_table_col_def sensor_table_columns[] = {
120   { 1, SNMP_ASN1_TYPE_INTEGER,      SNMP_NODE_INSTANCE_READ_WRITE },
121   { 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY  }
122 };
123 
124 /* sensortable .1.3.6.1.4.1.26381.1.1 */
125 static const struct snmp_table_node sensor_table = SNMP_TABLE_CREATE(
126   1, sensor_table_columns,
127   sensor_table_get_cell_instance, sensor_table_get_next_cell_instance,
128   sensor_table_get_value, snmp_set_test_ok, sensor_table_set_value);
129 
130 /* sensorcount .1.3.6.1.4.1.26381.1.2 */
131 static const struct snmp_scalar_node sensor_count = SNMP_SCALAR_CREATE_NODE_READONLY(
132   2, SNMP_ASN1_TYPE_INTEGER, sensor_count_get_value);
133 
134 /* example .1.3.6.1.4.1.26381.1 */
135 static const struct snmp_node* const example_nodes[] = {
136   &sensor_table.node.node,
137   &sensor_count.node.node
138 };
139 static const struct snmp_tree_node example_node = SNMP_CREATE_TREE_NODE(1, example_nodes);
140 
141 static const u32_t prvmib_base_oid[] = { 1,3,6,1,4,1,26381,1 };
142 const struct snmp_mib mib_private = SNMP_MIB_CREATE(prvmib_base_oid, &example_node.node);
143 
144 #if 0
145 /* for reference: we could also have expressed it like this: */
146 
147 /* lwip .1.3.6.1.4.1.26381 */
148 static const struct snmp_node* const lwip_nodes[] = {
149   &example_node.node
150 };
151 static const struct snmp_tree_node lwip_node = SNMP_CREATE_TREE_NODE(26381, lwip_nodes);
152 
153 /* enterprises .1.3.6.1.4.1 */
154 static const struct snmp_node* const enterprises_nodes[] = {
155   &lwip_node.node
156 };
157 static const struct snmp_tree_node enterprises_node = SNMP_CREATE_TREE_NODE(1, enterprises_nodes);
158 
159 /* private .1.3.6.1.4 */
160 static const struct snmp_node* const private_nodes[] = {
161   &enterprises_node.node
162 };
163 static const struct snmp_tree_node private_root = SNMP_CREATE_TREE_NODE(4, private_nodes);
164 
165 static const u32_t prvmib_base_oid[] = { 1,3,6,1,4 };
166 const struct snmp_mib mib_private = SNMP_MIB_CREATE(prvmib_base_oid, &private_root.node);
167 #endif
168 
169 /**
170  * Initialises this private MIB before use.
171  * @see main.c
172  */
173 void
lwip_privmib_init(void)174 lwip_privmib_init(void)
175 {
176 #if SENSORS_USE_FILES && SENSORS_SEARCH_FILES
177   char *buf, *ebuf, *cp;
178   size_t bufsize;
179   int nbytes;
180   struct stat sb;
181   struct dirent *dp;
182   int fd;
183 #else /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */
184   u8_t i;
185 #endif /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */
186 
187   memset(sensors, 0, sizeof(sensors));
188 
189   printf("SNMP private MIB start, detecting sensors.\n");
190 
191 #if SENSORS_USE_FILES && SENSORS_SEARCH_FILES
192   /* look for sensors in sensors directory */
193   fd = open(SENSORS_DIR, O_RDONLY);
194   if (fd > -1)
195   {
196     fstat(fd, &sb);
197     bufsize = sb.st_size;
198     if (bufsize < (size_t)sb.st_blksize)
199     {
200       bufsize = sb.st_blksize;
201     }
202     buf = (char*)malloc(bufsize);
203     if (buf != NULL)
204     {
205       do
206       {
207         long base;
208 
209         nbytes = getdirentries(fd, buf, bufsize, &base);
210         if (nbytes > 0)
211         {
212           ebuf = buf + nbytes;
213           cp = buf;
214           while (cp < ebuf)
215           {
216             dp = (struct dirent *)cp;
217             if (lwip_isdigit(dp->d_name[0]))
218             {
219               unsigned char idx = dp->d_name[0] - '0';
220 
221               sensors[idx].num = idx+1;
222               strncpy(&sensors[idx].file[0], dp->d_name, SENSOR_NAME_LEN);
223               printf("%s\n", sensors[idx].file);
224             }
225             cp += dp->d_reclen;
226           }
227         }
228       }
229       while (nbytes > 0);
230 
231       free(buf);
232     }
233     close(fd);
234   }
235 #else /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */
236   for (i = 0; i < SENSOR_COUNT; i++) {
237     sensors[i].num = (u8_t)(i + 1);
238     snprintf(sensors[i].file, sizeof(sensors[i].file), "%d.txt", i);
239 
240 #if !SENSORS_USE_FILES
241     /* initialize sensor value to != zero */
242     sensors[i].value = 11 * (i+1);
243 #endif /* !SENSORS_USE_FILES */
244   }
245 #endif /* SENSORS_USE_FILE && SENSORS_SEARCH_FILES */
246 }
247 
248 /* sensorcount .1.3.6.1.4.1.26381.1.2 */
249 static s16_t
sensor_count_get_value(struct snmp_node_instance * instance,void * value)250 sensor_count_get_value(struct snmp_node_instance* instance, void* value)
251 {
252   size_t count = 0;
253   u32_t *uint_ptr = (u32_t*)value;
254 
255   LWIP_UNUSED_ARG(instance);
256 
257   for(count=0; count<LWIP_ARRAYSIZE(sensors); count++) {
258     if(sensors[count].num == 0) {
259       *uint_ptr = (u32_t)count;
260       return sizeof(*uint_ptr);
261     }
262   }
263 
264   return 0;
265 }
266 
267 /* sensortable .1.3.6.1.4.1.26381.1.1 */
268 /* list of allowed value ranges for incoming OID */
269 static const struct snmp_oid_range sensor_table_oid_ranges[] = {
270   { 1, SENSOR_MAX+1 }
271 };
272 
273 static snmp_err_t
sensor_table_get_cell_instance(const u32_t * column,const u32_t * row_oid,u8_t row_oid_len,struct snmp_node_instance * cell_instance)274 sensor_table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance)
275 {
276   u32_t sensor_num;
277   size_t i;
278 
279   LWIP_UNUSED_ARG(column);
280 
281   /* check if incoming OID length and if values are in plausible range */
282   if(!snmp_oid_in_range(row_oid, row_oid_len, sensor_table_oid_ranges, LWIP_ARRAYSIZE(sensor_table_oid_ranges))) {
283     return SNMP_ERR_NOSUCHINSTANCE;
284   }
285 
286   /* get sensor index from incoming OID */
287   sensor_num = row_oid[0];
288 
289   /* find sensor with index */
290   for(i=0; i<LWIP_ARRAYSIZE(sensors); i++) {
291     if(sensors[i].num != 0) {
292       if(sensors[i].num == sensor_num) {
293         /* store sensor index for subsequent operations (get/test/set) */
294         cell_instance->reference.u32 = (u32_t)i;
295         return SNMP_ERR_NOERROR;
296       }
297     }
298   }
299 
300   /* not found */
301   return SNMP_ERR_NOSUCHINSTANCE;
302 }
303 
304 static snmp_err_t
sensor_table_get_next_cell_instance(const u32_t * column,struct snmp_obj_id * row_oid,struct snmp_node_instance * cell_instance)305 sensor_table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance)
306 {
307   size_t i;
308   struct snmp_next_oid_state state;
309   u32_t result_temp[LWIP_ARRAYSIZE(sensor_table_oid_ranges)];
310 
311   LWIP_UNUSED_ARG(column);
312 
313   /* init struct to search next oid */
314   snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(sensor_table_oid_ranges));
315 
316   /* iterate over all possible OIDs to find the next one */
317   for(i=0; i<LWIP_ARRAYSIZE(sensors); i++) {
318     if(sensors[i].num != 0) {
319       u32_t test_oid[LWIP_ARRAYSIZE(sensor_table_oid_ranges)];
320 
321       test_oid[0] = sensors[i].num;
322 
323       /* check generated OID: is it a candidate for the next one? */
324       snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(sensor_table_oid_ranges), (void*)i);
325     }
326   }
327 
328   /* did we find a next one? */
329   if(state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
330     snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
331     /* store sensor index for subsequent operations (get/test/set) */
332     cell_instance->reference.u32 = LWIP_CONST_CAST(u32_t, state.reference);
333     return SNMP_ERR_NOERROR;
334   }
335 
336   /* not found */
337   return SNMP_ERR_NOSUCHINSTANCE;
338 }
339 
340 static s16_t
sensor_table_get_value(struct snmp_node_instance * instance,void * value)341 sensor_table_get_value(struct snmp_node_instance* instance, void* value)
342 {
343   u32_t i = instance->reference.u32;
344   s32_t *temperature = (s32_t *)value;
345 
346   switch (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id))
347   {
348   case 1: /* sensor value */
349 #if SENSORS_USE_FILES
350     FILE* sensf;
351     char senspath[sizeof(SENSORS_DIR)+1+SENSOR_NAME_LEN+1] = SENSORS_DIR"/";
352 
353     strncpy(&senspath[sizeof(SENSORS_DIR)],
354             sensors[i].file,
355             SENSOR_NAME_LEN);
356     sensf = fopen(senspath,"r");
357     if (sensf != NULL)
358     {
359       fscanf(sensf,"%"S32_F,temperature);
360       fclose(sensf);
361     }
362 #else /* SENSORS_USE_FILES */
363     *temperature = sensors[i].value;
364 #endif /* SENSORS_USE_FILES */
365     return sizeof(s32_t);
366   case 2: /* file name */
367     MEMCPY(value, sensors[i].file, strlen(sensors[i].file));
368     return (s16_t)strlen(sensors[i].file);
369   default:
370     return 0;
371   }
372 }
373 
374 static snmp_err_t
sensor_table_set_value(struct snmp_node_instance * instance,u16_t len,void * value)375 sensor_table_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
376 {
377   u32_t i = instance->reference.u32;
378   s32_t *temperature = (s32_t *)value;
379 #if SENSORS_USE_FILES
380   FILE* sensf;
381   char senspath[sizeof(SENSORS_DIR)+1+SENSOR_NAME_LEN+1] = SENSORS_DIR"/";
382 
383   strncpy(&senspath[sizeof(SENSORS_DIR)],
384           sensors[i].file,
385           SENSOR_NAME_LEN);
386   sensf = fopen(senspath, "w");
387   if (sensf != NULL)
388   {
389     fprintf(sensf, "%"S32_F, *temperature);
390     fclose(sensf);
391   }
392 #else /* SENSORS_USE_FILES */
393   sensors[i].value = *temperature;
394 #endif /* SENSORS_USE_FILES */
395 
396   LWIP_UNUSED_ARG(len);
397 
398   return SNMP_ERR_NOERROR;
399 }
400 
401 #endif /* LWIP_SNMP */
402