STM32F769IDiscovery  1.00
uDANTE Audio Networking with STM32F7 DISCO board
snmp_core.c
Go to the documentation of this file.
1 
6 /*
7  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
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  * Author: Christiaan Simons <christiaan.simons@axon.tv>
33  * Martin Hentschel <info@cl-soft.de>
34 */
35 
36 #include "lwip/apps/snmp_opts.h"
37 
38 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
39 
40 #include "lwip/apps/snmp.h"
41 #include "lwip/apps/snmp_core.h"
42 #include "snmp_core_priv.h"
43 #include <string.h>
44 
45 
46 #if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))
47  #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
48 #endif
49 #if (!LWIP_UDP && LWIP_SNMP)
50  #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
51 #endif
52 
53 struct snmp_statistics snmp_stats;
54 static const struct snmp_obj_id snmp_device_enterprise_oid_default = {SNMP_DEVICE_ENTERPRISE_OID_LEN, SNMP_DEVICE_ENTERPRISE_OID};
55 static const struct snmp_obj_id* snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default;
56 
57 const u32_t snmp_zero_dot_zero_values[] = { 0, 0 };
58 const struct snmp_obj_id_const_ref snmp_zero_dot_zero = { LWIP_ARRAYSIZE(snmp_zero_dot_zero_values), snmp_zero_dot_zero_values };
59 
60 
61 #if SNMP_LWIP_MIB2
62 #include "lwip/apps/snmp_mib2.h"
63 static const struct snmp_mib *default_mibs[] = { &mib2 };
64 static u8_t snmp_num_mibs = 1;
65 #else
66 static const struct snmp_mib *default_mibs[] = { NULL };
67 static u8_t snmp_num_mibs = 0;
68 #endif
69 
70 /* List of known mibs */
71 static struct snmp_mib const **snmp_mibs = default_mibs;
72 
82 void
83 snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs)
84 {
85  LWIP_ASSERT("mibs pointer must be != NULL", (mibs != NULL));
86  LWIP_ASSERT("num_mibs pointer must be != 0", (num_mibs != 0));
87  snmp_mibs = mibs;
88  snmp_num_mibs = num_mibs;
89 }
90 
91 void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_oid)
92 {
93  if (device_enterprise_oid == NULL) {
94  snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default;
95  } else {
96  snmp_device_enterprise_oid = device_enterprise_oid;
97  }
98 }
99 
100 const struct snmp_obj_id* snmp_get_device_enterprise_oid(void)
101 {
102  return snmp_device_enterprise_oid;
103 }
104 
105 #if LWIP_IPV4
106 
111 u8_t
112 snmp_oid_to_ip4(const u32_t *oid, ip4_addr_t *ip)
113 {
114  if((oid[0] > 0xFF) ||
115  (oid[1] > 0xFF) ||
116  (oid[2] > 0xFF) ||
117  (oid[3] > 0xFF)) {
118  ip4_addr_copy(*ip, *IP4_ADDR_ANY);
119  return 0;
120  }
121 
122  IP4_ADDR(ip, oid[0], oid[1], oid[2], oid[3]);
123  return 1;
124 }
125 
131 void
132 snmp_ip4_to_oid(const ip4_addr_t *ip, u32_t *oid)
133 {
134  oid[0] = ip4_addr1(ip);
135  oid[1] = ip4_addr2(ip);
136  oid[2] = ip4_addr3(ip);
137  oid[3] = ip4_addr4(ip);
138 }
139 #endif /* LWIP_IPV4 */
140 
141 #if LWIP_IPV6
142 
147 u8_t
148 snmp_oid_to_ip6(const u32_t *oid, ip6_addr_t *ip)
149 {
150  if((oid[0] > 0xFF) ||
151  (oid[1] > 0xFF) ||
152  (oid[2] > 0xFF) ||
153  (oid[3] > 0xFF) ||
154  (oid[4] > 0xFF) ||
155  (oid[5] > 0xFF) ||
156  (oid[6] > 0xFF) ||
157  (oid[7] > 0xFF) ||
158  (oid[8] > 0xFF) ||
159  (oid[9] > 0xFF) ||
160  (oid[10] > 0xFF) ||
161  (oid[11] > 0xFF) ||
162  (oid[12] > 0xFF) ||
163  (oid[13] > 0xFF) ||
164  (oid[14] > 0xFF) ||
165  (oid[15] > 0xFF)) {
166  ip6_addr_set_any(ip);
167  return 0;
168  }
169 
170  ip->addr[0] = (oid[0] << 24) | (oid[1] << 16) | (oid[2] << 8) | (oid[3] << 0);
171  ip->addr[1] = (oid[4] << 24) | (oid[5] << 16) | (oid[6] << 8) | (oid[7] << 0);
172  ip->addr[2] = (oid[8] << 24) | (oid[9] << 16) | (oid[10] << 8) | (oid[11] << 0);
173  ip->addr[3] = (oid[12] << 24) | (oid[13] << 16) | (oid[14] << 8) | (oid[15] << 0);
174  return 1;
175 }
176 
182 void
183 snmp_ip6_to_oid(const ip6_addr_t *ip, u32_t *oid)
184 {
185  oid[0] = (ip->addr[0] & 0xFF000000) >> 24;
186  oid[1] = (ip->addr[0] & 0x00FF0000) >> 16;
187  oid[2] = (ip->addr[0] & 0x0000FF00) >> 8;
188  oid[3] = (ip->addr[0] & 0x000000FF) >> 0;
189  oid[4] = (ip->addr[1] & 0xFF000000) >> 24;
190  oid[5] = (ip->addr[1] & 0x00FF0000) >> 16;
191  oid[6] = (ip->addr[1] & 0x0000FF00) >> 8;
192  oid[7] = (ip->addr[1] & 0x000000FF) >> 0;
193  oid[8] = (ip->addr[2] & 0xFF000000) >> 24;
194  oid[9] = (ip->addr[2] & 0x00FF0000) >> 16;
195  oid[10] = (ip->addr[2] & 0x0000FF00) >> 8;
196  oid[11] = (ip->addr[2] & 0x000000FF) >> 0;
197  oid[12] = (ip->addr[3] & 0xFF000000) >> 24;
198  oid[13] = (ip->addr[3] & 0x00FF0000) >> 16;
199  oid[14] = (ip->addr[3] & 0x0000FF00) >> 8;
200  oid[15] = (ip->addr[3] & 0x000000FF) >> 0;
201 }
202 #endif /* LWIP_IPV6 */
203 
204 #if LWIP_IPV4 || LWIP_IPV6
205 
212 u8_t
213 snmp_ip_port_to_oid(const ip_addr_t *ip, u16_t port, u32_t *oid)
214 {
215  u8_t idx;
216 
217  idx = snmp_ip_to_oid(ip, oid);
218  oid[idx] = port;
219  idx++;
220 
221  return idx;
222 }
223 
230 u8_t
231 snmp_ip_to_oid(const ip_addr_t *ip, u32_t *oid)
232 {
233  if(IP_IS_V6(ip)) {
234 #if LWIP_IPV6
235  oid[0] = 2; /* ipv6 */
236  oid[1] = 16; /* 16 InetAddressIPv6 OIDs follow */
237  snmp_ip6_to_oid(ip_2_ip6(ip), &oid[2]);
238  return 18;
239 #else /* LWIP_IPV6 */
240  return 0;
241 #endif /* LWIP_IPV6 */
242  } else {
243 #if LWIP_IPV4
244  oid[0] = 1; /* ipv4 */
245  oid[1] = 4; /* 4 InetAddressIPv4 OIDs follow */
246  snmp_ip4_to_oid(ip_2_ip4(ip), &oid[2]);
247  return 6;
248 #else /* LWIP_IPV4 */
249  return 0;
250 #endif /* LWIP_IPV4 */
251  }
252 }
253 
261 u8_t
262 snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip)
263 {
264  /* InetAddressType */
265  if(oid_len < 1) {
266  return 0;
267  }
268 
269  if (oid[0] == 1) { /* ipv4 */
270 #if LWIP_IPV4
271  /* 1x InetAddressType, 4x InetAddressIPv4 */
272  if(oid_len < 6) {
273  return 0;
274  }
275 
276  /* 4x ipv4 OID */
277  if(oid[1] != 4) {
278  return 0;
279  }
280 
281  IP_SET_TYPE(ip, IPADDR_TYPE_V4);
282  if(!snmp_oid_to_ip4(&oid[2], ip_2_ip4(ip))) {
283  return 0;
284  }
285 
286  return 6;
287 #else /* LWIP_IPV4 */
288  return 0;
289 #endif /* LWIP_IPV4 */
290  } else if(oid[0] == 2) { /* ipv6 */
291 #if LWIP_IPV6
292  /* 1x InetAddressType, 16x InetAddressIPv6 */
293  if(oid_len < 18) {
294  return 0;
295  }
296 
297  /* 16x ipv6 OID */
298  if(oid[1] != 16) {
299  return 0;
300  }
301 
302  IP_SET_TYPE(ip, IPADDR_TYPE_V6);
303  if(!snmp_oid_to_ip6(&oid[2], ip_2_ip6(ip))) {
304  return 0;
305  }
306 
307  return 18;
308 #else /* LWIP_IPV6 */
309  return 0;
310 #endif /* LWIP_IPV6 */
311  } else { /* unsupported InetAddressType */
312  return 0;
313  }
314 }
315 
324 u8_t
325 snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port)
326 {
327  u8_t idx = 0;
328 
329  /* InetAddressType + InetAddress */
330  idx += snmp_oid_to_ip(&oid[idx], oid_len-idx, ip);
331  if(idx == 0) {
332  return 0;
333  }
334 
335  /* InetPortNumber */
336  if(oid_len < (idx+1)) {
337  return 0;
338  }
339  if(oid[idx] > 0xffff) {
340  return 0;
341  }
342  *port = (u16_t)oid[idx];
343  idx++;
344 
345  return idx;
346 }
347 
348 #endif /* LWIP_IPV4 || LWIP_IPV6 */
349 
350 void
351 snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
352 {
353  LWIP_ASSERT("oid_len <= LWIP_SNMP_OBJ_ID_LEN", oid_len <= SNMP_MAX_OBJ_ID_LEN);
354 
355  target->len = oid_len;
356 
357  if (oid_len > 0) {
358  MEMCPY(target->id, oid, oid_len * sizeof(u32_t));
359  }
360 }
361 
362 void
363 snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
364 {
365  LWIP_ASSERT("target->len + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN);
366 
367  if (oid_len > 0)
368  {
369  /* move existing OID to make room at the beginning for OID to insert */
370  int i;
371  for (i = target->len-1; i>=0; i--)
372  {
373  target->id[i + oid_len] = target->id[i];
374  }
375 
376  /* paste oid at the beginning */
377  MEMCPY(target->id, oid, oid_len * sizeof(u32_t));
378  }
379 }
380 
381 void
382 snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
383 {
384  snmp_oid_assign(target, oid1, oid1_len);
385  snmp_oid_append(target, oid2, oid2_len);
386 }
387 
388 void
389 snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
390 {
391  LWIP_ASSERT("offset + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN);
392 
393  if(oid_len > 0) {
394  MEMCPY(&target->id[target->len], oid, oid_len * sizeof(u32_t));
395  target->len += oid_len;
396  }
397 }
398 
399 s8_t
400 snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
401 {
402  u8_t level = 0;
403  LWIP_ASSERT("'oid1' param must not be NULL or 'oid1_len' param be 0!", (oid1 != NULL) || (oid1_len == 0));
404  LWIP_ASSERT("'oid2' param must not be NULL or 'oid2_len' param be 0!", (oid2 != NULL) || (oid2_len == 0));
405 
406  while ((level < oid1_len) && (level < oid2_len))
407  {
408  if (*oid1 < *oid2)
409  {
410  return -1;
411  }
412  if (*oid1 > *oid2)
413  {
414  return 1;
415  }
416 
417  level++;
418  oid1++;
419  oid2++;
420  }
421 
422  /* common part of both OID's is equal, compare length */
423  if (oid1_len < oid2_len)
424  {
425  return -1;
426  }
427  if (oid1_len > oid2_len)
428  {
429  return 1;
430  }
431 
432  /* they are equal */
433  return 0;
434 }
435 
436 u8_t
437 snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
438 {
439  return (snmp_oid_compare(oid1, oid1_len, oid2, oid2_len) == 0)? 1 : 0;
440 }
441 
442 static const struct snmp_mib*
443 snmp_get_mib_from_oid(const u32_t *oid, u8_t oid_len)
444 {
445  const u32_t* list_oid;
446  const u32_t* searched_oid;
447  u8_t i, l;
448 
449  u8_t max_match_len = 0;
450  const struct snmp_mib* matched_mib = NULL;
451 
452  LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL));
453  LWIP_ASSERT("'oid_len' param must be greater than 0!", (oid_len > 0));
454 
455  for (i=0; i<snmp_num_mibs; i++)
456  {
457  LWIP_ASSERT("MIB array not initialized correctly", (snmp_mibs[i] != NULL));
458  LWIP_ASSERT("MIB array not initialized correctly - base OID is NULL", (snmp_mibs[i]->base_oid != NULL));
459 
460  if (oid_len >= snmp_mibs[i]->base_oid_len)
461  {
462  l = snmp_mibs[i]->base_oid_len;
463  list_oid = snmp_mibs[i]->base_oid;
464  searched_oid = oid;
465 
466  while (l > 0)
467  {
468  if (*list_oid != *searched_oid)
469  {
470  break;
471  }
472 
473  l--;
474  list_oid++;
475  searched_oid++;
476  }
477 
478  if ((l == 0) && (snmp_mibs[i]->base_oid_len > max_match_len))
479  {
480  max_match_len = snmp_mibs[i]->base_oid_len;
481  matched_mib = snmp_mibs[i];
482  }
483  }
484  }
485 
486  return matched_mib;
487 }
488 
489 static const struct snmp_mib*
490 snmp_get_next_mib(const u32_t *oid, u8_t oid_len)
491 {
492  u8_t i;
493  const struct snmp_mib* next_mib = NULL;
494 
495  LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL));
496  LWIP_ASSERT("'oid_len' param must be greater than 0!", (oid_len > 0));
497 
498  for (i=0; i<snmp_num_mibs; i++)
499  {
500  if (snmp_mibs[i]->base_oid != NULL)
501  {
502  /* check if mib is located behind starting point */
503  if (snmp_oid_compare(snmp_mibs[i]->base_oid, snmp_mibs[i]->base_oid_len, oid, oid_len) > 0)
504  {
505  if ((next_mib == NULL) || (snmp_oid_compare(snmp_mibs[i]->base_oid, snmp_mibs[i]->base_oid_len, next_mib->base_oid, next_mib->base_oid_len) < 0))
506  {
507  next_mib = snmp_mibs[i];
508  }
509  }
510  }
511  }
512 
513  return next_mib;
514 }
515 
516 static const struct snmp_mib*
517 snmp_get_mib_between(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
518 {
519  const struct snmp_mib* next_mib = snmp_get_next_mib(oid1, oid1_len);
520 
521  LWIP_ASSERT("'oid2' param must not be NULL!", (oid2 != NULL));
522  LWIP_ASSERT("'oid2_len' param must be greater than 0!", (oid2_len > 0));
523 
524  if (next_mib != NULL)
525  {
526  if (snmp_oid_compare(next_mib->base_oid, next_mib->base_oid_len, oid2, oid2_len) < 0)
527  {
528  return next_mib;
529  }
530  }
531 
532  return NULL;
533 }
534 
535 u8_t
536 snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance)
537 {
538  u8_t result = SNMP_ERR_NOSUCHOBJECT;
539  const struct snmp_mib *mib;
540  const struct snmp_node *mn = NULL;
541 
542  mib = snmp_get_mib_from_oid(oid, oid_len);
543  if (mib != NULL) {
544  u8_t oid_instance_len;
545 
546  mn = snmp_mib_tree_resolve_exact(mib, oid, oid_len, &oid_instance_len);
547  if ((mn != NULL) && (mn->node_type != SNMP_NODE_TREE)) {
548  /* get instance */
549  const struct snmp_leaf_node* leaf_node = (const struct snmp_leaf_node*)mn;
550 
551  node_instance->node = mn;
552  snmp_oid_assign(&node_instance->instance_oid, oid + (oid_len - oid_instance_len), oid_instance_len);
553 
554  result = leaf_node->get_instance(
555  oid,
556  oid_len - oid_instance_len,
557  node_instance);
558 
559 #ifdef LWIP_DEBUG
560  if(result == SNMP_ERR_NOERROR) {
561  if(((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != 0) && (node_instance->get_value == NULL)) {
562  LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is readable but no get_value function is specified\n"));
563  }
564  if(((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != 0) && (node_instance->set_value == NULL)) {
565  LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is writable but no set_value and/or set_test function is specified\n"));
566  }
567  }
568 #endif
569  }
570  }
571 
572  return result;
573 }
574 
575 u8_t
576 snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_validate_node_instance_method validate_node_instance_method, void* validate_node_instance_arg, struct snmp_obj_id* node_oid, struct snmp_node_instance* node_instance)
577 {
578  const struct snmp_mib *mib;
579  const struct snmp_node *mn = NULL;
580  const u32_t* start_oid = NULL;
581  u8_t start_oid_len = 0;
582 
583  /* resolve target MIB from passed OID */
584  mib = snmp_get_mib_from_oid(oid, oid_len);
585  if (mib == NULL) {
586  /* passed OID does not reference any known MIB, start at the next closest MIB */
587  mib = snmp_get_next_mib(oid, oid_len);
588 
589  if (mib != NULL) {
590  start_oid = mib->base_oid;
591  start_oid_len = mib->base_oid_len;
592  }
593  } else {
594  start_oid = oid;
595  start_oid_len = oid_len;
596  }
597 
598  /* resolve target node from MIB, skip to next MIB if no suitable node is found in current MIB */
599  while ((mib != NULL) && (mn == NULL)) {
600  u8_t oid_instance_len;
601 
602  /* check if OID directly references a node inside current MIB, in this case we have to ask this node for the next instance */
603  mn = snmp_mib_tree_resolve_exact(mib, start_oid, start_oid_len, &oid_instance_len);
604  if (mn != NULL) {
605  snmp_oid_assign(node_oid, start_oid, start_oid_len - oid_instance_len); /* set oid to node */
606  snmp_oid_assign(&node_instance->instance_oid, start_oid + (start_oid_len - oid_instance_len), oid_instance_len); /* set (relative) instance oid */
607  } else {
608  /* OID does not reference a node, search for the next closest node inside MIB; set instance_oid.len to zero because we want the first instance of this node */
609  mn = snmp_mib_tree_resolve_next(mib, start_oid, start_oid_len, node_oid);
610  node_instance->instance_oid.len = 0;
611  }
612 
613  /* validate the node; if the node has no further instance or the returned instance is invalid, search for the next in MIB and validate again */
614  node_instance->node = mn;
615  while (mn != NULL)
616  {
617  u8_t result;
618 
619  /* clear fields which may have values from previous loops */
620  node_instance->asn1_type = 0;
621  node_instance->access = SNMP_NODE_INSTANCE_NOT_ACCESSIBLE;
622  node_instance->get_value = NULL;
623  node_instance->set_test = NULL;
624  node_instance->set_value = NULL;
625  node_instance->release_instance = NULL;
626  node_instance->reference.ptr = NULL;
627  node_instance->reference_len = 0;
628 
629  result = ((const struct snmp_leaf_node*)mn)->get_next_instance(
630  node_oid->id,
631  node_oid->len,
632  node_instance);
633 
634  if (result == SNMP_ERR_NOERROR)
635  {
636 #ifdef LWIP_DEBUG
637  if(((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != 0) && (node_instance->get_value == NULL)) {
638  LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is readable but no get_value function is specified\n"));
639  }
640  if(((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != 0) && (node_instance->set_value == NULL)) {
641  LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is writable but no set_value function is specified\n"));
642  }
643 #endif
644 
645  /* validate node because the node may be not accessible for example (but let the caller decide what is valid */
646  if ((validate_node_instance_method == NULL) || (validate_node_instance_method(node_instance, validate_node_instance_arg) == SNMP_ERR_NOERROR))
647  {
648  /* node_oid "returns" the full result OID (including the instance part) */
649  snmp_oid_append(node_oid, node_instance->instance_oid.id, node_instance->instance_oid.len);
650  break;
651  }
652 
653  if (node_instance->release_instance != NULL) {
654  node_instance->release_instance(node_instance);
655  }
656  /*
657  the instance itself is not valid, ask for next instance from same node.
658  we don't have to change any variables because node_instance->instance_oid is used as input (starting point)
659  as well as output (resulting next OID), so we have to simply call get_next_instance method again
660  */
661  }
662  else
663  {
664  if (node_instance->release_instance != NULL) {
665  node_instance->release_instance(node_instance);
666  }
667 
668  /* the node has no further instance, skip to next node */
669  mn = snmp_mib_tree_resolve_next(mib, node_oid->id, node_oid->len, &node_instance->instance_oid); /* misuse node_instance->instance_oid as tmp buffer */
670  if (mn != NULL)
671  {
672  /* prepare for next loop */
673  snmp_oid_assign(node_oid, node_instance->instance_oid.id, node_instance->instance_oid.len);
674  node_instance->instance_oid.len = 0;
675  node_instance->node = mn;
676  }
677  }
678  }
679 
680  if (mn != NULL) {
681  /*
682  we found a suitable next node,
683  now we have to check if a inner MIB is located between the searched OID and the resulting OID.
684  this is possible because MIB's may be located anywhere in the global tree, that means also in
685  the subtree of another MIB (e.g. if searched OID is .2 and resulting OID is .4, then another
686  MIB having .3 as root node may exist)
687  */
688  const struct snmp_mib *intermediate_mib;
689  intermediate_mib = snmp_get_mib_between(start_oid, start_oid_len, node_oid->id, node_oid->len);
690 
691  if (intermediate_mib != NULL) {
692  /* search for first node inside intermediate mib in next loop */
693  if (node_instance->release_instance != NULL) {
694  node_instance->release_instance(node_instance);
695  }
696 
697  mn = NULL;
698  mib = intermediate_mib;
699  start_oid = mib->base_oid;
700  start_oid_len = mib->base_oid_len;
701  }
702  /* else { we found out target node } */
703  } else {
704  /*
705  there is no further (suitable) node inside this MIB, search for the next MIB with following priority
706  1. search for inner MIB's (whose root is located inside tree of current MIB)
707  2. search for surrouding MIB's (where the current MIB is the inner MIB) and continue there if any
708  3. take the next closest MIB (not being related to the current MIB)
709  */
710  const struct snmp_mib *next_mib;
711  next_mib = snmp_get_next_mib(start_oid, start_oid_len); /* returns MIB's related to point 1 and 3 */
712 
713  /* is the found MIB an inner MIB? (point 1) */
714  if ((next_mib != NULL) && (next_mib->base_oid_len > mib->base_oid_len) &&
715  (snmp_oid_compare(next_mib->base_oid, mib->base_oid_len, mib->base_oid, mib->base_oid_len) == 0)) {
716  /* yes it is -> continue at inner MIB */
717  mib = next_mib;
718  start_oid = mib->base_oid;
719  start_oid_len = mib->base_oid_len;
720  } else {
721  /* check if there is a surrounding mib where to continue (point 2) (only possible if OID length > 1) */
722  if (mib->base_oid_len > 1) {
723  mib = snmp_get_mib_from_oid(mib->base_oid, mib->base_oid_len - 1);
724 
725  if (mib == NULL) {
726  /* no surrounding mib, use next mib encountered above (point 3) */
727  mib = next_mib;
728 
729  if (mib != NULL) {
730  start_oid = mib->base_oid;
731  start_oid_len = mib->base_oid_len;
732  }
733  }
734  /* else { start_oid stays the same because we want to continue from current offset in surrounding mib (point 2) } */
735  }
736  }
737  }
738  }
739 
740  if (mib == NULL)
741  {
742  /* loop is only left when mib == null (error) or mib_node != NULL (success) */
743  return SNMP_ERR_ENDOFMIBVIEW;
744  }
745 
746  return SNMP_ERR_NOERROR;
747 }
748 
753 const struct snmp_node *
754 snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len)
755 {
756  const struct snmp_node* const* node = &mib->root_node;
757  u8_t oid_offset = mib->base_oid_len;
758 
759  while ((oid_offset < oid_len) && ((*node)->node_type == SNMP_NODE_TREE))
760  {
761  /* search for matching sub node */
762  u32_t subnode_oid = *(oid + oid_offset);
763 
764  u32_t i = (*(const struct snmp_tree_node* const*)node)->subnode_count;
765  node = (*(const struct snmp_tree_node* const*)node)->subnodes;
766  while ((i > 0) && ((*node)->oid != subnode_oid))
767  {
768  node++;
769  i--;
770  }
771 
772  if (i == 0)
773  {
774  /* no matching subnode found */
775  return NULL;
776  }
777 
778  oid_offset++;
779  }
780 
781  if ((*node)->node_type != SNMP_NODE_TREE)
782  {
783  /* we found a leaf node */
784  *oid_instance_len = oid_len - oid_offset;
785  return (*node);
786  }
787 
788  return NULL;
789 }
790 
791 const struct snmp_node*
792 snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret)
793 {
794  u8_t oid_offset = mib->base_oid_len;
795  const struct snmp_node* const* node;
796  const struct snmp_tree_node* node_stack[SNMP_MAX_OBJ_ID_LEN];
797  s32_t nsi = 0; /* NodeStackIndex */
798  u32_t subnode_oid;
799 
800  if (mib->root_node->node_type != SNMP_NODE_TREE)
801  {
802  /* a next operation on a mib with only a leaf node will always return NULL because there is no other node */
803  return NULL;
804  }
805 
806  /* first build node stack related to passed oid (as far as possible), then go backwards to determine the next node */
807  node_stack[nsi] = (const struct snmp_tree_node*)mib->root_node;
808  while (oid_offset < oid_len)
809  {
810  /* search for matching sub node */
811  u32_t i = node_stack[nsi]->subnode_count;
812  node = node_stack[nsi]->subnodes;
813 
814  subnode_oid = *(oid + oid_offset);
815 
816  while ((i > 0) && ((*node)->oid != subnode_oid))
817  {
818  node++;
819  i--;
820  }
821 
822  if ((i == 0) || ((*node)->node_type != SNMP_NODE_TREE))
823  {
824  /* no (matching) tree-subnode found */
825  break;
826  }
827  nsi++;
828  node_stack[nsi] = (const struct snmp_tree_node*)(*node);
829 
830  oid_offset++;
831  }
832 
833 
834  if (oid_offset >= oid_len)
835  {
836  /* passed oid references a tree node -> return first useable sub node of it */
837  subnode_oid = 0;
838  }
839  else
840  {
841  subnode_oid = *(oid + oid_offset) + 1;
842  }
843 
844  while (nsi >= 0)
845  {
846  const struct snmp_node* subnode = NULL;
847 
848  /* find next node on current level */
849  s32_t i = node_stack[nsi]->subnode_count;
850  node = node_stack[nsi]->subnodes;
851  while (i > 0)
852  {
853  if ((*node)->oid == subnode_oid)
854  {
855  subnode = *node;
856  break;
857  }
858  else if (((*node)->oid > subnode_oid) && ((subnode == NULL) || ((*node)->oid < subnode->oid)))
859  {
860  subnode = *node;
861  }
862 
863  node++;
864  i--;
865  }
866 
867  if (subnode == NULL)
868  {
869  /* no further node found on this level, go one level up and start searching with index of current node*/
870  subnode_oid = node_stack[nsi]->node.oid + 1;
871  nsi--;
872  }
873  else
874  {
875  if (subnode->node_type == SNMP_NODE_TREE)
876  {
877  /* next is a tree node, go into it and start searching */
878  nsi++;
879  node_stack[nsi] = (const struct snmp_tree_node*)subnode;
880  subnode_oid = 0;
881  }
882  else
883  {
884  /* we found a leaf node -> fill oidret and return it */
885  snmp_oid_assign(oidret, mib->base_oid, mib->base_oid_len);
886  i = 1;
887  while (i <= nsi)
888  {
889  oidret->id[oidret->len] = node_stack[i]->node.oid;
890  oidret->len++;
891  i++;
892  }
893 
894  oidret->id[oidret->len] = subnode->oid;
895  oidret->len++;
896 
897  return subnode;
898  }
899  }
900  }
901 
902  return NULL;
903 }
904 
905 void
906 snmp_next_oid_init(struct snmp_next_oid_state *state,
907  const u32_t *start_oid, u8_t start_oid_len,
908  u32_t *next_oid_buf, u8_t next_oid_max_len)
909 {
910  state->start_oid = start_oid;
911  state->start_oid_len = start_oid_len;
912  state->next_oid = next_oid_buf;
913  state->next_oid_len = 0;
914  state->next_oid_max_len = next_oid_max_len;
915  state->status = SNMP_NEXT_OID_STATUS_NO_MATCH;
916 }
917 
918 u8_t
919 snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len)
920 {
921  if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL)
922  {
923  u8_t start_oid_len = (oid_len < state->start_oid_len) ? oid_len : state->start_oid_len;
924 
925  /* check passed OID is located behind start offset */
926  if (snmp_oid_compare(oid, oid_len, state->start_oid, start_oid_len) >= 0)
927  {
928  /* check if new oid is located closer to start oid than current closest oid */
929  if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) ||
930  (snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0))
931  {
932  return 1;
933  }
934  }
935  }
936 
937  return 0;
938 }
939 
940 u8_t
941 snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len, void* reference)
942 {
943  /* do not overwrite a fail result */
944  if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL)
945  {
946  /* check passed OID is located behind start offset */
947  if (snmp_oid_compare(oid, oid_len, state->start_oid, state->start_oid_len) > 0)
948  {
949  /* check if new oid is located closer to start oid than current closest oid */
950  if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) ||
951  (snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0))
952  {
953  if (oid_len <= state->next_oid_max_len)
954  {
955  MEMCPY(state->next_oid, oid, oid_len * sizeof(u32_t));
956  state->next_oid_len = oid_len;
957  state->status = SNMP_NEXT_OID_STATUS_SUCCESS;
958  state->reference = reference;
959  return 1;
960  }
961  else
962  {
963  state->status = SNMP_NEXT_OID_STATUS_BUF_TO_SMALL;
964  }
965  }
966  }
967  }
968 
969  return 0;
970 }
971 
972 u8_t
973 snmp_oid_in_range(const u32_t *oid_in, u8_t oid_len, const struct snmp_oid_range *oid_ranges, u8_t oid_ranges_len)
974 {
975  u8_t i;
976 
977  if(oid_len != oid_ranges_len) {
978  return 0;
979  }
980 
981  for(i=0; i<oid_ranges_len; i++)
982  {
983  if((oid_in[i] < oid_ranges[i].min) || (oid_in[i] > oid_ranges[i].max)) {
984  return 0;
985  }
986  }
987 
988  return 1;
989 }
990 
991 snmp_err_t
992 snmp_set_test_ok(struct snmp_node_instance* instance, u16_t value_len, void* value)
993 {
994  LWIP_UNUSED_ARG(instance);
995  LWIP_UNUSED_ARG(value_len);
996  LWIP_UNUSED_ARG(value);
997 
998  return SNMP_ERR_NOERROR;
999 }
1000 
1013 err_t
1014 snmp_decode_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value)
1015 {
1016  u8_t b;
1017  u8_t bits_processed = 0;
1018  *bit_value = 0;
1019 
1020  while (buf_len > 0) {
1021  /* any bit set in this byte? */
1022  if (*buf != 0x00) {
1023  if (bits_processed >= 32) {
1024  /* accept more than 4 bytes, but only when no bits are set */
1025  return ERR_VAL;
1026  }
1027 
1028  b = *buf;
1029  do {
1030  if (b & 0x80) {
1031  *bit_value |= (1 << bits_processed);
1032  }
1033  bits_processed++;
1034  b <<= 1;
1035  }
1036  while ((bits_processed % 8) != 0);
1037  } else {
1038  bits_processed += 8;
1039  }
1040 
1041  buf_len--;
1042  buf++;
1043  }
1044 
1045  return ERR_OK;
1046 }
1047 
1048 err_t
1049 snmp_decode_truthvalue(const s32_t *asn1_value, u8_t *bool_value)
1050 {
1051  /* defined by RFC1443:
1052  TruthValue ::= TEXTUAL-CONVENTION
1053  STATUS current
1054  DESCRIPTION
1055  "Represents a boolean value."
1056  SYNTAX INTEGER { true(1), false(2) }
1057  */
1058 
1059  if ((asn1_value == NULL) || (bool_value == NULL)) {
1060  return ERR_ARG;
1061  }
1062 
1063  if (*asn1_value == 1) {
1064  *bool_value = 1;
1065  } else if (*asn1_value == 2) {
1066  *bool_value = 0;
1067  } else {
1068  return ERR_VAL;
1069  }
1070 
1071  return ERR_OK;
1072 }
1073 
1087 u8_t
1088 snmp_encode_bits(u8_t *buf, u32_t buf_len, u32_t bit_value, u8_t bit_count)
1089 {
1090  u8_t len = 0;
1091  u8_t min_bytes = (bit_count + 7) / 8;
1092 
1093  while ((buf_len > 0) && (bit_value != 0x00)) {
1094  s8_t i = 7;
1095  *buf = 0x00;
1096  while (i >= 0) {
1097  if (bit_value & 0x01) {
1098  *buf |= 0x01;
1099  }
1100 
1101  if (i > 0) {
1102  *buf <<= 1;
1103  }
1104 
1105  bit_value >>= 1;
1106  i--;
1107  }
1108 
1109  buf++;
1110  buf_len--;
1111  len++;
1112  }
1113 
1114  if (len < min_bytes)
1115  {
1116  buf += len;
1117  buf_len -= len;
1118 
1119  while ((len < min_bytes) && (buf_len > 0))
1120  {
1121  *buf = 0x00;
1122  buf++;
1123  buf_len--;
1124  len++;
1125  }
1126  }
1127 
1128  return len;
1129 }
1130 
1131 u8_t
1132 snmp_encode_truthvalue(s32_t *asn1_value, u32_t bool_value)
1133 {
1134  /* defined by RFC1443:
1135  TruthValue ::= TEXTUAL-CONVENTION
1136  STATUS current
1137  DESCRIPTION
1138  "Represents a boolean value."
1139  SYNTAX INTEGER { true(1), false(2) }
1140  */
1141 
1142  if (asn1_value == NULL) {
1143  return 0;
1144  }
1145 
1146  if (bool_value) {
1147  *asn1_value = 1; /* defined by RFC1443 */
1148  } else {
1149  *asn1_value = 2; /* defined by RFC1443 */
1150  }
1151 
1152  return sizeof(s32_t);
1153 }
1154 
1155 #endif /* LWIP_SNMP */
uint32_t idx
Definition: lcd_log.c:247
#define ip_2_ip6(ipaddr)
Definition: ip_addr.h:200
signed char s8_t
Definition: cc.h:39
#define ERR_VAL
Definition: err.h:58
#define SNMP_MAX_OBJ_ID_LEN
Definition: snmp_opts.h:120
#define MEMCPY(dst, src, len)
Definition: opt.h:84
if(LCD_Lock==DISABLE)
Definition: lcd_log.c:249
#define IP_IS_V6(ipaddr)
Definition: ip_addr.h:197
#define NULL
Definition: usbd_def.h:53
unsigned long u32_t
Definition: cc.h:42
#define ERR_OK
Definition: err.h:52
s8_t err_t
Definition: err.h:47
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:70
#define LWIP_ARRAYSIZE(x)
Definition: def.h:53
#define ERR_ARG
Definition: err.h:71
#define SNMP_DEBUG
Definition: snmp_opts.h:189
unsigned char u8_t
Definition: cc.h:38
ip6_addr_t ip_addr_t
Definition: ip_addr.h:194
#define SNMP_DEVICE_ENTERPRISE_OID
Definition: snmp_opts.h:181
signed long s32_t
Definition: cc.h:43
#define IP_SET_TYPE(ipaddr, iptype)
Definition: ip_addr.h:199
#define SNMP_DEVICE_ENTERPRISE_OID_LEN
Definition: snmp_opts.h:182
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:113
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:89
unsigned short u16_t
Definition: cc.h:40