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
snmp_table_get_instance(const u32_t * root_oid,u8_t root_oid_len,struct snmp_node_instance * instance)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
snmp_table_get_next_instance(const u32_t * root_oid,u8_t root_oid_len,struct snmp_node_instance * instance)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
snmp_table_simple_get_instance(const u32_t * root_oid,u8_t root_oid_len,struct snmp_node_instance * instance)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
snmp_table_simple_get_next_instance(const u32_t * root_oid,u8_t root_oid_len,struct snmp_node_instance * instance)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
snmp_table_extract_value_from_s32ref(struct snmp_node_instance * instance,void * value)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
snmp_table_extract_value_from_u32ref(struct snmp_node_instance * instance,void * value)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
snmp_table_extract_value_from_refconstptr(struct snmp_node_instance * instance,void * value)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