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