1 /** 2 * @file 3 * SNMP table support implementation. 4 */ 5 6 /* 7 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without modification, 11 * are permitted provided that the following conditions are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright notice, 14 * this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 30 * OF SUCH DAMAGE. 31 * 32 * This file is part of the lwIP TCP/IP stack. 33 * 34 * Author: Martin Hentschel <info@cl-soft.de> 35 * 36 */ 37 38 #include "lwip/apps/snmp_opts.h" 39 40 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ 41 42 #include "lwip/apps/snmp_core.h" 43 #include "lwip/apps/snmp_table.h" 44 #include <string.h> 45 46 snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance) 47 { 48 snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE; 49 const struct snmp_table_node *table_node = (const struct snmp_table_node *)(const void *)instance->node; 50 51 LWIP_UNUSED_ARG(root_oid); 52 LWIP_UNUSED_ARG(root_oid_len); 53 54 /* check min. length (fixed row entry definition, column, row instance oid with at least one entry */ 55 /* fixed row entry always has oid 1 */ 56 if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) { 57 /* search column */ 58 const struct snmp_table_col_def *col_def = table_node->columns; 59 u16_t i = table_node->column_count; 60 while (i > 0) { 61 if (col_def->index == instance->instance_oid.id[1]) { 62 break; 63 } 64 65 col_def++; 66 i--; 67 } 68 69 if (i > 0) { 70 /* everything may be overwritten by get_cell_instance_method() in order to implement special handling for single columns/cells */ 71 instance->asn1_type = col_def->asn1_type; 72 instance->access = col_def->access; 73 instance->get_value = table_node->get_value; 74 instance->set_test = table_node->set_test; 75 instance->set_value = table_node->set_value; 76 77 ret = table_node->get_cell_instance( 78 &(instance->instance_oid.id[1]), 79 &(instance->instance_oid.id[2]), 80 instance->instance_oid.len - 2, 81 instance); 82 } 83 } 84 85 return ret; 86 } 87 88 snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance) 89 { 90 const struct snmp_table_node *table_node = (const struct snmp_table_node *)(const void *)instance->node; 91 const struct snmp_table_col_def *col_def; 92 struct snmp_obj_id row_oid; 93 u32_t column = 0; 94 snmp_err_t result; 95 96 LWIP_UNUSED_ARG(root_oid); 97 LWIP_UNUSED_ARG(root_oid_len); 98 99 /* check that first part of id is 0 or 1, referencing fixed row entry */ 100 if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) { 101 return SNMP_ERR_NOSUCHINSTANCE; 102 } 103 if (instance->instance_oid.len > 1) { 104 column = instance->instance_oid.id[1]; 105 } 106 if (instance->instance_oid.len > 2) { 107 snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2); 108 } else { 109 row_oid.len = 0; 110 } 111 112 instance->get_value = table_node->get_value; 113 instance->set_test = table_node->set_test; 114 instance->set_value = table_node->set_value; 115 116 /* resolve column and value */ 117 do { 118 u16_t i; 119 const struct snmp_table_col_def *next_col_def = NULL; 120 col_def = table_node->columns; 121 122 for (i = 0; i < table_node->column_count; i++) { 123 if (col_def->index == column) { 124 next_col_def = col_def; 125 break; 126 } else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index))) { 127 next_col_def = col_def; 128 } 129 col_def++; 130 } 131 132 if (next_col_def == NULL) { 133 /* no further column found */ 134 return SNMP_ERR_NOSUCHINSTANCE; 135 } 136 137 instance->asn1_type = next_col_def->asn1_type; 138 instance->access = next_col_def->access; 139 140 result = table_node->get_next_cell_instance( 141 &next_col_def->index, 142 &row_oid, 143 instance); 144 145 if (result == SNMP_ERR_NOERROR) { 146 col_def = next_col_def; 147 break; 148 } 149 150 row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */ 151 column = next_col_def->index + 1; 152 } while (1); 153 154 /* build resulting oid */ 155 instance->instance_oid.len = 2; 156 instance->instance_oid.id[0] = 1; 157 instance->instance_oid.id[1] = col_def->index; 158 snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len); 159 160 return SNMP_ERR_NOERROR; 161 } 162 163 164 snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance) 165 { 166 snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE; 167 const struct snmp_table_simple_node *table_node = (const struct snmp_table_simple_node *)(const void *)instance->node; 168 169 LWIP_UNUSED_ARG(root_oid); 170 LWIP_UNUSED_ARG(root_oid_len); 171 172 /* check min. length (fixed row entry definition, column, row instance oid with at least one entry */ 173 /* fixed row entry always has oid 1 */ 174 if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) { 175 ret = table_node->get_cell_value( 176 &(instance->instance_oid.id[1]), 177 &(instance->instance_oid.id[2]), 178 instance->instance_oid.len - 2, 179 &instance->reference, 180 &instance->reference_len); 181 182 if (ret == SNMP_ERR_NOERROR) { 183 /* search column */ 184 const struct snmp_table_simple_col_def *col_def = table_node->columns; 185 u32_t i = table_node->column_count; 186 while (i > 0) { 187 if (col_def->index == instance->instance_oid.id[1]) { 188 break; 189 } 190 191 col_def++; 192 i--; 193 } 194 195 if (i > 0) { 196 instance->asn1_type = col_def->asn1_type; 197 instance->access = SNMP_NODE_INSTANCE_READ_ONLY; 198 instance->set_test = NULL; 199 instance->set_value = NULL; 200 201 switch (col_def->data_type) { 202 case SNMP_VARIANT_VALUE_TYPE_U32: 203 instance->get_value = snmp_table_extract_value_from_u32ref; 204 break; 205 case SNMP_VARIANT_VALUE_TYPE_S32: 206 instance->get_value = snmp_table_extract_value_from_s32ref; 207 break; 208 case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */ 209 case SNMP_VARIANT_VALUE_TYPE_CONST_PTR: 210 instance->get_value = snmp_table_extract_value_from_refconstptr; 211 break; 212 default: 213 LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type)); 214 return SNMP_ERR_GENERROR; 215 } 216 217 ret = SNMP_ERR_NOERROR; 218 } else { 219 ret = SNMP_ERR_NOSUCHINSTANCE; 220 } 221 } 222 } 223 224 return ret; 225 } 226 227 snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance) 228 { 229 const struct snmp_table_simple_node *table_node = (const struct snmp_table_simple_node *)(const void *)instance->node; 230 const struct snmp_table_simple_col_def *col_def; 231 struct snmp_obj_id row_oid; 232 u32_t column = 0; 233 snmp_err_t result; 234 235 LWIP_UNUSED_ARG(root_oid); 236 LWIP_UNUSED_ARG(root_oid_len); 237 238 /* check that first part of id is 0 or 1, referencing fixed row entry */ 239 if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) { 240 return SNMP_ERR_NOSUCHINSTANCE; 241 } 242 if (instance->instance_oid.len > 1) { 243 column = instance->instance_oid.id[1]; 244 } 245 if (instance->instance_oid.len > 2) { 246 snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2); 247 } else { 248 row_oid.len = 0; 249 } 250 251 /* resolve column and value */ 252 do { 253 u32_t i; 254 const struct snmp_table_simple_col_def *next_col_def = NULL; 255 col_def = table_node->columns; 256 257 for (i = 0; i < table_node->column_count; i++) { 258 if (col_def->index == column) { 259 next_col_def = col_def; 260 break; 261 } else if ((col_def->index > column) && ((next_col_def == NULL) || 262 (col_def->index < next_col_def->index))) { 263 next_col_def = col_def; 264 } 265 col_def++; 266 } 267 268 if (next_col_def == NULL) { 269 /* no further column found */ 270 return SNMP_ERR_NOSUCHINSTANCE; 271 } 272 273 result = table_node->get_next_cell_instance_and_value( 274 &next_col_def->index, 275 &row_oid, 276 &instance->reference, 277 &instance->reference_len); 278 279 if (result == SNMP_ERR_NOERROR) { 280 col_def = next_col_def; 281 break; 282 } 283 284 row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */ 285 column = next_col_def->index + 1; 286 } while (1); 287 288 instance->asn1_type = col_def->asn1_type; 289 instance->access = SNMP_NODE_INSTANCE_READ_ONLY; 290 instance->set_test = NULL; 291 instance->set_value = NULL; 292 293 switch (col_def->data_type) { 294 case SNMP_VARIANT_VALUE_TYPE_U32: 295 instance->get_value = snmp_table_extract_value_from_u32ref; 296 break; 297 case SNMP_VARIANT_VALUE_TYPE_S32: 298 instance->get_value = snmp_table_extract_value_from_s32ref; 299 break; 300 case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */ 301 case SNMP_VARIANT_VALUE_TYPE_CONST_PTR: 302 instance->get_value = snmp_table_extract_value_from_refconstptr; 303 break; 304 default: 305 LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type)); 306 return SNMP_ERR_GENERROR; 307 } 308 309 /* build resulting oid */ 310 instance->instance_oid.len = 2; 311 instance->instance_oid.id[0] = 1; 312 instance->instance_oid.id[1] = col_def->index; 313 snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len); 314 315 return SNMP_ERR_NOERROR; 316 } 317 318 319 s16_t 320 snmp_table_extract_value_from_s32ref(struct snmp_node_instance *instance, void *value) 321 { 322 s32_t *dst = (s32_t *)value; 323 *dst = instance->reference.s32; 324 return sizeof(*dst); 325 } 326 327 s16_t 328 snmp_table_extract_value_from_u32ref(struct snmp_node_instance *instance, void *value) 329 { 330 u32_t *dst = (u32_t *)value; 331 *dst = instance->reference.u32; 332 return sizeof(*dst); 333 } 334 335 s16_t 336 snmp_table_extract_value_from_refconstptr(struct snmp_node_instance *instance, void *value) 337 { 338 MEMCPY(value, instance->reference.const_ptr, instance->reference_len); 339 return (u16_t)instance->reference_len; 340 } 341 342 #endif /* LWIP_SNMP */ 343