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
46snmp_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
88snmp_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
164snmp_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
227snmp_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  }
287  while (1);
288
289  instance->asn1_type = col_def->asn1_type;
290  instance->access    = SNMP_NODE_INSTANCE_READ_ONLY;
291  instance->set_test  = NULL;
292  instance->set_value = NULL;
293
294  switch (col_def->data_type) {
295    case SNMP_VARIANT_VALUE_TYPE_U32:
296      instance->get_value = snmp_table_extract_value_from_u32ref;
297      break;
298    case SNMP_VARIANT_VALUE_TYPE_S32:
299      instance->get_value = snmp_table_extract_value_from_s32ref;
300      break;
301    case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */
302    case SNMP_VARIANT_VALUE_TYPE_CONST_PTR:
303      instance->get_value = snmp_table_extract_value_from_refconstptr;
304      break;
305    default:
306      LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type));
307      return SNMP_ERR_GENERROR;
308  }
309
310  /* build resulting oid */
311  instance->instance_oid.len   = 2;
312  instance->instance_oid.id[0] = 1;
313  instance->instance_oid.id[1] = col_def->index;
314  snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len);
315
316  return SNMP_ERR_NOERROR;
317}
318
319
320s16_t
321snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value)
322{
323  s32_t *dst = (s32_t*)value;
324  *dst = instance->reference.s32;
325  return sizeof(*dst);
326}
327
328s16_t
329snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value)
330{
331  u32_t *dst = (u32_t*)value;
332  *dst = instance->reference.u32;
333  return sizeof(*dst);
334}
335
336s16_t
337snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value)
338{
339  MEMCPY(value, instance->reference.const_ptr, instance->reference_len);
340  return (u16_t)instance->reference_len;
341}
342
343#endif /* LWIP_SNMP */
344