| /** |
| * @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 <info@cl-soft.de> |
| * |
| */ |
| |
| #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 <string.h> |
| |
| 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 */ |