/** * @file * SNMP table support implementation. */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Martin Hentschel * */ #include "lwip/apps/snmp_opts.h" #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/apps/snmp_core.h" #include "lwip/apps/snmp_table.h" #include snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance) { snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE; const struct snmp_table_node *table_node = (const struct snmp_table_node *)(const void *)instance->node; LWIP_UNUSED_ARG(root_oid); LWIP_UNUSED_ARG(root_oid_len); /* check min. length (fixed row entry definition, column, row instance oid with at least one entry */ /* fixed row entry always has oid 1 */ if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) { /* search column */ const struct snmp_table_col_def *col_def = table_node->columns; u16_t i = table_node->column_count; while (i > 0) { if (col_def->index == instance->instance_oid.id[1]) { break; } col_def++; i--; } if (i > 0) { /* everything may be overwritten by get_cell_instance_method() in order to implement special handling for single columns/cells */ instance->asn1_type = col_def->asn1_type; instance->access = col_def->access; instance->get_value = table_node->get_value; instance->set_test = table_node->set_test; instance->set_value = table_node->set_value; ret = table_node->get_cell_instance( &(instance->instance_oid.id[1]), &(instance->instance_oid.id[2]), instance->instance_oid.len - 2, instance); } } return ret; } snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance) { const struct snmp_table_node *table_node = (const struct snmp_table_node *)(const void *)instance->node; const struct snmp_table_col_def *col_def; struct snmp_obj_id row_oid; u32_t column = 0; snmp_err_t result; LWIP_UNUSED_ARG(root_oid); LWIP_UNUSED_ARG(root_oid_len); /* check that first part of id is 0 or 1, referencing fixed row entry */ if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) { return SNMP_ERR_NOSUCHINSTANCE; } if (instance->instance_oid.len > 1) { column = instance->instance_oid.id[1]; } if (instance->instance_oid.len > 2) { snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2); } else { row_oid.len = 0; } instance->get_value = table_node->get_value; instance->set_test = table_node->set_test; instance->set_value = table_node->set_value; /* resolve column and value */ do { u16_t i; const struct snmp_table_col_def *next_col_def = NULL; col_def = table_node->columns; for (i = 0; i < table_node->column_count; i++) { if (col_def->index == column) { next_col_def = col_def; break; } else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index))) { next_col_def = col_def; } col_def++; } if (next_col_def == NULL) { /* no further column found */ return SNMP_ERR_NOSUCHINSTANCE; } instance->asn1_type = next_col_def->asn1_type; instance->access = next_col_def->access; result = table_node->get_next_cell_instance( &next_col_def->index, &row_oid, instance); if (result == SNMP_ERR_NOERROR) { col_def = next_col_def; break; } row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */ column = next_col_def->index + 1; } while (1); /* build resulting oid */ instance->instance_oid.len = 2; instance->instance_oid.id[0] = 1; instance->instance_oid.id[1] = col_def->index; snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len); return SNMP_ERR_NOERROR; } snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance) { snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE; const struct snmp_table_simple_node *table_node = (const struct snmp_table_simple_node *)(const void *)instance->node; LWIP_UNUSED_ARG(root_oid); LWIP_UNUSED_ARG(root_oid_len); /* check min. length (fixed row entry definition, column, row instance oid with at least one entry */ /* fixed row entry always has oid 1 */ if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) { ret = table_node->get_cell_value( &(instance->instance_oid.id[1]), &(instance->instance_oid.id[2]), instance->instance_oid.len - 2, &instance->reference, &instance->reference_len); if (ret == SNMP_ERR_NOERROR) { /* search column */ const struct snmp_table_simple_col_def *col_def = table_node->columns; u32_t i = table_node->column_count; while (i > 0) { if (col_def->index == instance->instance_oid.id[1]) { break; } col_def++; i--; } if (i > 0) { instance->asn1_type = col_def->asn1_type; instance->access = SNMP_NODE_INSTANCE_READ_ONLY; instance->set_test = NULL; instance->set_value = NULL; switch (col_def->data_type) { case SNMP_VARIANT_VALUE_TYPE_U32: instance->get_value = snmp_table_extract_value_from_u32ref; break; case SNMP_VARIANT_VALUE_TYPE_S32: instance->get_value = snmp_table_extract_value_from_s32ref; break; case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */ case SNMP_VARIANT_VALUE_TYPE_CONST_PTR: instance->get_value = snmp_table_extract_value_from_refconstptr; break; default: LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type)); return SNMP_ERR_GENERROR; } ret = SNMP_ERR_NOERROR; } else { ret = SNMP_ERR_NOSUCHINSTANCE; } } } return ret; } snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance) { const struct snmp_table_simple_node *table_node = (const struct snmp_table_simple_node *)(const void *)instance->node; const struct snmp_table_simple_col_def *col_def; struct snmp_obj_id row_oid; u32_t column = 0; snmp_err_t result; LWIP_UNUSED_ARG(root_oid); LWIP_UNUSED_ARG(root_oid_len); /* check that first part of id is 0 or 1, referencing fixed row entry */ if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) { return SNMP_ERR_NOSUCHINSTANCE; } if (instance->instance_oid.len > 1) { column = instance->instance_oid.id[1]; } if (instance->instance_oid.len > 2) { snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2); } else { row_oid.len = 0; } /* resolve column and value */ do { u32_t i; const struct snmp_table_simple_col_def *next_col_def = NULL; col_def = table_node->columns; for (i = 0; i < table_node->column_count; i++) { if (col_def->index == column) { next_col_def = col_def; break; } else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index))) { next_col_def = col_def; } col_def++; } if (next_col_def == NULL) { /* no further column found */ return SNMP_ERR_NOSUCHINSTANCE; } result = table_node->get_next_cell_instance_and_value( &next_col_def->index, &row_oid, &instance->reference, &instance->reference_len); if (result == SNMP_ERR_NOERROR) { col_def = next_col_def; break; } row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */ column = next_col_def->index + 1; } while (1); instance->asn1_type = col_def->asn1_type; instance->access = SNMP_NODE_INSTANCE_READ_ONLY; instance->set_test = NULL; instance->set_value = NULL; switch (col_def->data_type) { case SNMP_VARIANT_VALUE_TYPE_U32: instance->get_value = snmp_table_extract_value_from_u32ref; break; case SNMP_VARIANT_VALUE_TYPE_S32: instance->get_value = snmp_table_extract_value_from_s32ref; break; case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */ case SNMP_VARIANT_VALUE_TYPE_CONST_PTR: instance->get_value = snmp_table_extract_value_from_refconstptr; break; default: LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type)); return SNMP_ERR_GENERROR; } /* build resulting oid */ instance->instance_oid.len = 2; instance->instance_oid.id[0] = 1; instance->instance_oid.id[1] = col_def->index; snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len); return SNMP_ERR_NOERROR; } s16_t snmp_table_extract_value_from_s32ref(struct snmp_node_instance *instance, void *value) { s32_t *dst = (s32_t *)value; *dst = instance->reference.s32; return sizeof(*dst); } s16_t snmp_table_extract_value_from_u32ref(struct snmp_node_instance *instance, void *value) { u32_t *dst = (u32_t *)value; *dst = instance->reference.u32; return sizeof(*dst); } s16_t snmp_table_extract_value_from_refconstptr(struct snmp_node_instance *instance, void *value) { MEMCPY(value, instance->reference.const_ptr, instance->reference_len); return (u16_t)instance->reference_len; } #endif /* LWIP_SNMP */