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