BA
/
BaBoRo1
Embed:
(wiki syntax)
Show/hide line numbers
lwip_snmp_core.c
Go to the documentation of this file.
00001 /** 00002 * @file 00003 * MIB tree access/construction functions. 00004 */ 00005 00006 /* 00007 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. 00008 * All rights reserved. 00009 * 00010 * Redistribution and use in source and binary forms, with or without modification, 00011 * are permitted provided that the following conditions are met: 00012 * 00013 * 1. Redistributions of source code must retain the above copyright notice, 00014 * this list of conditions and the following disclaimer. 00015 * 2. Redistributions in binary form must reproduce the above copyright notice, 00016 * this list of conditions and the following disclaimer in the documentation 00017 * and/or other materials provided with the distribution. 00018 * 3. The name of the author may not be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00022 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00024 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00026 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00029 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00030 * OF SUCH DAMAGE. 00031 * 00032 * Author: Christiaan Simons <christiaan.simons@axon.tv> 00033 * Martin Hentschel <info@cl-soft.de> 00034 */ 00035 00036 /** 00037 * @defgroup snmp SNMPv2c agent 00038 * @ingroup apps 00039 * SNMPv2c compatible agent\n 00040 * There is also a MIB compiler and a MIB viewer in lwIP contrib repository 00041 * (lwip-contrib/apps/LwipMibCompiler).\n 00042 * The agent implements the most important MIB2 MIBs including IPv6 support 00043 * (interfaces, UDP, TCP, SNMP, ICMP, SYSTEM). IP MIB is an older version 00044 * whithout IPv6 statistics (TODO).\n 00045 * Rewritten by Martin Hentschel <info@cl-soft.de> and 00046 * Dirk Ziegelmeier <dziegel@gmx.de>\n 00047 * Work on SNMPv3 has started, but is not finished.\n 00048 * 00049 * 0 Agent Capabilities 00050 * ==================== 00051 * 00052 * Features: 00053 * --------- 00054 * - SNMPv2c support. 00055 * - Low RAM usage - no memory pools, stack only. 00056 * - MIB2 implementation is separated from SNMP stack. 00057 * - Support for multiple MIBs (snmp_set_mibs() call) - e.g. for private MIB. 00058 * - Simple and generic API for MIB implementation. 00059 * - Comfortable node types and helper functions for scalar arrays and tables. 00060 * - Counter64, bit and truthvalue datatype support. 00061 * - Callbacks for SNMP writes e.g. to implement persistency. 00062 * - Runs on two APIs: RAW and netconn. 00063 * - Async API is gone - the stack now supports netconn API instead, 00064 * so blocking operations can be done in MIB calls. 00065 * SNMP runs in a worker thread when netconn API is used. 00066 * - Simplified thread sync support for MIBs - useful when MIBs 00067 * need to access variables shared with other threads where no locking is 00068 * possible. Used in MIB2 to access lwIP stats from lwIP thread. 00069 * 00070 * MIB compiler (code generator): 00071 * ------------------------------ 00072 * - Provided in lwIP contrib repository. 00073 * - Written in C#. MIB viewer used Windows Forms. 00074 * - Developed on Windows with Visual Studio 2010. 00075 * - Can be compiled and used on all platforms with http://www.monodevelop.com/. 00076 * - Based on a heavily modified version of of SharpSnmpLib (a4bd05c6afb4) 00077 * (https://sharpsnmplib.codeplex.com/SourceControl/network/forks/Nemo157/MIBParserUpdate). 00078 * - MIB parser, C file generation framework and LWIP code generation are cleanly 00079 * separated, which means the code may be useful as a base for code generation 00080 * of other SNMP agents. 00081 * 00082 * Notes: 00083 * ------ 00084 * - Stack and MIB compiler were used to implement a Profinet device. 00085 * Compiled/implemented MIBs: LLDP-MIB, LLDP-EXT-DOT3-MIB, LLDP-EXT-PNO-MIB. 00086 * 00087 * SNMPv1 per RFC1157 and SNMPv2c per RFC 3416 00088 * ------------------------------------------- 00089 * Note the S in SNMP stands for "Simple". Note that "Simple" is 00090 * relative. SNMP is simple compared to the complex ISO network 00091 * management protocols CMIP (Common Management Information Protocol) 00092 * and CMOT (CMip Over Tcp). 00093 * 00094 * MIB II 00095 * ------ 00096 * The standard lwIP stack management information base. 00097 * This is a required MIB, so this is always enabled. 00098 * The groups EGP, CMOT and transmission are disabled by default. 00099 * 00100 * Most mib-2 objects are not writable except: 00101 * sysName, sysLocation, sysContact, snmpEnableAuthenTraps. 00102 * Writing to or changing the ARP and IP address and route 00103 * tables is not possible. 00104 * 00105 * Note lwIP has a very limited notion of IP routing. It currently 00106 * doen't have a route table and doesn't have a notion of the U,G,H flags. 00107 * Instead lwIP uses the interface list with only one default interface 00108 * acting as a single gateway interface (G) for the default route. 00109 * 00110 * The agent returns a "virtual table" with the default route 0.0.0.0 00111 * for the default interface and network routes (no H) for each 00112 * network interface in the netif_list. 00113 * All routes are considered to be up (U). 00114 * 00115 * Loading additional MIBs 00116 * ----------------------- 00117 * MIBs can only be added in compile-time, not in run-time. 00118 * 00119 * 00120 * 1 Building the Agent 00121 * ==================== 00122 * First of all you'll need to add the following define 00123 * to your local lwipopts.h: 00124 * \#define LWIP_SNMP 1 00125 * 00126 * and add the source files your makefile. 00127 * 00128 * Note you'll might need to adapt you network driver to update 00129 * the mib2 variables for your interface. 00130 * 00131 * 2 Running the Agent 00132 * =================== 00133 * The following function calls must be made in your program to 00134 * actually get the SNMP agent running. 00135 * 00136 * Before starting the agent you should supply pointers 00137 * for sysContact, sysLocation, and snmpEnableAuthenTraps. 00138 * You can do this by calling 00139 * 00140 * - snmp_mib2_set_syscontact() 00141 * - snmp_mib2_set_syslocation() 00142 * - snmp_set_auth_traps_enabled() 00143 * 00144 * You can register a callback which is called on successful write access: 00145 * snmp_set_write_callback(). 00146 * 00147 * Additionally you may want to set 00148 * 00149 * - snmp_mib2_set_sysdescr() 00150 * - snmp_set_device_enterprise_oid() 00151 * - snmp_mib2_set_sysname() 00152 * 00153 * Also before starting the agent you need to setup 00154 * one or more trap destinations using these calls: 00155 * 00156 * - snmp_trap_dst_enable() 00157 * - snmp_trap_dst_ip_set() 00158 * 00159 * If you need more than MIB2, set the MIBs you want to use 00160 * by snmp_set_mibs(). 00161 * 00162 * Finally, enable the agent by calling snmp_init() 00163 * 00164 * @defgroup snmp_core Core 00165 * @ingroup snmp 00166 * 00167 * @defgroup snmp_traps Traps 00168 * @ingroup snmp 00169 */ 00170 00171 #include "lwip/apps/snmp_opts.h" 00172 00173 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ 00174 00175 #include "lwip/apps/snmp.h" 00176 #include "lwip/apps/snmp_core.h" 00177 #include "snmp_core_priv.h" 00178 #include "lwip/netif.h" 00179 #include <string.h> 00180 00181 00182 #if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0)) 00183 #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h" 00184 #endif 00185 #if (!LWIP_UDP && LWIP_SNMP) 00186 #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h" 00187 #endif 00188 00189 struct snmp_statistics snmp_stats; 00190 static const struct snmp_obj_id snmp_device_enterprise_oid_default = {SNMP_DEVICE_ENTERPRISE_OID_LEN, SNMP_DEVICE_ENTERPRISE_OID}; 00191 static const struct snmp_obj_id* snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default; 00192 00193 const u32_t snmp_zero_dot_zero_values[] = { 0, 0 }; 00194 const struct snmp_obj_id_const_ref snmp_zero_dot_zero = { LWIP_ARRAYSIZE(snmp_zero_dot_zero_values), snmp_zero_dot_zero_values }; 00195 00196 00197 #if SNMP_LWIP_MIB2 00198 #include "lwip/apps/snmp_mib2.h" 00199 static const struct snmp_mib* const default_mibs[] = { &mib2 }; 00200 static u8_t snmp_num_mibs = 1; 00201 #else 00202 static const struct snmp_mib* const default_mibs[] = { NULL }; 00203 static u8_t snmp_num_mibs = 0; 00204 #endif 00205 00206 /* List of known mibs */ 00207 static struct snmp_mib const * const *snmp_mibs = default_mibs; 00208 00209 /** 00210 * @ingroup snmp_core 00211 * Sets the MIBs to use. 00212 * Example: call snmp_set_mibs() as follows: 00213 * static const struct snmp_mib *my_snmp_mibs[] = { 00214 * &mib2, 00215 * &private_mib 00216 * }; 00217 * snmp_set_mibs(my_snmp_mibs, LWIP_ARRAYSIZE(my_snmp_mibs)); 00218 */ 00219 void 00220 snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs) 00221 { 00222 LWIP_ASSERT("mibs pointer must be != NULL", (mibs != NULL)); 00223 LWIP_ASSERT("num_mibs pointer must be != 0", (num_mibs != 0)); 00224 snmp_mibs = mibs; 00225 snmp_num_mibs = num_mibs; 00226 } 00227 00228 /** 00229 * @ingroup snmp_core 00230 * 'device enterprise oid' is used for 'device OID' field in trap PDU's (for identification of generating device) 00231 * as well as for value returned by MIB-2 'sysObjectID' field (if internal MIB2 implementation is used). 00232 * The 'device enterprise oid' shall point to an OID located under 'private-enterprises' branch (1.3.6.1.4.1.XXX). If a vendor 00233 * wants to provide a custom object there, he has to get its own enterprise oid from IANA (http://www.iana.org). It 00234 * is not allowed to use LWIP enterprise ID! 00235 * In order to identify a specific device it is recommended to create a dedicated OID for each device type under its own 00236 * enterprise oid. 00237 * e.g. 00238 * device a > 1.3.6.1.4.1.XXX(ent-oid).1(devices).1(device a) 00239 * device b > 1.3.6.1.4.1.XXX(ent-oid).1(devices).2(device b) 00240 * for more details see description of 'sysObjectID' field in RFC1213-MIB 00241 */ 00242 void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_oid) 00243 { 00244 if (device_enterprise_oid == NULL) { 00245 snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default; 00246 } else { 00247 snmp_device_enterprise_oid = device_enterprise_oid; 00248 } 00249 } 00250 00251 /** 00252 * @ingroup snmp_core 00253 * Get 'device enterprise oid' 00254 */ 00255 const struct snmp_obj_id* snmp_get_device_enterprise_oid(void) 00256 { 00257 return snmp_device_enterprise_oid; 00258 } 00259 00260 #if LWIP_IPV4 00261 /** 00262 * Conversion from InetAddressIPv4 oid to lwIP ip4_addr 00263 * @param oid points to u32_t ident[4] input 00264 * @param ip points to output struct 00265 */ 00266 u8_t 00267 snmp_oid_to_ip4(const u32_t *oid, ip4_addr_t *ip) 00268 { 00269 if ((oid[0] > 0xFF) || 00270 (oid[1] > 0xFF) || 00271 (oid[2] > 0xFF) || 00272 (oid[3] > 0xFF)) { 00273 ip4_addr_copy(*ip, *IP4_ADDR_ANY4); 00274 return 0; 00275 } 00276 00277 IP4_ADDR(ip, oid[0], oid[1], oid[2], oid[3]); 00278 return 1; 00279 } 00280 00281 /** 00282 * Convert ip4_addr to InetAddressIPv4 (no InetAddressType) 00283 * @param ip points to input struct 00284 * @param oid points to u32_t ident[4] output 00285 */ 00286 void 00287 snmp_ip4_to_oid(const ip4_addr_t *ip, u32_t *oid) 00288 { 00289 oid[0] = ip4_addr1(ip); 00290 oid[1] = ip4_addr2(ip); 00291 oid[2] = ip4_addr3(ip); 00292 oid[3] = ip4_addr4(ip); 00293 } 00294 #endif /* LWIP_IPV4 */ 00295 00296 #if LWIP_IPV6 00297 /** 00298 * Conversion from InetAddressIPv6 oid to lwIP ip6_addr 00299 * @param oid points to u32_t oid[16] input 00300 * @param ip points to output struct 00301 */ 00302 u8_t 00303 snmp_oid_to_ip6(const u32_t *oid, ip6_addr_t *ip) 00304 { 00305 if ((oid[0] > 0xFF) || 00306 (oid[1] > 0xFF) || 00307 (oid[2] > 0xFF) || 00308 (oid[3] > 0xFF) || 00309 (oid[4] > 0xFF) || 00310 (oid[5] > 0xFF) || 00311 (oid[6] > 0xFF) || 00312 (oid[7] > 0xFF) || 00313 (oid[8] > 0xFF) || 00314 (oid[9] > 0xFF) || 00315 (oid[10] > 0xFF) || 00316 (oid[11] > 0xFF) || 00317 (oid[12] > 0xFF) || 00318 (oid[13] > 0xFF) || 00319 (oid[14] > 0xFF) || 00320 (oid[15] > 0xFF)) { 00321 ip6_addr_set_any(ip); 00322 return 0; 00323 } 00324 00325 ip->addr[0] = (oid[0] << 24) | (oid[1] << 16) | (oid[2] << 8) | (oid[3] << 0); 00326 ip->addr[1] = (oid[4] << 24) | (oid[5] << 16) | (oid[6] << 8) | (oid[7] << 0); 00327 ip->addr[2] = (oid[8] << 24) | (oid[9] << 16) | (oid[10] << 8) | (oid[11] << 0); 00328 ip->addr[3] = (oid[12] << 24) | (oid[13] << 16) | (oid[14] << 8) | (oid[15] << 0); 00329 return 1; 00330 } 00331 00332 /** 00333 * Convert ip6_addr to InetAddressIPv6 (no InetAddressType) 00334 * @param ip points to input struct 00335 * @param oid points to u32_t ident[16] output 00336 */ 00337 void 00338 snmp_ip6_to_oid(const ip6_addr_t *ip, u32_t *oid) 00339 { 00340 oid[0] = (ip->addr[0] & 0xFF000000) >> 24; 00341 oid[1] = (ip->addr[0] & 0x00FF0000) >> 16; 00342 oid[2] = (ip->addr[0] & 0x0000FF00) >> 8; 00343 oid[3] = (ip->addr[0] & 0x000000FF) >> 0; 00344 oid[4] = (ip->addr[1] & 0xFF000000) >> 24; 00345 oid[5] = (ip->addr[1] & 0x00FF0000) >> 16; 00346 oid[6] = (ip->addr[1] & 0x0000FF00) >> 8; 00347 oid[7] = (ip->addr[1] & 0x000000FF) >> 0; 00348 oid[8] = (ip->addr[2] & 0xFF000000) >> 24; 00349 oid[9] = (ip->addr[2] & 0x00FF0000) >> 16; 00350 oid[10] = (ip->addr[2] & 0x0000FF00) >> 8; 00351 oid[11] = (ip->addr[2] & 0x000000FF) >> 0; 00352 oid[12] = (ip->addr[3] & 0xFF000000) >> 24; 00353 oid[13] = (ip->addr[3] & 0x00FF0000) >> 16; 00354 oid[14] = (ip->addr[3] & 0x0000FF00) >> 8; 00355 oid[15] = (ip->addr[3] & 0x000000FF) >> 0; 00356 } 00357 #endif /* LWIP_IPV6 */ 00358 00359 #if LWIP_IPV4 || LWIP_IPV6 00360 /** 00361 * Convert to InetAddressType+InetAddress+InetPortNumber 00362 * @param ip IP address 00363 * @param port Port 00364 * @param oid OID 00365 * @return OID length 00366 */ 00367 u8_t 00368 snmp_ip_port_to_oid(const ip_addr_t *ip, u16_t port, u32_t *oid) 00369 { 00370 u8_t idx; 00371 00372 idx = snmp_ip_to_oid(ip, oid); 00373 oid[idx] = port; 00374 idx++; 00375 00376 return idx; 00377 } 00378 00379 /** 00380 * Convert to InetAddressType+InetAddress 00381 * @param ip IP address 00382 * @param oid OID 00383 * @return OID length 00384 */ 00385 u8_t 00386 snmp_ip_to_oid(const ip_addr_t *ip, u32_t *oid) 00387 { 00388 if (IP_IS_ANY_TYPE_VAL(*ip)) { 00389 oid[0] = 0; /* any */ 00390 oid[1] = 0; /* no IP OIDs follow */ 00391 return 2; 00392 } else if (IP_IS_V6(ip)) { 00393 #if LWIP_IPV6 00394 oid[0] = 2; /* ipv6 */ 00395 oid[1] = 16; /* 16 InetAddressIPv6 OIDs follow */ 00396 snmp_ip6_to_oid(ip_2_ip6(ip), &oid[2]); 00397 return 18; 00398 #else /* LWIP_IPV6 */ 00399 return 0; 00400 #endif /* LWIP_IPV6 */ 00401 } else { 00402 #if LWIP_IPV4 00403 oid[0] = 1; /* ipv4 */ 00404 oid[1] = 4; /* 4 InetAddressIPv4 OIDs follow */ 00405 snmp_ip4_to_oid(ip_2_ip4(ip), &oid[2]); 00406 return 6; 00407 #else /* LWIP_IPV4 */ 00408 return 0; 00409 #endif /* LWIP_IPV4 */ 00410 } 00411 } 00412 00413 /** 00414 * Convert from InetAddressType+InetAddress to ip_addr_t 00415 * @param oid OID 00416 * @param oid_len OID length 00417 * @param ip IP address 00418 * @return Parsed OID length 00419 */ 00420 u8_t 00421 snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip) 00422 { 00423 /* InetAddressType */ 00424 if (oid_len < 1) { 00425 return 0; 00426 } 00427 00428 if (oid[0] == 0) { /* any */ 00429 /* 1x InetAddressType, 1x OID len */ 00430 if (oid_len < 2) { 00431 return 0; 00432 } 00433 if (oid[1] != 0) { 00434 return 0; 00435 } 00436 00437 memset(ip, 0, sizeof(*ip)); 00438 IP_SET_TYPE(ip, IPADDR_TYPE_ANY); 00439 00440 return 2; 00441 } else if (oid[0] == 1) { /* ipv4 */ 00442 #if LWIP_IPV4 00443 /* 1x InetAddressType, 1x OID len, 4x InetAddressIPv4 */ 00444 if (oid_len < 6) { 00445 return 0; 00446 } 00447 00448 /* 4x ipv4 OID */ 00449 if (oid[1] != 4) { 00450 return 0; 00451 } 00452 00453 IP_SET_TYPE(ip, IPADDR_TYPE_V4); 00454 if (!snmp_oid_to_ip4(&oid[2], ip_2_ip4(ip))) { 00455 return 0; 00456 } 00457 00458 return 6; 00459 #else /* LWIP_IPV4 */ 00460 return 0; 00461 #endif /* LWIP_IPV4 */ 00462 } else if (oid[0] == 2) { /* ipv6 */ 00463 #if LWIP_IPV6 00464 /* 1x InetAddressType, 1x OID len, 16x InetAddressIPv6 */ 00465 if (oid_len < 18) { 00466 return 0; 00467 } 00468 00469 /* 16x ipv6 OID */ 00470 if (oid[1] != 16) { 00471 return 0; 00472 } 00473 00474 IP_SET_TYPE(ip, IPADDR_TYPE_V6); 00475 if (!snmp_oid_to_ip6(&oid[2], ip_2_ip6(ip))) { 00476 return 0; 00477 } 00478 00479 return 18; 00480 #else /* LWIP_IPV6 */ 00481 return 0; 00482 #endif /* LWIP_IPV6 */ 00483 } else { /* unsupported InetAddressType */ 00484 return 0; 00485 } 00486 } 00487 00488 /** 00489 * Convert from InetAddressType+InetAddress+InetPortNumber to ip_addr_t and u16_t 00490 * @param oid OID 00491 * @param oid_len OID length 00492 * @param ip IP address 00493 * @param port Port 00494 * @return Parsed OID length 00495 */ 00496 u8_t 00497 snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port) 00498 { 00499 u8_t idx = 0; 00500 00501 /* InetAddressType + InetAddress */ 00502 idx += snmp_oid_to_ip(&oid[idx], oid_len-idx, ip); 00503 if (idx == 0) { 00504 return 0; 00505 } 00506 00507 /* InetPortNumber */ 00508 if (oid_len < (idx+1)) { 00509 return 0; 00510 } 00511 if (oid[idx] > 0xffff) { 00512 return 0; 00513 } 00514 *port = (u16_t)oid[idx]; 00515 idx++; 00516 00517 return idx; 00518 } 00519 00520 #endif /* LWIP_IPV4 || LWIP_IPV6 */ 00521 00522 /** 00523 * Assign an OID to struct snmp_obj_id 00524 * @param target Assignment target 00525 * @param oid OID 00526 * @param oid_len OID length 00527 */ 00528 void 00529 snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len) 00530 { 00531 LWIP_ASSERT("oid_len <= LWIP_SNMP_OBJ_ID_LEN", oid_len <= SNMP_MAX_OBJ_ID_LEN); 00532 00533 target->len = oid_len; 00534 00535 if (oid_len > 0) { 00536 MEMCPY(target->id, oid, oid_len * sizeof(u32_t)); 00537 } 00538 } 00539 00540 /** 00541 * Prefix an OID to OID in struct snmp_obj_id 00542 * @param target Assignment target to prefix 00543 * @param oid OID 00544 * @param oid_len OID length 00545 */ 00546 void 00547 snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len) 00548 { 00549 LWIP_ASSERT("target->len + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN); 00550 00551 if (oid_len > 0) { 00552 /* move existing OID to make room at the beginning for OID to insert */ 00553 int i; 00554 for (i = target->len-1; i>=0; i--) { 00555 target->id[i + oid_len] = target->id[i]; 00556 } 00557 00558 /* paste oid at the beginning */ 00559 MEMCPY(target->id, oid, oid_len * sizeof(u32_t)); 00560 } 00561 } 00562 00563 /** 00564 * Combine two OIDs into struct snmp_obj_id 00565 * @param target Assignmet target 00566 * @param oid1 OID 1 00567 * @param oid1_len OID 1 length 00568 * @param oid2 OID 2 00569 * @param oid2_len OID 2 length 00570 */ 00571 void 00572 snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len) 00573 { 00574 snmp_oid_assign(target, oid1, oid1_len); 00575 snmp_oid_append(target, oid2, oid2_len); 00576 } 00577 00578 /** 00579 * Append OIDs to struct snmp_obj_id 00580 * @param target Assignment target to append to 00581 * @param oid OID 00582 * @param oid_len OID length 00583 */ 00584 void 00585 snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len) 00586 { 00587 LWIP_ASSERT("offset + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN); 00588 00589 if (oid_len > 0) { 00590 MEMCPY(&target->id[target->len], oid, oid_len * sizeof(u32_t)); 00591 target->len += oid_len; 00592 } 00593 } 00594 00595 /** 00596 * Compare two OIDs 00597 * @param oid1 OID 1 00598 * @param oid1_len OID 1 length 00599 * @param oid2 OID 2 00600 * @param oid2_len OID 2 length 00601 * @return -1: OID1<OID2 1: OID1 >OID2 0: equal 00602 */ 00603 s8_t 00604 snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len) 00605 { 00606 u8_t level = 0; 00607 LWIP_ASSERT("'oid1' param must not be NULL or 'oid1_len' param be 0!", (oid1 != NULL) || (oid1_len == 0)); 00608 LWIP_ASSERT("'oid2' param must not be NULL or 'oid2_len' param be 0!", (oid2 != NULL) || (oid2_len == 0)); 00609 00610 while ((level < oid1_len) && (level < oid2_len)) { 00611 if (*oid1 < *oid2) { 00612 return -1; 00613 } 00614 if (*oid1 > *oid2) { 00615 return 1; 00616 } 00617 00618 level++; 00619 oid1++; 00620 oid2++; 00621 } 00622 00623 /* common part of both OID's is equal, compare length */ 00624 if (oid1_len < oid2_len) { 00625 return -1; 00626 } 00627 if (oid1_len > oid2_len) { 00628 return 1; 00629 } 00630 00631 /* they are equal */ 00632 return 0; 00633 } 00634 00635 00636 /** 00637 * Check of two OIDs are equal 00638 * @param oid1 OID 1 00639 * @param oid1_len OID 1 length 00640 * @param oid2 OID 2 00641 * @param oid2_len OID 2 length 00642 * @return 1: equal 0: non-equal 00643 */ 00644 u8_t 00645 snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len) 00646 { 00647 return (snmp_oid_compare(oid1, oid1_len, oid2, oid2_len) == 0)? 1 : 0; 00648 } 00649 00650 /** 00651 * Convert netif to interface index 00652 * @param netif netif 00653 * @return index 00654 */ 00655 u8_t 00656 netif_to_num(const struct netif *netif) 00657 { 00658 u8_t result = 0; 00659 struct netif *netif_iterator = netif_list; 00660 00661 while (netif_iterator != NULL) { 00662 result++; 00663 00664 if (netif_iterator == netif) { 00665 return result; 00666 } 00667 00668 netif_iterator = netif_iterator->next; 00669 } 00670 00671 LWIP_ASSERT("netif not found in netif_list", 0); 00672 return 0; 00673 } 00674 00675 static const struct snmp_mib* 00676 snmp_get_mib_from_oid(const u32_t *oid, u8_t oid_len) 00677 { 00678 const u32_t* list_oid; 00679 const u32_t* searched_oid; 00680 u8_t i, l; 00681 00682 u8_t max_match_len = 0; 00683 const struct snmp_mib* matched_mib = NULL; 00684 00685 LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL)); 00686 00687 if (oid_len == 0) { 00688 return NULL; 00689 } 00690 00691 for (i = 0; i < snmp_num_mibs; i++) { 00692 LWIP_ASSERT("MIB array not initialized correctly", (snmp_mibs[i] != NULL)); 00693 LWIP_ASSERT("MIB array not initialized correctly - base OID is NULL", (snmp_mibs[i]->base_oid != NULL)); 00694 00695 if (oid_len >= snmp_mibs[i]->base_oid_len) { 00696 l = snmp_mibs[i]->base_oid_len; 00697 list_oid = snmp_mibs[i]->base_oid; 00698 searched_oid = oid; 00699 00700 while (l > 0) { 00701 if (*list_oid != *searched_oid) { 00702 break; 00703 } 00704 00705 l--; 00706 list_oid++; 00707 searched_oid++; 00708 } 00709 00710 if ((l == 0) && (snmp_mibs[i]->base_oid_len > max_match_len)) { 00711 max_match_len = snmp_mibs[i]->base_oid_len; 00712 matched_mib = snmp_mibs[i]; 00713 } 00714 } 00715 } 00716 00717 return matched_mib; 00718 } 00719 00720 static const struct snmp_mib* 00721 snmp_get_next_mib(const u32_t *oid, u8_t oid_len) 00722 { 00723 u8_t i; 00724 const struct snmp_mib* next_mib = NULL; 00725 00726 LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL)); 00727 00728 if (oid_len == 0) { 00729 return NULL; 00730 } 00731 00732 for (i = 0; i < snmp_num_mibs; i++) { 00733 if (snmp_mibs[i]->base_oid != NULL) { 00734 /* check if mib is located behind starting point */ 00735 if (snmp_oid_compare(snmp_mibs[i]->base_oid, snmp_mibs[i]->base_oid_len, oid, oid_len) > 0) { 00736 if ((next_mib == NULL) || 00737 (snmp_oid_compare(snmp_mibs[i]->base_oid, snmp_mibs[i]->base_oid_len, 00738 next_mib->base_oid, next_mib->base_oid_len) < 0)) { 00739 next_mib = snmp_mibs[i]; 00740 } 00741 } 00742 } 00743 } 00744 00745 return next_mib; 00746 } 00747 00748 static const struct snmp_mib* 00749 snmp_get_mib_between(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len) 00750 { 00751 const struct snmp_mib* next_mib = snmp_get_next_mib(oid1, oid1_len); 00752 00753 LWIP_ASSERT("'oid2' param must not be NULL!", (oid2 != NULL)); 00754 LWIP_ASSERT("'oid2_len' param must be greater than 0!", (oid2_len > 0)); 00755 00756 if (next_mib != NULL) { 00757 if (snmp_oid_compare(next_mib->base_oid, next_mib->base_oid_len, oid2, oid2_len) < 0) { 00758 return next_mib; 00759 } 00760 } 00761 00762 return NULL; 00763 } 00764 00765 u8_t 00766 snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance) 00767 { 00768 u8_t result = SNMP_ERR_NOSUCHOBJECT; 00769 const struct snmp_mib *mib; 00770 const struct snmp_node *mn = NULL; 00771 00772 mib = snmp_get_mib_from_oid(oid, oid_len); 00773 if (mib != NULL) { 00774 u8_t oid_instance_len; 00775 00776 mn = snmp_mib_tree_resolve_exact(mib, oid, oid_len, &oid_instance_len); 00777 if ((mn != NULL) && (mn->node_type != SNMP_NODE_TREE)) { 00778 /* get instance */ 00779 const struct snmp_leaf_node* leaf_node = (const struct snmp_leaf_node*)(const void*)mn; 00780 00781 node_instance->node = mn; 00782 snmp_oid_assign(&node_instance->instance_oid, oid + (oid_len - oid_instance_len), oid_instance_len); 00783 00784 result = leaf_node->get_instance( 00785 oid, 00786 oid_len - oid_instance_len, 00787 node_instance); 00788 00789 #ifdef LWIP_DEBUG 00790 if (result == SNMP_ERR_NOERROR) { 00791 if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != 0) && (node_instance->get_value == NULL)) { 00792 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is readable but no get_value function is specified\n")); 00793 } 00794 if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != 0) && (node_instance->set_value == NULL)) { 00795 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is writable but no set_value and/or set_test function is specified\n")); 00796 } 00797 } 00798 #endif 00799 } 00800 } 00801 00802 return result; 00803 } 00804 00805 u8_t 00806 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) 00807 { 00808 const struct snmp_mib *mib; 00809 const struct snmp_node *mn = NULL; 00810 const u32_t* start_oid = NULL; 00811 u8_t start_oid_len = 0; 00812 00813 /* resolve target MIB from passed OID */ 00814 mib = snmp_get_mib_from_oid(oid, oid_len); 00815 if (mib == NULL) { 00816 /* passed OID does not reference any known MIB, start at the next closest MIB */ 00817 mib = snmp_get_next_mib(oid, oid_len); 00818 00819 if (mib != NULL) { 00820 start_oid = mib->base_oid; 00821 start_oid_len = mib->base_oid_len; 00822 } 00823 } else { 00824 start_oid = oid; 00825 start_oid_len = oid_len; 00826 } 00827 00828 /* resolve target node from MIB, skip to next MIB if no suitable node is found in current MIB */ 00829 while ((mib != NULL) && (mn == NULL)) { 00830 u8_t oid_instance_len; 00831 00832 /* check if OID directly references a node inside current MIB, in this case we have to ask this node for the next instance */ 00833 mn = snmp_mib_tree_resolve_exact(mib, start_oid, start_oid_len, &oid_instance_len); 00834 if (mn != NULL) { 00835 snmp_oid_assign(node_oid, start_oid, start_oid_len - oid_instance_len); /* set oid to node */ 00836 snmp_oid_assign(&node_instance->instance_oid, start_oid + (start_oid_len - oid_instance_len), oid_instance_len); /* set (relative) instance oid */ 00837 } else { 00838 /* 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 */ 00839 mn = snmp_mib_tree_resolve_next(mib, start_oid, start_oid_len, node_oid); 00840 node_instance->instance_oid.len = 0; 00841 } 00842 00843 /* 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 */ 00844 node_instance->node = mn; 00845 while (mn != NULL) { 00846 u8_t result; 00847 00848 /* clear fields which may have values from previous loops */ 00849 node_instance->asn1_type = 0; 00850 node_instance->access = SNMP_NODE_INSTANCE_NOT_ACCESSIBLE; 00851 node_instance->get_value = NULL; 00852 node_instance->set_test = NULL; 00853 node_instance->set_value = NULL; 00854 node_instance->release_instance = NULL; 00855 node_instance->reference.ptr = NULL; 00856 node_instance->reference_len = 0; 00857 00858 result = ((const struct snmp_leaf_node*)(const void*)mn)->get_next_instance( 00859 node_oid->id, 00860 node_oid->len, 00861 node_instance); 00862 00863 if (result == SNMP_ERR_NOERROR) { 00864 #ifdef LWIP_DEBUG 00865 if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != 0) && (node_instance->get_value == NULL)) { 00866 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is readable but no get_value function is specified\n")); 00867 } 00868 if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != 0) && (node_instance->set_value == NULL)) { 00869 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is writable but no set_value function is specified\n")); 00870 } 00871 #endif 00872 00873 /* validate node because the node may be not accessible for example (but let the caller decide what is valid */ 00874 if ((validate_node_instance_method == NULL) || 00875 (validate_node_instance_method(node_instance, validate_node_instance_arg) == SNMP_ERR_NOERROR)) { 00876 /* node_oid "returns" the full result OID (including the instance part) */ 00877 snmp_oid_append(node_oid, node_instance->instance_oid.id, node_instance->instance_oid.len); 00878 break; 00879 } 00880 00881 if (node_instance->release_instance != NULL) { 00882 node_instance->release_instance(node_instance); 00883 } 00884 /* 00885 the instance itself is not valid, ask for next instance from same node. 00886 we don't have to change any variables because node_instance->instance_oid is used as input (starting point) 00887 as well as output (resulting next OID), so we have to simply call get_next_instance method again 00888 */ 00889 } else { 00890 if (node_instance->release_instance != NULL) { 00891 node_instance->release_instance(node_instance); 00892 } 00893 00894 /* the node has no further instance, skip to next node */ 00895 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 */ 00896 if (mn != NULL) { 00897 /* prepare for next loop */ 00898 snmp_oid_assign(node_oid, node_instance->instance_oid.id, node_instance->instance_oid.len); 00899 node_instance->instance_oid.len = 0; 00900 node_instance->node = mn; 00901 } 00902 } 00903 } 00904 00905 if (mn != NULL) { 00906 /* 00907 we found a suitable next node, 00908 now we have to check if a inner MIB is located between the searched OID and the resulting OID. 00909 this is possible because MIB's may be located anywhere in the global tree, that means also in 00910 the subtree of another MIB (e.g. if searched OID is .2 and resulting OID is .4, then another 00911 MIB having .3 as root node may exist) 00912 */ 00913 const struct snmp_mib *intermediate_mib; 00914 intermediate_mib = snmp_get_mib_between(start_oid, start_oid_len, node_oid->id, node_oid->len); 00915 00916 if (intermediate_mib != NULL) { 00917 /* search for first node inside intermediate mib in next loop */ 00918 if (node_instance->release_instance != NULL) { 00919 node_instance->release_instance(node_instance); 00920 } 00921 00922 mn = NULL; 00923 mib = intermediate_mib; 00924 start_oid = mib->base_oid; 00925 start_oid_len = mib->base_oid_len; 00926 } 00927 /* else { we found out target node } */ 00928 } else { 00929 /* 00930 there is no further (suitable) node inside this MIB, search for the next MIB with following priority 00931 1. search for inner MIB's (whose root is located inside tree of current MIB) 00932 2. search for surrouding MIB's (where the current MIB is the inner MIB) and continue there if any 00933 3. take the next closest MIB (not being related to the current MIB) 00934 */ 00935 const struct snmp_mib *next_mib; 00936 next_mib = snmp_get_next_mib(start_oid, start_oid_len); /* returns MIB's related to point 1 and 3 */ 00937 00938 /* is the found MIB an inner MIB? (point 1) */ 00939 if ((next_mib != NULL) && (next_mib->base_oid_len > mib->base_oid_len) && 00940 (snmp_oid_compare(next_mib->base_oid, mib->base_oid_len, mib->base_oid, mib->base_oid_len) == 0)) { 00941 /* yes it is -> continue at inner MIB */ 00942 mib = next_mib; 00943 start_oid = mib->base_oid; 00944 start_oid_len = mib->base_oid_len; 00945 } else { 00946 /* check if there is a surrounding mib where to continue (point 2) (only possible if OID length > 1) */ 00947 if (mib->base_oid_len > 1) { 00948 mib = snmp_get_mib_from_oid(mib->base_oid, mib->base_oid_len - 1); 00949 00950 if (mib == NULL) { 00951 /* no surrounding mib, use next mib encountered above (point 3) */ 00952 mib = next_mib; 00953 00954 if (mib != NULL) { 00955 start_oid = mib->base_oid; 00956 start_oid_len = mib->base_oid_len; 00957 } 00958 } 00959 /* else { start_oid stays the same because we want to continue from current offset in surrounding mib (point 2) } */ 00960 } 00961 } 00962 } 00963 } 00964 00965 if (mib == NULL) { 00966 /* loop is only left when mib == null (error) or mib_node != NULL (success) */ 00967 return SNMP_ERR_ENDOFMIBVIEW; 00968 } 00969 00970 return SNMP_ERR_NOERROR; 00971 } 00972 00973 /** 00974 * Searches tree for the supplied object identifier. 00975 * 00976 */ 00977 const struct snmp_node * 00978 snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len) 00979 { 00980 const struct snmp_node* const* node = &mib->root_node; 00981 u8_t oid_offset = mib->base_oid_len; 00982 00983 while ((oid_offset < oid_len) && ((*node)->node_type == SNMP_NODE_TREE)) { 00984 /* search for matching sub node */ 00985 u32_t subnode_oid = *(oid + oid_offset); 00986 00987 u32_t i = (*(const struct snmp_tree_node* const*)node)->subnode_count; 00988 node = (*(const struct snmp_tree_node* const*)node)->subnodes; 00989 while ((i > 0) && ((*node)->oid != subnode_oid)) { 00990 node++; 00991 i--; 00992 } 00993 00994 if (i == 0) { 00995 /* no matching subnode found */ 00996 return NULL; 00997 } 00998 00999 oid_offset++; 01000 } 01001 01002 if ((*node)->node_type != SNMP_NODE_TREE) { 01003 /* we found a leaf node */ 01004 *oid_instance_len = oid_len - oid_offset; 01005 return (*node); 01006 } 01007 01008 return NULL; 01009 } 01010 01011 const struct snmp_node* 01012 snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret) 01013 { 01014 u8_t oid_offset = mib->base_oid_len; 01015 const struct snmp_node* const* node; 01016 const struct snmp_tree_node* node_stack[SNMP_MAX_OBJ_ID_LEN]; 01017 s32_t nsi = 0; /* NodeStackIndex */ 01018 u32_t subnode_oid; 01019 01020 if (mib->root_node->node_type != SNMP_NODE_TREE) { 01021 /* a next operation on a mib with only a leaf node will always return NULL because there is no other node */ 01022 return NULL; 01023 } 01024 01025 /* first build node stack related to passed oid (as far as possible), then go backwards to determine the next node */ 01026 node_stack[nsi] = (const struct snmp_tree_node*)(const void*)mib->root_node; 01027 while (oid_offset < oid_len) { 01028 /* search for matching sub node */ 01029 u32_t i = node_stack[nsi]->subnode_count; 01030 node = node_stack[nsi]->subnodes; 01031 01032 subnode_oid = *(oid + oid_offset); 01033 01034 while ((i > 0) && ((*node)->oid != subnode_oid)) { 01035 node++; 01036 i--; 01037 } 01038 01039 if ((i == 0) || ((*node)->node_type != SNMP_NODE_TREE)) { 01040 /* no (matching) tree-subnode found */ 01041 break; 01042 } 01043 nsi++; 01044 node_stack[nsi] = (const struct snmp_tree_node*)(const void*)(*node); 01045 01046 oid_offset++; 01047 } 01048 01049 01050 if (oid_offset >= oid_len) { 01051 /* passed oid references a tree node -> return first useable sub node of it */ 01052 subnode_oid = 0; 01053 } else { 01054 subnode_oid = *(oid + oid_offset) + 1; 01055 } 01056 01057 while (nsi >= 0) { 01058 const struct snmp_node* subnode = NULL; 01059 01060 /* find next node on current level */ 01061 s32_t i = node_stack[nsi]->subnode_count; 01062 node = node_stack[nsi]->subnodes; 01063 while (i > 0) { 01064 if ((*node)->oid == subnode_oid) { 01065 subnode = *node; 01066 break; 01067 } else if (((*node)->oid > subnode_oid) && ((subnode == NULL) || ((*node)->oid < subnode->oid))) { 01068 subnode = *node; 01069 } 01070 01071 node++; 01072 i--; 01073 } 01074 01075 if (subnode == NULL) { 01076 /* no further node found on this level, go one level up and start searching with index of current node*/ 01077 subnode_oid = node_stack[nsi]->node.oid + 1; 01078 nsi--; 01079 } else { 01080 if (subnode->node_type == SNMP_NODE_TREE) { 01081 /* next is a tree node, go into it and start searching */ 01082 nsi++; 01083 node_stack[nsi] = (const struct snmp_tree_node*)(const void*)subnode; 01084 subnode_oid = 0; 01085 } else { 01086 /* we found a leaf node -> fill oidret and return it */ 01087 snmp_oid_assign(oidret, mib->base_oid, mib->base_oid_len); 01088 i = 1; 01089 while (i <= nsi) { 01090 oidret->id[oidret->len] = node_stack[i]->node.oid; 01091 oidret->len++; 01092 i++; 01093 } 01094 01095 oidret->id[oidret->len] = subnode->oid; 01096 oidret->len++; 01097 01098 return subnode; 01099 } 01100 } 01101 } 01102 01103 return NULL; 01104 } 01105 01106 /** initialize struct next_oid_state using this function before passing it to next_oid_check */ 01107 void 01108 snmp_next_oid_init(struct snmp_next_oid_state *state, 01109 const u32_t *start_oid, u8_t start_oid_len, 01110 u32_t *next_oid_buf, u8_t next_oid_max_len) 01111 { 01112 state->start_oid = start_oid; 01113 state->start_oid_len = start_oid_len; 01114 state->next_oid = next_oid_buf; 01115 state->next_oid_len = 0; 01116 state->next_oid_max_len = next_oid_max_len; 01117 state->status = SNMP_NEXT_OID_STATUS_NO_MATCH; 01118 } 01119 01120 /** checks if the passed incomplete OID may be a possible candidate for snmp_next_oid_check(); 01121 this methid is intended if the complete OID is not yet known but it is very expensive to build it up, 01122 so it is possible to test the starting part before building up the complete oid and pass it to snmp_next_oid_check()*/ 01123 u8_t 01124 snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len) 01125 { 01126 if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL) { 01127 u8_t start_oid_len = (oid_len < state->start_oid_len) ? oid_len : state->start_oid_len; 01128 01129 /* check passed OID is located behind start offset */ 01130 if (snmp_oid_compare(oid, oid_len, state->start_oid, start_oid_len) >= 0) { 01131 /* check if new oid is located closer to start oid than current closest oid */ 01132 if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) || 01133 (snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0)) { 01134 return 1; 01135 } 01136 } 01137 } 01138 01139 return 0; 01140 } 01141 01142 /** checks the passed OID if it is a candidate to be the next one (get_next); returns !=0 if passed oid is currently closest, otherwise 0 */ 01143 u8_t 01144 snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len, void* reference) 01145 { 01146 /* do not overwrite a fail result */ 01147 if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL) { 01148 /* check passed OID is located behind start offset */ 01149 if (snmp_oid_compare(oid, oid_len, state->start_oid, state->start_oid_len) > 0) { 01150 /* check if new oid is located closer to start oid than current closest oid */ 01151 if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) || 01152 (snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0)) { 01153 if (oid_len <= state->next_oid_max_len) { 01154 MEMCPY(state->next_oid, oid, oid_len * sizeof(u32_t)); 01155 state->next_oid_len = oid_len; 01156 state->status = SNMP_NEXT_OID_STATUS_SUCCESS; 01157 state->reference = reference; 01158 return 1; 01159 } else { 01160 state->status = SNMP_NEXT_OID_STATUS_BUF_TO_SMALL; 01161 } 01162 } 01163 } 01164 } 01165 01166 return 0; 01167 } 01168 01169 u8_t 01170 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) 01171 { 01172 u8_t i; 01173 01174 if (oid_len != oid_ranges_len) { 01175 return 0; 01176 } 01177 01178 for (i = 0; i < oid_ranges_len; i++) { 01179 if ((oid_in[i] < oid_ranges[i].min) || (oid_in[i] > oid_ranges[i].max)) { 01180 return 0; 01181 } 01182 } 01183 01184 return 1; 01185 } 01186 01187 snmp_err_t 01188 snmp_set_test_ok(struct snmp_node_instance* instance, u16_t value_len, void* value) 01189 { 01190 LWIP_UNUSED_ARG(instance); 01191 LWIP_UNUSED_ARG(value_len); 01192 LWIP_UNUSED_ARG(value); 01193 01194 return SNMP_ERR_NOERROR; 01195 } 01196 01197 /** 01198 * Decodes BITS pseudotype value from ASN.1 OctetString. 01199 * 01200 * @note Because BITS pseudo type is encoded as OCTET STRING, it cannot directly 01201 * be encoded/decoded by the agent. Instead call this function as required from 01202 * get/test/set methods. 01203 * 01204 * @param buf points to a buffer holding the ASN1 octet string 01205 * @param buf_len length of octet string 01206 * @param bit_value decoded Bit value with Bit0 == LSB 01207 * @return ERR_OK if successful, ERR_ARG if bit value contains more than 32 bit 01208 */ 01209 err_t 01210 snmp_decode_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value) 01211 { 01212 u8_t b; 01213 u8_t bits_processed = 0; 01214 *bit_value = 0; 01215 01216 while (buf_len > 0) { 01217 /* any bit set in this byte? */ 01218 if (*buf != 0x00) { 01219 if (bits_processed >= 32) { 01220 /* accept more than 4 bytes, but only when no bits are set */ 01221 return ERR_VAL; 01222 } 01223 01224 b = *buf; 01225 do { 01226 if (b & 0x80) { 01227 *bit_value |= (1 << bits_processed); 01228 } 01229 bits_processed++; 01230 b <<= 1; 01231 } 01232 while ((bits_processed & 0x07) != 0); /* &0x07 -> % 8 */ 01233 } else { 01234 bits_processed += 8; 01235 } 01236 01237 buf_len--; 01238 buf++; 01239 } 01240 01241 return ERR_OK; 01242 } 01243 01244 err_t 01245 snmp_decode_truthvalue(const s32_t *asn1_value, u8_t *bool_value) 01246 { 01247 /* defined by RFC1443: 01248 TruthValue ::= TEXTUAL-CONVENTION 01249 STATUS current 01250 DESCRIPTION 01251 "Represents a boolean value." 01252 SYNTAX INTEGER { true(1), false(2) } 01253 */ 01254 01255 if ((asn1_value == NULL) || (bool_value == NULL)) { 01256 return ERR_ARG; 01257 } 01258 01259 if (*asn1_value == 1) { 01260 *bool_value = 1; 01261 } else if (*asn1_value == 2) { 01262 *bool_value = 0; 01263 } else { 01264 return ERR_VAL; 01265 } 01266 01267 return ERR_OK; 01268 } 01269 01270 /** 01271 * Encodes BITS pseudotype value into ASN.1 OctetString. 01272 * 01273 * @note Because BITS pseudo type is encoded as OCTET STRING, it cannot directly 01274 * be encoded/decoded by the agent. Instead call this function as required from 01275 * get/test/set methods. 01276 * 01277 * @param buf points to a buffer where the resulting ASN1 octet string is stored to 01278 * @param buf_len max length of the bufffer 01279 * @param bit_value Bit value to encode with Bit0 == LSB 01280 * @param bit_count Number of possible bits for the bit value (according to rfc we have to send all bits independant from their truth value) 01281 * @return number of bytes used from buffer to store the resulting OctetString 01282 */ 01283 u8_t 01284 snmp_encode_bits(u8_t *buf, u32_t buf_len, u32_t bit_value, u8_t bit_count) 01285 { 01286 u8_t len = 0; 01287 u8_t min_bytes = (bit_count + 7) >> 3; /* >>3 -> / 8 */ 01288 01289 while ((buf_len > 0) && (bit_value != 0x00)) { 01290 s8_t i = 7; 01291 *buf = 0x00; 01292 while (i >= 0) { 01293 if (bit_value & 0x01) { 01294 *buf |= 0x01; 01295 } 01296 01297 if (i > 0) { 01298 *buf <<= 1; 01299 } 01300 01301 bit_value >>= 1; 01302 i--; 01303 } 01304 01305 buf++; 01306 buf_len--; 01307 len++; 01308 } 01309 01310 if (len < min_bytes) { 01311 buf += len; 01312 buf_len -= len; 01313 01314 while ((len < min_bytes) && (buf_len > 0)) { 01315 *buf = 0x00; 01316 buf++; 01317 buf_len--; 01318 len++; 01319 } 01320 } 01321 01322 return len; 01323 } 01324 01325 u8_t 01326 snmp_encode_truthvalue(s32_t *asn1_value, u32_t bool_value) 01327 { 01328 /* defined by RFC1443: 01329 TruthValue ::= TEXTUAL-CONVENTION 01330 STATUS current 01331 DESCRIPTION 01332 "Represents a boolean value." 01333 SYNTAX INTEGER { true(1), false(2) } 01334 */ 01335 01336 if (asn1_value == NULL) { 01337 return 0; 01338 } 01339 01340 if (bool_value) { 01341 *asn1_value = 1; /* defined by RFC1443 */ 01342 } else { 01343 *asn1_value = 2; /* defined by RFC1443 */ 01344 } 01345 01346 return sizeof(s32_t); 01347 } 01348 01349 #endif /* LWIP_SNMP */
Generated on Tue Jul 12 2022 12:22:02 by
