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 <ctype.h> 60#include <unistd.h> 61#include <fcntl.h> 62#include <dirent.h> 63#endif /* SENSORS_SEARCH_FILES */ 64 65#include <string.h> 66#include <stdio.h> 67 68#include "lwip/apps/snmp_table.h" 69#include "lwip/apps/snmp_scalar.h" 70 71#if !SENSORS_USE_FILES || !SENSORS_SEARCH_FILES 72/** When not using & searching files, defines the number of sensors */ 73#define SENSOR_COUNT 4 74#endif /* !SENSORS_USE_FILES || !SENSORS_SEARCH_FILES */ 75 76/* 77 This example presents a table for a few (at most 10) sensors. 78 Sensor detection takes place at initialization (once only). 79 Sensors may and can not be added or removed after agent 80 has started. Note this is only a limitation of this crude example, 81 the agent does support dynamic object insertions and removals. 82 83 You'll need to manually create a directory called "sensors" and 84 a few single line text files with an integer temperature value. 85 The files must be called [0..9].txt. 86 87 ./sensors/0.txt [content: 20] 88 ./sensors/3.txt [content: 75] 89 90 The sensor values may be changed in runtime by editing the 91 text files in the "sensors" directory. 92*/ 93 94#define SENSOR_MAX 10 95#define SENSOR_NAME_LEN 20 96 97struct sensor_inf 98{ 99 u8_t num; 100 101 char file[SENSOR_NAME_LEN + 1]; 102 103#if !SENSORS_USE_FILES 104 /** When not using files, contains the value of the sensor */ 105 s32_t value; 106#endif /* !SENSORS_USE_FILES */ 107}; 108 109static struct sensor_inf sensors[SENSOR_MAX]; 110 111static s16_t sensor_count_get_value(struct snmp_node_instance* instance, void* value); 112static 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); 113static 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); 114static s16_t sensor_table_get_value(struct snmp_node_instance* instance, void* value); 115static snmp_err_t sensor_table_set_value(struct snmp_node_instance* instance, u16_t len, void *value); 116 117/* sensorentry .1.3.6.1.4.1.26381.1.1.1 (.level0.level1) 118 where level 0 is the table column (temperature/file name) 119 and level 1 the table row (sensor index) */ 120static const struct snmp_table_col_def sensor_table_columns[] = { 121 { 1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE }, 122 { 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY } 123}; 124 125/* sensortable .1.3.6.1.4.1.26381.1.1 */ 126static const struct snmp_table_node sensor_table = SNMP_TABLE_CREATE( 127 1, sensor_table_columns, 128 sensor_table_get_cell_instance, sensor_table_get_next_cell_instance, 129 sensor_table_get_value, snmp_set_test_ok, sensor_table_set_value); 130 131/* sensorcount .1.3.6.1.4.1.26381.1.2 */ 132static const struct snmp_scalar_node sensor_count = SNMP_SCALAR_CREATE_NODE_READONLY( 133 2, SNMP_ASN1_TYPE_INTEGER, sensor_count_get_value); 134 135/* example .1.3.6.1.4.1.26381.1 */ 136static const struct snmp_node* const example_nodes[] = { 137 &sensor_table.node.node, 138 &sensor_count.node.node 139}; 140static const struct snmp_tree_node example_node = SNMP_CREATE_TREE_NODE(1, example_nodes); 141 142static const u32_t prvmib_base_oid[] = { 1,3,6,1,4,1,26381,1 }; 143const struct snmp_mib mib_private = SNMP_MIB_CREATE(prvmib_base_oid, &example_node.node); 144 145#if 0 146/* for reference: we could also have expressed it like this: */ 147 148/* lwip .1.3.6.1.4.1.26381 */ 149static const struct snmp_node* const lwip_nodes[] = { 150 &example_node.node 151}; 152static const struct snmp_tree_node lwip_node = SNMP_CREATE_TREE_NODE(26381, lwip_nodes); 153 154/* enterprises .1.3.6.1.4.1 */ 155static const struct snmp_node* const enterprises_nodes[] = { 156 &lwip_node.node 157}; 158static const struct snmp_tree_node enterprises_node = SNMP_CREATE_TREE_NODE(1, enterprises_nodes); 159 160/* private .1.3.6.1.4 */ 161static const struct snmp_node* const private_nodes[] = { 162 &enterprises_node.node 163}; 164static const struct snmp_tree_node private_root = SNMP_CREATE_TREE_NODE(0, private_nodes); 165 166static const u32_t prvmib_base_oid[] = { 1,3,6,1,4 }; 167const struct snmp_mib mib_private = SNMP_MIB_CREATE(prvmib_base_oid, &private_root.node); 168#endif 169 170/** 171 * Initialises this private MIB before use. 172 * @see main.c 173 */ 174void 175lwip_privmib_init(void) 176{ 177#if SENSORS_USE_FILES && SENSORS_SEARCH_FILES 178 char *buf, *ebuf, *cp; 179 size_t bufsize; 180 int nbytes; 181 struct stat sb; 182 struct dirent *dp; 183 int fd; 184#else /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ 185 u8_t i; 186#endif /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ 187 188 memset(sensors, 0, sizeof(sensors)); 189 190 printf("SNMP private MIB start, detecting sensors.\n"); 191 192#if SENSORS_USE_FILES && SENSORS_SEARCH_FILES 193 /* look for sensors in sensors directory */ 194 fd = open(SENSORS_DIR, O_RDONLY); 195 if (fd > -1) 196 { 197 fstat(fd, &sb); 198 bufsize = sb.st_size; 199 if (bufsize < (size_t)sb.st_blksize) 200 { 201 bufsize = sb.st_blksize; 202 } 203 buf = (char*)malloc(bufsize); 204 if (buf != NULL) 205 { 206 do 207 { 208 long base; 209 210 nbytes = getdirentries(fd, buf, bufsize, &base); 211 if (nbytes > 0) 212 { 213 ebuf = buf + nbytes; 214 cp = buf; 215 while (cp < ebuf) 216 { 217 dp = (struct dirent *)cp; 218 if (isdigit(dp->d_name[0])) 219 { 220 unsigned char idx = dp->d_name[0] - '0'; 221 222 sensors[idx].num = idx+1; 223 strncpy(&sensors[idx].file[0], dp->d_name, SENSOR_NAME_LEN); 224 printf("%s\n", sensors[idx].file); 225 } 226 cp += dp->d_reclen; 227 } 228 } 229 } 230 while (nbytes > 0); 231 232 free(buf); 233 } 234 close(fd); 235 } 236#else /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ 237 for (i = 0; i < SENSOR_COUNT; i++) { 238 sensors[i].num = i+1; 239 snprintf(sensors[i].file, sizeof(sensors[i].file), "%d.txt", i); 240 241#if !SENSORS_USE_FILES 242 /* initialize sensor value to != zero */ 243 sensors[i].value = 11 * (i+1); 244#endif /* !SENSORS_USE_FILES */ 245 } 246#endif /* SENSORS_USE_FILE && SENSORS_SEARCH_FILES */ 247} 248 249/* sensorcount .1.3.6.1.4.1.26381.1.2 */ 250static s16_t 251sensor_count_get_value(struct snmp_node_instance* instance, void* value) 252{ 253 size_t count = 0; 254 u32_t *uint_ptr = (u32_t*)value; 255 256 LWIP_UNUSED_ARG(instance); 257 258 for(count=0; count<LWIP_ARRAYSIZE(sensors); count++) { 259 if(sensors[count].num == 0) { 260 *uint_ptr = (u32_t)count; 261 return sizeof(*uint_ptr); 262 } 263 } 264 265 return 0; 266} 267 268/* sensortable .1.3.6.1.4.1.26381.1.1 */ 269/* list of allowed value ranges for incoming OID */ 270static const struct snmp_oid_range sensor_table_oid_ranges[] = { 271 { 1, SENSOR_MAX+1 } 272}; 273 274static snmp_err_t 275sensor_table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance) 276{ 277 u32_t sensor_num; 278 size_t i; 279 280 LWIP_UNUSED_ARG(column); 281 282 /* check if incoming OID length and if values are in plausible range */ 283 if(!snmp_oid_in_range(row_oid, row_oid_len, sensor_table_oid_ranges, LWIP_ARRAYSIZE(sensor_table_oid_ranges))) { 284 return SNMP_ERR_NOSUCHINSTANCE; 285 } 286 287 /* get sensor index from incoming OID */ 288 sensor_num = row_oid[0]; 289 290 /* find sensor with index */ 291 for(i=0; i<LWIP_ARRAYSIZE(sensors); i++) { 292 if(sensors[i].num != 0) { 293 if(sensors[i].num == sensor_num) { 294 /* store sensor index for subsequent operations (get/test/set) */ 295 cell_instance->reference.u32 = (u32_t)i; 296 return SNMP_ERR_NOERROR; 297 } 298 } 299 } 300 301 /* not found */ 302 return SNMP_ERR_NOSUCHINSTANCE; 303} 304 305static snmp_err_t 306sensor_table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance) 307{ 308 size_t i; 309 struct snmp_next_oid_state state; 310 u32_t result_temp[LWIP_ARRAYSIZE(sensor_table_oid_ranges)]; 311 312 LWIP_UNUSED_ARG(column); 313 314 /* init struct to search next oid */ 315 snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(sensor_table_oid_ranges)); 316 317 /* iterate over all possible OIDs to find the next one */ 318 for(i=0; i<LWIP_ARRAYSIZE(sensors); i++) { 319 if(sensors[i].num != 0) { 320 u32_t test_oid[LWIP_ARRAYSIZE(sensor_table_oid_ranges)]; 321 322 test_oid[0] = sensors[i].num; 323 324 /* check generated OID: is it a candidate for the next one? */ 325 snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(sensor_table_oid_ranges), (void*)i); 326 } 327 } 328 329 /* did we find a next one? */ 330 if(state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { 331 snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); 332 /* store sensor index for subsequent operations (get/test/set) */ 333 cell_instance->reference.u32 = LWIP_CONST_CAST(u32_t, state.reference); 334 return SNMP_ERR_NOERROR; 335 } 336 337 /* not found */ 338 return SNMP_ERR_NOSUCHINSTANCE; 339} 340 341static s16_t 342sensor_table_get_value(struct snmp_node_instance* instance, void* value) 343{ 344 u32_t i = instance->reference.u32; 345 s32_t *temperature = (s32_t *)value; 346 347 switch (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id)) 348 { 349 case 1: /* sensor value */ 350#if SENSORS_USE_FILES 351 FILE* sensf; 352 char senspath[sizeof(SENSORS_DIR)+1+SENSOR_NAME_LEN+1] = SENSORS_DIR"/"; 353 354 strncpy(&senspath[sizeof(SENSORS_DIR)], 355 sensors[i].file, 356 SENSOR_NAME_LEN); 357 sensf = fopen(senspath,"r"); 358 if (sensf != NULL) 359 { 360 fscanf(sensf,"%"S32_F,temperature); 361 fclose(sensf); 362 } 363#else /* SENSORS_USE_FILES */ 364 *temperature = sensors[i].value; 365#endif /* SENSORS_USE_FILES */ 366 return sizeof(s32_t); 367 case 2: /* file name */ 368 MEMCPY(value, sensors[i].file, strlen(sensors[i].file)); 369 return (u16_t)strlen(sensors[i].file); 370 default: 371 return 0; 372 } 373} 374 375static snmp_err_t 376sensor_table_set_value(struct snmp_node_instance* instance, u16_t len, void *value) 377{ 378 u32_t i = instance->reference.u32; 379 s32_t *temperature = (s32_t *)value; 380#if SENSORS_USE_FILES 381 FILE* sensf; 382 char senspath[sizeof(SENSORS_DIR)+1+SENSOR_NAME_LEN+1] = SENSORS_DIR"/"; 383 384 strncpy(&senspath[sizeof(SENSORS_DIR)], 385 sensors[i].file, 386 SENSOR_NAME_LEN); 387 sensf = fopen(senspath, "w"); 388 if (sensf != NULL) 389 { 390 fprintf(sensf, "%"S32_F, *temperature); 391 fclose(sensf); 392 } 393#else /* SENSORS_USE_FILES */ 394 sensors[i].value = *temperature; 395#endif /* SENSORS_USE_FILES */ 396 397 LWIP_UNUSED_ARG(len); 398 399 return SNMP_ERR_NOERROR; 400} 401 402#endif /* LWIP_SNMP */ 403