SNMP agent rewrite

- SNMPv2c support
  - Greatly reduced RAM usage, no memory pools any more
  - API cleanup
  - MIB2 is separated from SNMP stack
  - Support for multiple MIBs (snmp_set_mibs call) - e.g. for private MIB
  - Improved MIB2 implementation (tcpConnTable etc.)
  - Redesigned simple and generic API for MIB implementation
  - Comfortable node types for scalar arrays and tables
  - Counter64, bit and truthvalue datatype support
  - Callbacks for SNMP writes
  - Runs on two APIs: RAW and netconn
  - Async API is gone - the stack now supports netconn API instead,
    so blocking operations can be done in MIB calls.
    SNMP runs in a worker thread when netconn API is used.
  - Simplified thread sync support for MIBs - useful when MIBs
    need to access variables shared with other threads without locking
    (used in MIB2 to access lwIP stats from lwIP thread)

Currently in work:
  - Traps rewrite
  - MIB compiler
This commit is contained in:
Dirk Ziegelmeier 2015-12-26 11:43:29 +01:00
parent 0178d1d2ee
commit 7b946fa9b1
32 changed files with 8034 additions and 8176 deletions

View File

@ -118,13 +118,18 @@ LWIPNOAPPSFILES=$(COREFILES) \
$(NETIFFILES) \
$(PPPFILES)
# SNMPFILES: SNMPv1 agent
SNMPFILES=$(LWIPDIR)/apps/snmp/asn1_dec.c \
$(LWIPDIR)/apps/snmp/asn1_enc.c \
$(LWIPDIR)/apps/snmp/mib2.c \
$(LWIPDIR)/apps/snmp/mib_structs.c \
$(LWIPDIR)/apps/snmp/msg_in.c \
$(LWIPDIR)/apps/snmp/msg_out.c
# SNMPFILES: SNMPv2c agent
SNMPFILES=$(LWIPDIR)/apps/snmp/snmp_asn1.c \
$(LWIPDIR)/apps/snmp/snmp_core.c \
$(LWIPDIR)/apps/snmp/snmp_mib2.c \
$(LWIPDIR)/apps/snmp/snmp_msg.c \
$(LWIPDIR)/apps/snmp/snmp_netconn.c \
$(LWIPDIR)/apps/snmp/snmp_pbuf_stream.c \
$(LWIPDIR)/apps/snmp/snmp_raw.c \
$(LWIPDIR)/apps/snmp/snmp_scalar.c \
$(LWIPDIR)/apps/snmp/snmp_table.c \
$(LWIPDIR)/apps/snmp/snmp_threadsync.c \
$(LWIPDIR)/apps/snmp/snmp_traps.c
# HTTPDFILES: HTTP server
HTTPDFILES=$(LWIPDIR)/apps/httpd/fs.c \

30
src/apps/snmp/README Normal file
View File

@ -0,0 +1,30 @@
lwIP SNMPv2c agent
==================
Based on SNMP stack written by Christiaan Simons <christiaan.simons@axon.tv>
Rewritten by Martin Hentschel <info@cl-soft.de> and
Dirk Ziegelmeier <dziegel@gmx.de>
Changes:
- SNMPv2c support
- Greatly reduced RAM usage, no memory pools any more
- API cleanup
- MIB2 is separated from SNMP stack
- Support for multiple MIBs (snmp_set_mibs call) - e.g. for private MIB
- Improved MIB2 implementation (tcpConnTable etc.)
- Redesigned simple and generic API for MIB implementation
- Comfortable node types for scalar arrays and tables
- Counter64, bit and truthvalue datatype support
- Callbacks for SNMP writes
- Runs on two APIs: RAW and netconn
- Async API is gone - the stack now supports netconn API instead,
so blocking operations can be done in MIB calls.
SNMP runs in a worker thread when netconn API is used.
- Simplified thread sync support for MIBs - useful when MIBs
need to access variables shared with other threads without locking
(used in MIB2 to access lwIP stats from lwIP thread)
Currently in work:
- Traps rewrite
- MIB compiler

View File

@ -1,614 +0,0 @@
/**
* @file
* Abstract Syntax Notation One (ISO 8824, 8825) decoding
*
* @todo not optimised (yet), favor correctness over speed, favor speed over size
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_asn1.h"
/**
* Retrieves type field from incoming pbuf chain.
*
* @param p points to a pbuf holding an ASN1 coded type field
* @param ofs points to the offset within the pbuf chain of the ASN1 coded type field
* @param type return ASN1 type
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
*type = *msg_ptr;
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Decodes length field from incoming pbuf chain into host length.
*
* @param p points to a pbuf holding an ASN1 coded length
* @param ofs points to the offset within the pbuf chain of the ASN1 coded length
* @param octets_used returns number of octets used by the length code
* @param length return host order length, up to 64k
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (*msg_ptr < 0x80) {
/* primitive definite length format */
*octets_used = 1;
*length = *msg_ptr;
return ERR_OK;
} else if (*msg_ptr == 0x80) {
/* constructed indefinite length format, termination with two zero octets */
u8_t zeros;
u8_t i;
*length = 0;
zeros = 0;
while (zeros != 2) {
i = 2;
while (i > 0) {
i--;
(*length) += 1;
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
if (*msg_ptr == 0) {
zeros++;
if (zeros == 2) {
/* stop while (i > 0) */
i = 0;
}
} else {
zeros = 0;
}
}
}
*octets_used = 1;
return ERR_OK;
} else if (*msg_ptr == 0x81) {
/* constructed definite length format, one octet */
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
*length = *msg_ptr;
*octets_used = 2;
return ERR_OK;
} else if (*msg_ptr == 0x82) {
u8_t i;
/* constructed definite length format, two octets */
i = 2;
while (i > 0) {
i--;
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
if (i == 0) {
/* least significant length octet */
*length |= *msg_ptr;
} else {
/* most significant length octet */
*length = (*msg_ptr) << 8;
}
}
*octets_used = 3;
return ERR_OK;
} else {
/* constructed definite length format 3..127 octets, this is too big (>64k) */
/** @todo: do we need to accept inefficient codings with many leading zero's? */
*octets_used = 1 + ((*msg_ptr) & 0x7f);
return ERR_ARG;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Decodes positive integer (counter, gauge, timeticks) into u32_t.
*
* @param p points to a pbuf holding an ASN1 coded integer
* @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
err_t
snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if ((len > 0) && (len < 6)) {
/* start from zero */
*value = 0;
if (*msg_ptr & 0x80) {
/* negative, expecting zero sign bit! */
return ERR_ARG;
} else {
/* positive */
if ((len > 1) && (*msg_ptr == 0)) {
/* skip leading "sign byte" octet 0x00 */
len--;
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
}
/* OR octets with value */
while (len > 1) {
len--;
*value |= *msg_ptr;
*value <<= 8;
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
*value |= *msg_ptr;
return ERR_OK;
} else {
return ERR_ARG;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Decodes integer into s32_t.
*
* @param p points to a pbuf holding an ASN1 coded integer
* @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed!
*/
err_t
snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
{
u16_t plen, base;
u8_t *msg_ptr;
#if BYTE_ORDER == LITTLE_ENDIAN
u8_t *lsb_ptr = (u8_t*)value;
#endif
#if BYTE_ORDER == BIG_ENDIAN
u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
#endif
u8_t sign;
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if ((len > 0) && (len < 5)) {
if (*msg_ptr & 0x80) {
/* negative, start from -1 */
*value = -1;
sign = 1;
} else {
/* positive, start from 0 */
*value = 0;
sign = 0;
}
/* OR/AND octets with value */
while (len > 1) {
len--;
if (sign) {
*lsb_ptr &= *msg_ptr;
*value <<= 8;
*lsb_ptr |= 255;
} else {
*lsb_ptr |= *msg_ptr;
*value <<= 8;
}
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
if (sign) {
*lsb_ptr &= *msg_ptr;
} else {
*lsb_ptr |= *msg_ptr;
}
return ERR_OK;
} else {
return ERR_ARG;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Decodes object identifier from incoming message into array of s32_t.
*
* @param p points to a pbuf holding an ASN1 coded object identifier
* @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier
* @param len length of the coded object identifier
* @param oid return object identifier struct
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
{
u16_t plen, base;
u8_t *msg_ptr;
s32_t *oid_ptr;
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
oid->len = 0;
oid_ptr = &oid->id[0];
if (len > 0) {
/* first compressed octet */
if (*msg_ptr == 0x2B) {
/* (most) common case 1.3 (iso.org) */
*oid_ptr = 1;
oid_ptr++;
*oid_ptr = 3;
oid_ptr++;
} else if (*msg_ptr < 40) {
*oid_ptr = 0;
oid_ptr++;
*oid_ptr = *msg_ptr;
oid_ptr++;
} else if (*msg_ptr < 80) {
*oid_ptr = 1;
oid_ptr++;
*oid_ptr = (*msg_ptr) - 40;
oid_ptr++;
} else {
*oid_ptr = 2;
oid_ptr++;
*oid_ptr = (*msg_ptr) - 80;
oid_ptr++;
}
oid->len = 2;
} else {
/* accepting zero length identifiers e.g. for
getnext operation. uncommon but valid */
return ERR_OK;
}
len--;
if (len > 0) {
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN)) {
/* sub-identifier uses multiple octets */
if (*msg_ptr & 0x80) {
s32_t sub_id = 0;
while ((*msg_ptr & 0x80) && (len > 1)) {
len--;
sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
if (!(*msg_ptr & 0x80) && (len > 0)) {
/* last octet sub-identifier */
len--;
sub_id = (sub_id << 7) + *msg_ptr;
*oid_ptr = sub_id;
}
} else {
/* !(*msg_ptr & 0x80) sub-identifier uses single octet */
len--;
*oid_ptr = *msg_ptr;
}
if (len > 0) {
/* remaining oid bytes available ... */
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
oid_ptr++;
oid->len++;
}
if (len == 0) {
/* len == 0, end of oid */
return ERR_OK;
} else {
/* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */
return ERR_ARG;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
* from incoming message into array.
*
* @param p points to a pbuf holding an ASN1 coded raw data
* @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data
* @param len length of the coded raw data (zero is valid, e.g. empty string!)
* @param raw_len length of the raw return value
* @param raw return raw bytes
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)
{
u16_t plen, base;
u8_t *msg_ptr;
if (len > 0) {
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (raw_len >= len) {
while (len > 1) {
/* copy len - 1 octets */
len--;
*raw = *msg_ptr;
raw++;
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
/* copy last octet */
*raw = *msg_ptr;
return ERR_OK;
} else {
/* raw_len < len, not enough dst space */
return ERR_ARG;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
} else {
/* len == 0, empty string */
return ERR_OK;
}
}
/**
* Decodes BITS pseudotype value from ASN.1 OctetString.
*
* @note Because BITS pseudo type is encoded as OCTET STRING, it cannot directly
* be encoded/decoded by the agent. Instead call this function as required from
* get/test/set methods.
*
* @param buf points to a buffer holding the ASN1 octet string
* @param buf_len length of octet string
* @param bit_value decoded Bit value with Bit0 == LSB
* @return ERR_OK if successful, ERR_ARG if bit value contains more than 32 bit
*/
err_t
snmp_asn1_dec_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value)
{
u8_t b;
u8_t bits_processed = 0;
*bit_value = 0;
while (buf_len > 0) {
/* any bit set in this byte? */
if (*buf != 0x00) {
if (bits_processed >= 32) {
/* accept more than 4 bytes, but only when no bits are set */
return ERR_ARG;
}
b = *buf;
do {
if (b & 0x80) {
*bit_value |= (1 << bits_processed);
}
bits_processed++;
b <<= 1;
}
while ((bits_processed % 8) != 0);
} else {
bits_processed += 8;
}
buf_len--;
buf++;
}
return ERR_OK;
}
#endif /* LWIP_SNMP */

View File

@ -1,580 +0,0 @@
/**
* @file
* Abstract Syntax Notation One (ISO 8824, 8825) encoding
*
* @todo not optimised (yet), favor correctness over speed, favor speed over size
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_asn1.h"
/**
* Returns octet count for length.
*
* @param length
* @param octets_needed points to the return value
*/
void
snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
{
if (length < 0x80U) {
*octets_needed = 1;
} else if (length < 0x100U) {
*octets_needed = 2;
} else {
*octets_needed = 3;
}
}
/**
* Returns octet count for an u32_t.
*
* @param value
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
void
snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
{
if (value < 0x80UL) {
*octets_needed = 1;
} else if (value < 0x8000UL) {
*octets_needed = 2;
} else if (value < 0x800000UL) {
*octets_needed = 3;
} else if (value < 0x80000000UL) {
*octets_needed = 4;
} else {
*octets_needed = 5;
}
}
/**
* Returns octet count for an s32_t.
*
* @param value
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed.
*/
void
snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
{
if (value < 0) {
value = ~value;
} if (value < 0x80L) {
*octets_needed = 1;
} else if (value < 0x8000L) {
*octets_needed = 2;
} else if (value < 0x800000L) {
*octets_needed = 3;
} else {
*octets_needed = 4;
}
}
/**
* Returns octet count for an object identifier.
*
* @param ident_len object identifier array length
* @param ident points to object identifier array
* @param octets_needed points to the return value
*/
void
snmp_asn1_enc_oid_cnt(u16_t ident_len, const s32_t *ident, u16_t *octets_needed)
{
s32_t sub_id;
u8_t cnt;
cnt = 0;
if (ident_len > 1) {
/* compressed prefix in one octet */
cnt++;
ident_len -= 2;
ident += 2;
}
while (ident_len > 0) {
ident_len--;
sub_id = *ident;
sub_id >>= 7;
cnt++;
while (sub_id > 0) {
sub_id >>= 7;
cnt++;
}
ident++;
}
*octets_needed = cnt;
}
/**
* Encodes ASN type field into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode value into
* @param ofs points to the offset within the pbuf chain
* @param type input ASN1 type
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
*msg_ptr = type;
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Encodes host order length field into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode length into
* @param ofs points to the offset within the pbuf chain
* @param length is the host order length to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (length < 0x80) {
*msg_ptr = (u8_t)length;
return ERR_OK;
} else if (length < 0x100) {
*msg_ptr = 0x81;
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
*msg_ptr = (u8_t)length;
return ERR_OK;
} else {
u8_t i;
/* length >= 0x100 && length <= 0xFFFF */
*msg_ptr = 0x82;
i = 2;
while (i > 0) {
i--;
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
if (i == 0) {
/* least significant length octet */
*msg_ptr = (u8_t)length;
} else {
/* most significant length octet */
*msg_ptr = (u8_t)(length >> 8);
}
}
return ERR_OK;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode value into
* @param ofs points to the offset within the pbuf chain
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
* @param value is the host order u32_t value to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_u32t_cnt()
*/
err_t
snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (octets_needed == 5) {
/* not enough bits in 'value' add leading 0x00 */
octets_needed--;
*msg_ptr = 0x00;
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
while (octets_needed > 1) {
octets_needed--;
*msg_ptr = (u8_t)(value >> (octets_needed << 3));
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
/* (only) one least significant octet */
*msg_ptr = (u8_t)value;
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Encodes s32_t integer into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode value into
* @param ofs points to the offset within the pbuf chain
* @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
* @param value is the host order s32_t value to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_s32t_cnt()
*/
err_t
snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
while (octets_needed > 1) {
octets_needed--;
*msg_ptr = (u8_t)(value >> (octets_needed << 3));
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
/* (only) one least significant octet */
*msg_ptr = (u8_t)value;
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Encodes object identifier into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode oid into
* @param ofs points to the offset within the pbuf chain
* @param ident_len object identifier array length
* @param ident points to object identifier array
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u16_t ident_len, const s32_t *ident)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (ident_len > 1) {
if ((ident[0] == 1) && (ident[1] == 3)) {
/* compressed (most common) prefix .iso.org */
*msg_ptr = 0x2b;
} else {
/* calculate prefix */
*msg_ptr = (u8_t)((ident[0] * 40) + ident[1]);
}
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
ident_len -= 2;
ident += 2;
} else {
/* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
/* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
return ERR_ARG;
}
while (ident_len > 0) {
s32_t sub_id;
u8_t shift, tail;
ident_len--;
sub_id = *ident;
tail = 0;
shift = 28;
while (shift > 0) {
u8_t code;
code = (u8_t)(sub_id >> shift);
if ((code != 0) || (tail != 0)) {
tail = 1;
*msg_ptr = code | 0x80;
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
shift -= 7;
}
*msg_ptr = (u8_t)sub_id & 0x7F;
if (ident_len > 0) {
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
/* proceed to next sub-identifier */
ident++;
}
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode raw data into
* @param ofs points to the offset within the pbuf chain
* @param raw_len raw data length
* @param raw points raw data
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, const u8_t *raw)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL) {
base = plen;
plen += p->len;
if (ofs < plen) {
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
while (raw_len > 1) {
/* copy raw_len - 1 octets */
raw_len--;
*msg_ptr = *raw;
raw++;
ofs += 1;
if (ofs >= plen) {
/* next octet in next pbuf */
p = p->next;
if (p == NULL) {
return ERR_ARG;
}
msg_ptr = (u8_t*)p->payload;
plen += p->len;
} else {
/* next octet in same pbuf */
msg_ptr++;
}
}
if (raw_len > 0) {
/* copy last or single octet */
*msg_ptr = *raw;
}
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Encodes BITS pseudotype value into ASN.1 OctetString.
*
* @note Because BITS pseudo type is encoded as OCTET STRING, it cannot directly
* be encoded/decoded by the agent. Instead call this function as required from
* get/test/set methods.
*
* @param buf points to a buffer where the resulting ASN1 octet string is stored to
* @param buf_len max length of the bufffer
* @param bit_value Bit value to encode with Bit0 == LSB
* @return number of bytes used from buffer to store the resulting OctetString
*/
u8_t
snmp_asn1_enc_bits(u8_t *buf, u32_t buf_len, u32_t bit_value)
{
int i = 0;
u8_t len = 0;
u8_t *buf_ptr = (u8_t *)buf;
while ((buf_len > 0) && (bit_value != 0x00)) {
*buf_ptr = 0x00;
i = 8;
while (i > 0) {
if (bit_value & 0x01) {
*buf_ptr |= 0x01;
}
bit_value >>= 1;
*buf_ptr <<= 1;
i--;
}
buf_ptr++;
buf_len--;
len++;
}
return len;
}
#endif /* LWIP_SNMP */

File diff suppressed because it is too large Load Diff

View File

@ -1,994 +0,0 @@
/**
* @file
* MIB tree access/construction functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_structs.h"
#include "lwip/memp.h"
#include "lwip/netif.h"
LWIP_MEMPOOL_DECLARE(SNMP_ROOTNODE, SNMP_NUM_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE")
LWIP_MEMPOOL_DECLARE(SNMP_NODE, SNMP_NUM_NODE, sizeof(struct mib_list_node), "SNMP_NODE")
/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */
const s32_t prefix[4] = {1, 3, 6, 1};
#define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN)
/** node stack entry (old news?) */
struct nse
{
/** right child */
const struct mib_node* r_ptr;
/** right child identifier */
s32_t r_id;
/** right child next level */
u8_t r_nl;
};
static u8_t node_stack_cnt;
static struct nse node_stack[NODE_STACK_SIZE];
const struct nse node_null = {NULL, 0, 0};
/**
* Pushes nse struct onto stack.
*/
static void
push_node(const struct nse* node)
{
LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE);
LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(const void*)(node->r_ptr),node->r_id));
if (node_stack_cnt < NODE_STACK_SIZE) {
node_stack[node_stack_cnt] = *node;
node_stack_cnt++;
}
}
/**
* Pops nse struct from stack.
*/
static void
pop_node(struct nse* node)
{
if (node_stack_cnt > 0) {
node_stack_cnt--;
*node = node_stack[node_stack_cnt];
}
LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(const void *)(node->r_ptr),node->r_id));
}
/**
* Conversion from ifIndex to lwIP netif
* @param ifindex is a s32_t object sub-identifier
* @param netif points to returned netif struct pointer
*/
void
snmp_ifindextonetif(s32_t ifindex, struct netif **netif)
{
struct netif *nif = netif_list;
s32_t i, ifidx;
ifidx = ifindex - 1;
i = 0;
while ((nif != NULL) && (i < ifidx)) {
nif = nif->next;
i++;
}
*netif = nif;
}
/**
* Conversion from lwIP netif to ifIndex
* @param netif points to a netif struct
* @param ifidx points to s32_t object sub-identifier
*/
void
snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)
{
struct netif *nif = netif_list;
u16_t i;
i = 0;
while ((nif != NULL) && (nif != netif)) {
nif = nif->next;
i++;
}
*ifidx = i+1;
}
/**
* Conversion from oid to lwIP ip_addr
* @param ident points to s32_t ident[4] input
* @param ip points to output struct
*/
void
snmp_oidtoip(s32_t *ident, ip4_addr_t *ip)
{
IP4_ADDR(ip, ident[0], ident[1], ident[2], ident[3]);
}
/**
* Conversion from lwIP ip_addr to oid
* @param ip points to input struct
* @param ident points to s32_t ident[4] output
*/
void
snmp_iptooid(const ip4_addr_t *ip, s32_t *ident)
{
ident[0] = ip4_addr1(ip);
ident[1] = ip4_addr2(ip);
ident[2] = ip4_addr3(ip);
ident[3] = ip4_addr4(ip);
}
struct mib_list_node *
snmp_mib_ln_alloc(s32_t id)
{
struct mib_list_node *ln;
ln = (struct mib_list_node *)LWIP_MEMPOOL_ALLOC(SNMP_NODE);
if (ln != NULL) {
ln->prev = NULL;
ln->next = NULL;
ln->objid = id;
ln->nptr = NULL;
}
return ln;
}
void
snmp_mib_ln_free(struct mib_list_node *ln)
{
LWIP_MEMPOOL_FREE(SNMP_NODE, ln);
}
struct mib_list_rootnode *
snmp_mib_lrn_alloc(void)
{
struct mib_list_rootnode *lrn;
lrn = (struct mib_list_rootnode*)LWIP_MEMPOOL_ALLOC(SNMP_ROOTNODE);
if (lrn != NULL) {
lrn->scalar.get_object_def = noleafs_get_object_def;
lrn->scalar.get_value = noleafs_get_value;
lrn->scalar.set_test = noleafs_set_test;
lrn->scalar.set_value = noleafs_set_value;
lrn->scalar.node.node_type = MIB_NODE_LR;
lrn->head = NULL;
lrn->tail = NULL;
lrn->count = 0;
}
return lrn;
}
void
snmp_mib_lrn_free(struct mib_list_rootnode *lrn)
{
LWIP_MEMPOOL_FREE(SNMP_ROOTNODE, lrn);
}
/**
* Inserts node in idx list in a sorted
* (ascending order) fashion and
* allocates the node if needed.
*
* @param rn points to the root node
* @param objid is the object sub identifier
* @param insn points to a pointer to the inserted node
* used for constructing the tree.
* @return -1 if failed, 1 if inserted, 2 if present.
*/
s8_t
snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn)
{
struct mib_list_node *nn;
s8_t insert;
LWIP_ASSERT("rn != NULL",rn != NULL);
/* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */
insert = 0;
if (rn->head == NULL) {
/* empty list, add first node */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid));
nn = snmp_mib_ln_alloc(objid);
if (nn != NULL) {
rn->head = nn;
rn->tail = nn;
*insn = nn;
insert = 1;
} else {
insert = -1;
}
} else {
struct mib_list_node *n;
/* at least one node is present */
n = rn->head;
while ((n != NULL) && (insert == 0)) {
if (n->objid == objid) {
/* node is already there */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid));
*insn = n;
insert = 2;
} else if (n->objid < objid) {
if (n->next == NULL) {
/* alloc and insert at the tail */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid));
nn = snmp_mib_ln_alloc(objid);
if (nn != NULL) {
nn->next = NULL;
nn->prev = n;
n->next = nn;
rn->tail = nn;
*insn = nn;
insert = 1;
} else {
/* insertion failure */
insert = -1;
}
} else {
/* there's more to explore: traverse list */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n"));
n = n->next;
}
} else {
/* n->objid > objid */
/* alloc and insert between n->prev and n */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid));
nn = snmp_mib_ln_alloc(objid);
if (nn != NULL) {
if (n->prev == NULL) {
/* insert at the head */
nn->next = n;
nn->prev = NULL;
rn->head = nn;
n->prev = nn;
} else {
/* insert in the middle */
nn->next = n;
nn->prev = n->prev;
n->prev->next = nn;
n->prev = nn;
}
*insn = nn;
insert = 1;
} else {
/* insertion failure */
insert = -1;
}
}
}
}
if (insert == 1) {
rn->count += 1;
}
LWIP_ASSERT("insert != 0",insert != 0);
return insert;
}
/**
* Finds node in idx list and returns deletion mark.
*
* @param rn points to the root node
* @param objid is the object sub identifier
* @param fn returns pointer to found node
* @return 0 if not found, 1 if deletable,
* 2 can't delete (2 or more children), 3 not a list_node
*/
s8_t
snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn)
{
s8_t fc;
struct mib_list_node *n;
LWIP_ASSERT("rn != NULL",rn != NULL);
n = rn->head;
while ((n != NULL) && (n->objid != objid)) {
n = n->next;
}
if (n == NULL) {
fc = 0;
} else if (n->nptr == NULL) {
/* leaf, can delete node */
fc = 1;
} else {
struct mib_list_rootnode *r;
if (n->nptr->node_type == MIB_NODE_LR) {
r = (struct mib_list_rootnode*)(void*)n->nptr;
if (r->count > 1) {
/* can't delete node */
fc = 2;
} else {
/* count <= 1, can delete node */
fc = 1;
}
} else {
/* other node type */
fc = 3;
}
}
*fn = n;
return fc;
}
/**
* Removes node from idx list
* if it has a single child left.
*
* @param rn points to the root node
* @param n points to the node to delete
* @return the nptr to be freed by caller
*/
struct mib_list_rootnode *
snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n)
{
struct mib_list_rootnode *next;
LWIP_ASSERT("rn != NULL",rn != NULL);
LWIP_ASSERT("n != NULL",n != NULL);
/* caller must remove this sub-tree */
next = (struct mib_list_rootnode*)(void*)n->nptr;
rn->count -= 1;
if (n == rn->head) {
rn->head = n->next;
if (n->next != NULL) {
/* not last node, new list begin */
n->next->prev = NULL;
}
} else if (n == rn->tail) {
rn->tail = n->prev;
if (n->prev != NULL) {
/* not last node, new list end */
n->prev->next = NULL;
}
} else {
/* node must be in the middle */
n->prev->next = n->next;
n->next->prev = n->prev;
}
LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid));
snmp_mib_ln_free(n);
if (rn->count == 0) {
rn->head = NULL;
rn->tail = NULL;
}
return next;
}
/**
* Searches tree for the supplied (scalar?) object identifier.
*
* @param node points to the root of the tree ('.internet')
* @param ident_len the length of the supplied object identifier
* @param ident points to the array of sub identifiers
* @param np points to the found object instance (return)
* @return pointer to the requested parent (!) node if success, NULL otherwise
*/
const struct mib_node *
snmp_search_tree(const struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np)
{
u8_t node_type, ext_level;
ext_level = 0;
LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(const void*)node,*ident));
while (node != NULL) {
node_type = node->node_type;
if (node_type == MIB_NODE_AR) {
const struct mib_array_node *an;
u16_t i;
if (ident_len > 0) {
/* array node (internal ROM or RAM, fixed length) */
an = (const struct mib_array_node*)(const void*)node;
i = 0;
while ((i < an->maxlength) && (an->entries[i].objid != *ident)) {
i++;
}
if (i < an->maxlength) {
/* found it, if available proceed to child, otherwise inspect leaf */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->entries[i].objid,*ident));
if (an->entries[i].nptr == NULL) {
/* a scalar leaf OR table,
inspect remaining instance number / table index */
np->ident_len = ident_len;
np->ident = ident;
return &an->node;
} else {
/* follow next child pointer */
ident++;
ident_len--;
node = an->entries[i].nptr;
}
} else {
/* search failed, identifier mismatch (nosuchname) */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident));
return NULL;
}
} else {
/* search failed, short object identifier (nosuchname) */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n"));
return NULL;
}
} else if (node_type == MIB_NODE_LR) {
const struct mib_list_rootnode *lrn;
struct mib_list_node *ln;
if (ident_len > 0) {
/* list root node (internal 'RAM', variable length) */
lrn = (const struct mib_list_rootnode*)(const void*)node;
ln = lrn->head;
/* iterate over list, head to tail */
while ((ln != NULL) && (ln->objid != *ident)) {
ln = ln->next;
}
if (ln != NULL) {
/* found it, proceed to child */;
LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));
if (ln->nptr == NULL) {
np->ident_len = ident_len;
np->ident = ident;
return &lrn->scalar.node;
} else {
/* follow next child pointer */
ident_len--;
ident++;
node = ln->nptr;
}
} else {
/* search failed */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident));
return NULL;
}
} else {
/* search failed, short object identifier (nosuchname) */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n"));
return NULL;
}
} else if (node_type == MIB_NODE_EX) {
const struct mib_external_node *en;
u16_t i, len;
if (ident_len > 0) {
/* external node (addressing and access via functions) */
en = (const struct mib_external_node*)(const void*)node;
i = 0;
len = en->level_length(en->addr_inf,ext_level);
while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0)) {
i++;
}
if (i < len) {
s32_t debug_id;
en->get_objid(en->addr_inf,ext_level,i,&debug_id);
LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident));
if ((ext_level + 1) == en->tree_levels) {
np->ident_len = ident_len;
np->ident = ident;
return &en->node;
} else {
/* found it, proceed to child */
ident_len--;
ident++;
ext_level++;
}
} else {
/* search failed */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident));
return NULL;
}
} else {
/* search failed, short object identifier (nosuchname) */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n"));
return NULL;
}
} else if (node_type == MIB_NODE_SC) {
/* scalar node */
if ((ident_len == 1) && (*ident == 0)) {
np->ident_len = ident_len;
np->ident = ident;
return node;
} else {
/* search failed, short object identifier (nosuchname) */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n"));
return NULL;
}
} else {
/* unknown node_type */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type));
return NULL;
}
}
/* done, found nothing */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(const void*)node));
return NULL;
}
/**
* Test table for presence of at least one table entry.
*/
static u8_t
empty_table(const struct mib_node *node)
{
u8_t node_type;
u8_t empty = 0;
if (node != NULL) {
node_type = node->node_type;
if (node_type == MIB_NODE_LR) {
const struct mib_list_rootnode *lrn;
lrn = (const struct mib_list_rootnode*)(const void*)node;
if ((lrn->count == 0) || (lrn->head == NULL)) {
empty = 1;
}
} else if (node_type == MIB_NODE_AR) {
const struct mib_array_node *an;
an = (const struct mib_array_node*)(const void*)node;
if ((an->maxlength == 0) || (an->entries == NULL)) {
empty = 1;
}
} else if (node_type == MIB_NODE_EX) {
const struct mib_external_node *en;
en = (const struct mib_external_node*)(const void*)node;
if (en->tree_levels == 0) {
empty = 1;
}
}
}
return empty;
}
/**
* Tree expansion.
*/
const struct mib_node *
snmp_expand_tree(const struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)
{
u8_t node_type, ext_level, climb_tree;
ext_level = 0;
/* reset node stack */
node_stack_cnt = 0;
while (node != NULL) {
climb_tree = 0;
node_type = node->node_type;
if (node_type == MIB_NODE_AR) {
const struct mib_array_node *an;
u16_t i;
/* array node (internal ROM or RAM, fixed length) */
an = (const struct mib_array_node*)(const void*)node;
if (ident_len > 0) {
i = 0;
while ((i < an->maxlength) && (an->entries[i].objid < *ident)) {
i++;
}
if (i < an->maxlength) {
LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->entries[i].objid,*ident));
/* add identifier to oidret */
oidret->id[oidret->len] = an->entries[i].objid;
(oidret->len)++;
if (an->entries[i].nptr == NULL) {
LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));
/* leaf node (e.g. in a fixed size table) */
if (an->entries[i].objid > *ident) {
return &an->node;
} else if ((i + 1) < an->maxlength) {
/* an->entries[i].objid == *ident */
(oidret->len)--;
oidret->id[oidret->len] = an->entries[i + 1].objid;
(oidret->len)++;
return &an->node;
} else {
/* (i + 1) == an->maxlength */
(oidret->len)--;
climb_tree = 1;
}
} else {
u16_t j;
LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
/* non-leaf, store right child ptr and id */
LWIP_ASSERT("i < 0xff", i < 0xff);
j = i + 1;
while ((j < an->maxlength) && (empty_table(an->entries[j].nptr))) {
j++;
}
if (j < an->maxlength) {
struct nse cur_node;
cur_node.r_ptr = an->entries[j].nptr;
cur_node.r_id = an->entries[j].objid;
cur_node.r_nl = 0;
push_node(&cur_node);
} else {
push_node(&node_null);
}
if (an->entries[i].objid == *ident) {
ident_len--;
ident++;
} else {
/* an->entries[i].objid < *ident */
ident_len = 0;
}
/* follow next child pointer */
node = an->entries[i].nptr;
}
} else {
/* i == an->maxlength */
climb_tree = 1;
}
} else {
u16_t j;
/* ident_len == 0, complete with leftmost '.thing' */
j = 0;
while ((j < an->maxlength) && empty_table(an->entries[j].nptr)) {
j++;
}
if (j < an->maxlength) {
LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->entries[j].objid==%"S32_F"\n",an->entries[j].objid));
oidret->id[oidret->len] = an->entries[j].objid;
(oidret->len)++;
if (an->entries[j].nptr == NULL) {
/* leaf node */
return &an->node;
} else {
/* no leaf, continue */
node = an->entries[j].nptr;
}
} else {
/* j == an->maxlength */
climb_tree = 1;
}
}
} else if (node_type == MIB_NODE_LR) {
const struct mib_list_rootnode *lrn;
struct mib_list_node *ln;
/* list root node (internal 'RAM', variable length) */
lrn = (const struct mib_list_rootnode*)(const void*)node;
if (ident_len > 0) {
ln = lrn->head;
/* iterate over list, head to tail */
while ((ln != NULL) && (ln->objid < *ident)) {
ln = ln->next;
}
if (ln != NULL) {
LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));
oidret->id[oidret->len] = ln->objid;
(oidret->len)++;
if (ln->nptr == NULL) {
/* leaf node */
if (ln->objid > *ident) {
return &lrn->scalar.node;
} else if (ln->next != NULL) {
/* ln->objid == *ident */
(oidret->len)--;
oidret->id[oidret->len] = ln->next->objid;
(oidret->len)++;
return &lrn->scalar.node;
} else {
/* ln->next == NULL */
(oidret->len)--;
climb_tree = 1;
}
} else {
struct mib_list_node *jn;
/* non-leaf, store right child ptr and id */
jn = ln->next;
while ((jn != NULL) && empty_table(jn->nptr)) {
jn = jn->next;
}
if (jn != NULL) {
struct nse cur_node;
cur_node.r_ptr = jn->nptr;
cur_node.r_id = jn->objid;
cur_node.r_nl = 0;
push_node(&cur_node);
} else {
push_node(&node_null);
}
if (ln->objid == *ident) {
ident_len--;
ident++;
} else {
/* ln->objid < *ident */
ident_len = 0;
}
/* follow next child pointer */
node = ln->nptr;
}
} else {
/* ln == NULL */
climb_tree = 1;
}
} else {
struct mib_list_node *jn;
/* ident_len == 0, complete with leftmost '.thing' */
jn = lrn->head;
while ((jn != NULL) && empty_table(jn->nptr)) {
jn = jn->next;
}
if (jn != NULL) {
LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid));
oidret->id[oidret->len] = jn->objid;
(oidret->len)++;
if (jn->nptr == NULL) {
/* leaf node */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n"));
return &lrn->scalar.node;
} else {
/* no leaf, continue */
node = jn->nptr;
}
} else {
/* jn == NULL */
climb_tree = 1;
}
}
} else if (node_type == MIB_NODE_EX) {
const struct mib_external_node *en;
s32_t ex_id;
/* external node (addressing and access via functions) */
en = (const struct mib_external_node*)(const void*)node;
if (ident_len > 0) {
u16_t i, len;
i = 0;
len = en->level_length(en->addr_inf,ext_level);
while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0)) {
i++;
}
if (i < len) {
/* add identifier to oidret */
en->get_objid(en->addr_inf,ext_level,i,&ex_id);
LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident));
oidret->id[oidret->len] = ex_id;
(oidret->len)++;
if ((ext_level + 1) == en->tree_levels) {
LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));
/* leaf node */
if (ex_id > *ident) {
return &en->node;
} else if ((i + 1) < len) {
/* ex_id == *ident */
en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id);
(oidret->len)--;
oidret->id[oidret->len] = ex_id;
(oidret->len)++;
return &en->node;
} else {
/* (i + 1) == len */
(oidret->len)--;
climb_tree = 1;
}
} else {
u16_t j;
LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
/* non-leaf, store right child ptr and id */
LWIP_ASSERT("i < 0xff", i < 0xff);
j = i + 1;
if (j < len) {
struct nse cur_node;
/* right node is the current external node */
cur_node.r_ptr = node;
en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id);
cur_node.r_nl = ext_level + 1;
push_node(&cur_node);
} else {
push_node(&node_null);
}
if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0) {
ident_len--;
ident++;
} else {
/* external id < *ident */
ident_len = 0;
}
/* proceed to child */
ext_level++;
}
} else {
/* i == len (en->level_len()) */
climb_tree = 1;
}
} else {
/* ident_len == 0, complete with leftmost '.thing' */
en->get_objid(en->addr_inf,ext_level,0,&ex_id);
LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id));
oidret->id[oidret->len] = ex_id;
(oidret->len)++;
if ((ext_level + 1) == en->tree_levels) {
/* leaf node */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n"));
return &en->node;
} else {
/* no leaf, proceed to child */
ext_level++;
}
}
} else if (node_type == MIB_NODE_SC) {
/* scalar node */
if (ident_len > 0) {
/* at .0 */
climb_tree = 1;
} else {
/* ident_len == 0, complete object identifier */
oidret->id[oidret->len] = 0;
(oidret->len)++;
/* leaf node */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n"));
return node;
}
} else {
/* unknown/unhandled node_type */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type));
return NULL;
}
if (climb_tree) {
struct nse child;
/* find right child ptr */
child.r_ptr = NULL;
child.r_id = 0;
child.r_nl = 0;
while ((node_stack_cnt > 0) && (child.r_ptr == NULL)) {
pop_node(&child);
/* trim returned oid */
(oidret->len)--;
}
if (child.r_ptr != NULL) {
/* incoming ident is useless beyond this point */
ident_len = 0;
oidret->id[oidret->len] = child.r_id;
oidret->len++;
node = child.r_ptr;
ext_level = child.r_nl;
} else {
/* tree ends here ... */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n"));
return NULL;
}
}
}
/* done, found nothing */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(const void*)node));
return NULL;
}
/**
* Test object identifier for the iso.org.dod.internet prefix.
*
* @param ident_len the length of the supplied object identifier
* @param ident points to the array of sub identifiers
* @return 1 if it matches, 0 otherwise
*/
u8_t
snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident)
{
if ((ident_len > 3) &&
(ident[0] == 1) && (ident[1] == 3) &&
(ident[2] == 6) && (ident[3] == 1)) {
return 1;
} else {
return 0;
}
}
/**
* Expands object identifier to the iso.org.dod.internet
* prefix for use in getnext operation.
*
* @param ident_len the length of the supplied object identifier
* @param ident points to the array of sub identifiers
* @param oidret points to returned expanded object identifier
* @return 1 if it matches, 0 otherwise
*
* @note ident_len 0 is allowed, expanding to the first known object id!!
*/
u8_t
snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)
{
const s32_t *prefix_ptr;
s32_t *ret_ptr;
u8_t i;
i = 0;
prefix_ptr = &prefix[0];
ret_ptr = &oidret->id[0];
ident_len = ((ident_len < 4)?ident_len:4);
while ((i < ident_len) && ((*ident) <= (*prefix_ptr))) {
*ret_ptr++ = *prefix_ptr++;
ident++;
i++;
}
if (i == ident_len) {
/* match, complete missing bits */
while (i < 4) {
*ret_ptr++ = *prefix_ptr++;
i++;
}
oidret->len = i;
return 1;
} else {
/* i != ident_len */
return 0;
}
}
void
noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
{
LWIP_UNUSED_ARG(ident_len);
LWIP_UNUSED_ARG(ident);
od->instance = MIB_OBJECT_NONE;
}
u16_t
noleafs_get_value(struct obj_def *od, void *value)
{
LWIP_UNUSED_ARG(od);
LWIP_UNUSED_ARG(value);
return 0;
}
u8_t
noleafs_set_test(struct obj_def *od, u16_t len, void *value)
{
LWIP_UNUSED_ARG(od);
LWIP_UNUSED_ARG(len);
LWIP_UNUSED_ARG(value);
/* can't set */
return 0;
}
void
noleafs_set_value(struct obj_def *od, u16_t len, void *value)
{
LWIP_UNUSED_ARG(od);
LWIP_UNUSED_ARG(len);
LWIP_UNUSED_ARG(value);
}
#endif /* LWIP_SNMP */

File diff suppressed because it is too large Load Diff

View File

@ -1,673 +0,0 @@
/**
* @file
* SNMP output message processing (RFC1157).
*
* Output responses and traps are build in two passes:
*
* Pass 0: iterate over the output message backwards to determine encoding lengths
* Pass 1: the actual forward encoding of internal form into ASN1
*
* The single-pass encoding method described by Comer & Stevens
* requires extra buffer space and copying for reversal of the packet.
* The buffer requirement can be prohibitively large for big payloads
* (>= 484) therefore we use the two encoding passes.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/udp.h"
#include "lwip/netif.h"
#include "lwip/apps/snmp.h"
#include "lwip/snmp.h"
#include "lwip/apps/snmp_asn1.h"
#include "snmp_msg.h"
#include "lwip/sys.h"
#include <string.h>
#if !SNMP_COMMUNITY_EXT
#define snmp_community_trap snmp_community
#endif
struct snmp_trap_dst
{
/* destination IP address in network order */
ip_addr_t dip;
/* set to 0 when disabled, >0 when enabled */
u8_t enable;
};
struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];
/** TRAP message structure */
struct snmp_msg_trap trap_msg;
static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len);
static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len);
static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root);
static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p);
static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p);
static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs);
/**
* Sets enable switch for this trap destination.
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
* @param enable switch if 0 destination is disabled >0 enabled.
*/
void
snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
{
if (dst_idx < SNMP_TRAP_DESTINATIONS) {
trap_dst[dst_idx].enable = enable;
}
}
/**
* Sets IPv4 address for this trap destination.
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
* @param dst IPv4 address in host order.
*/
void
snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst)
{
if (dst_idx < SNMP_TRAP_DESTINATIONS) {
ip_addr_set(&trap_dst[dst_idx].dip, dst);
}
}
/**
* Sends a 'getresponse' message to the request originator.
*
* @param m_stat points to the current message request state source
* @return ERR_OK when success, ERR_MEM if we're out of memory
*
* @note the caller is responsible for filling in outvb in the m_stat
* and provide error-status and index (except for tooBig errors) ...
*/
err_t
snmp_send_response(struct snmp_msg_pstat *m_stat)
{
struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0};
struct pbuf *p;
u16_t tot_len;
err_t err;
/* pass 0, calculate length fields */
tot_len = snmp_varbind_list_sum(&m_stat->outvb);
tot_len = snmp_resp_header_sum(m_stat, tot_len);
/* try allocating pbuf(s) for complete response */
p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM);
if (p == NULL) {
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n"));
/* can't construct reply, return error-status tooBig */
m_stat->error_status = SNMP_ES_TOOBIG;
m_stat->error_index = 0;
/* pass 0, recalculate lengths, for empty varbind-list */
tot_len = snmp_varbind_list_sum(&emptyvb);
tot_len = snmp_resp_header_sum(m_stat, tot_len);
/* retry allocation once for header and empty varbind-list */
p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM);
}
if (p != NULL) {
/* first pbuf alloc try or retry alloc success */
u16_t ofs;
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n"));
/* pass 1, size error, encode packet ino the pbuf(s) */
ofs = snmp_resp_header_enc(m_stat, p);
snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
switch (m_stat->error_status) {
case SNMP_ES_NOERROR:
/* nothing to do */
break;
case SNMP_ES_TOOBIG:
mib2_inc_snmpouttoobigs();
break;
case SNMP_ES_NOSUCHNAME:
mib2_inc_snmpoutnosuchnames();
break;
case SNMP_ES_BADVALUE:
mib2_inc_snmpoutbadvalues();
break;
case SNMP_ES_GENERROR:
mib2_inc_snmpoutgenerrs();
break;
default:
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_send_response(): unknown error_status: %d\n", (int)m_stat->error_status));
break;
}
mib2_inc_snmpoutgetresponses();
mib2_inc_snmpoutpkts();
/** @todo do we need separate rx and tx pcbs for threaded case? */
/** connect to the originating source */
udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp);
err = udp_send(m_stat->pcb, p);
if (err == ERR_MEM) {
/** @todo release some memory, retry and return tooBig? tooMuchHassle? */
err = ERR_MEM;
} else {
err = ERR_OK;
}
/** disassociate remote address and port with this pcb */
udp_disconnect(m_stat->pcb);
pbuf_free(p);
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n"));
return err;
} else {
/* first pbuf alloc try or retry alloc failed
very low on memory, couldn't return tooBig */
return ERR_MEM;
}
}
/**
* Sends an generic or enterprise specific trap message.
*
* @param generic_trap is the trap code
* @param eoid points to enterprise object identifier
* @param specific_trap used for enterprise traps when generic_trap == 6
* @return ERR_OK when success, ERR_MEM if we're out of memory
*
* @note the caller is responsible for filling in outvb in the trap_msg
* @note the use of the enterprise identifier field
* is per RFC1215.
* Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps
* and .iso.org.dod.internet.private.enterprises.yourenterprise
* (sysObjectID) for specific traps.
*/
err_t
snmp_send_trap(s8_t generic_trap, const struct snmp_obj_id *eoid, s32_t specific_trap)
{
struct snmp_trap_dst *td;
struct netif *dst_if;
const ip_addr_t* dst_ip;
struct pbuf *p;
u16_t i,tot_len;
err_t err = ERR_OK;
for (i = 0, td = &trap_dst[0]; i < SNMP_TRAP_DESTINATIONS; i++, td++) {
if ((td->enable != 0) && !ip_addr_isany(&td->dip)) {
/* network order trap destination */
ip_addr_copy(trap_msg.dip, td->dip);
/* lookup current source address for this dst */
ip_route_get_local_ip(PCB_ISIPV6(trap_msg.pcb), &trap_msg.pcb->local_ip,
&td->dip, dst_if, dst_ip);
if ((dst_if != NULL) && (dst_ip != NULL)) {
trap_msg.sip_raw_len = (IP_IS_V6_VAL(*dst_ip) ? 16 : 4);
memcpy(trap_msg.sip_raw, dst_ip, trap_msg.sip_raw_len);
trap_msg.gen_trap = generic_trap;
trap_msg.spc_trap = specific_trap;
if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC) {
/* enterprise-Specific trap */
trap_msg.enterprise = eoid;
} else {
/* generic (MIB-II) trap */
mib2_get_snmpgrpid_ptr(&trap_msg.enterprise);
}
MIB2_COPY_SYSUPTIME_TO(&trap_msg.ts);
/* pass 0, calculate length fields */
tot_len = snmp_varbind_list_sum(&trap_msg.outvb);
tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
/* allocate pbuf(s) */
p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM);
if (p != NULL) {
u16_t ofs;
/* pass 1, encode packet ino the pbuf(s) */
ofs = snmp_trap_header_enc(&trap_msg, p);
snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);
mib2_inc_snmpouttraps();
mib2_inc_snmpoutpkts();
/** send to the TRAP destination */
udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT);
pbuf_free(p);
} else {
err = ERR_MEM;
}
} else {
/* routing error */
err = ERR_RTE;
}
}
}
return err;
}
void
snmp_coldstart_trap(void)
{
trap_msg.outvb.head = NULL;
trap_msg.outvb.tail = NULL;
trap_msg.outvb.count = 0;
snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0);
}
void
snmp_authfail_trap(void)
{
u8_t enable;
mib2_get_snmpenableauthentraps(&enable);
if (enable == 1) {
trap_msg.outvb.head = NULL;
trap_msg.outvb.tail = NULL;
trap_msg.outvb.count = 0;
snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0);
}
}
/**
* Sums response header field lengths from tail to head and
* returns resp_header_lengths for second encoding pass.
*
* @param vb_len varbind-list length
* @param rhl points to returned header lengths
* @return the required length for encoding the response header
*/
static u16_t
snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len)
{
u16_t tot_len;
s32_t snmp_req_ver;
struct snmp_resp_header_lengths *rhl;
rhl = &m_stat->rhl;
tot_len = vb_len;
snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen);
snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen);
tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen;
snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen);
snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen);
tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen;
snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen);
snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen);
tot_len += 1 + rhl->ridlenlen + rhl->ridlen;
rhl->pdulen = tot_len;
snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen);
tot_len += 1 + rhl->pdulenlen;
rhl->comlen = m_stat->com_strlen;
snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen);
tot_len += 1 + rhl->comlenlen + rhl->comlen;
snmp_req_ver = m_stat->version;
snmp_asn1_enc_s32t_cnt(snmp_req_ver, &rhl->verlen);
snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen);
tot_len += 1 + rhl->verlen + rhl->verlenlen;
rhl->seqlen = tot_len;
snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen);
tot_len += 1 + rhl->seqlenlen;
return tot_len;
}
/**
* Sums trap header field lengths from tail to head and
* returns trap_header_lengths for second encoding pass.
*
* @param vb_len varbind-list length
* @param thl points to returned header lengths
* @return the required length for encoding the trap header
*/
static u16_t
snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len)
{
u16_t tot_len;
struct snmp_trap_header_lengths *thl;
thl = &m_trap->thl;
tot_len = vb_len;
snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen);
snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen);
tot_len += 1 + thl->tslen + thl->tslenlen;
snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen);
snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen);
tot_len += 1 + thl->strplen + thl->strplenlen;
snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen);
snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen);
tot_len += 1 + thl->gtrplen + thl->gtrplenlen;
thl->aaddrlen = m_trap->sip_raw_len;
snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen);
tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen;
snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen);
snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen);
tot_len += 1 + thl->eidlen + thl->eidlenlen;
thl->pdulen = tot_len;
snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen);
tot_len += 1 + thl->pdulenlen;
thl->comlen = (u16_t)strlen(snmp_community_trap);
snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen);
tot_len += 1 + thl->comlenlen + thl->comlen;
snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen);
snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen);
tot_len += 1 + thl->verlen + thl->verlenlen;
thl->seqlen = tot_len;
snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen);
tot_len += 1 + thl->seqlenlen;
return tot_len;
}
/**
* Sums varbind lengths from tail to head and
* annotates lengths in varbind for second encoding pass.
*
* @param root points to the root of the variable binding list
* @return the required length for encoding the variable bindings
*/
static u16_t
snmp_varbind_list_sum(struct snmp_varbind_root *root)
{
struct snmp_varbind *vb;
u32_t *uint_ptr;
s32_t *sint_ptr;
u16_t tot_len;
tot_len = 0;
vb = root->tail;
while (vb != NULL) {
/* encoded value lenght depends on type */
switch (vb->value_type) {
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);
break;
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
uint_ptr = (u32_t*)vb->value;
snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
vb->vlen = vb->value_len;
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);
break;
default:
/* unsupported type */
vb->vlen = 0;
break;
}
/* encoding length of value length field */
snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen);
snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen);
snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen);
vb->seqlen = 1 + vb->vlenlen + vb->vlen;
vb->seqlen += 1 + vb->olenlen + vb->olen;
snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen);
/* varbind seq */
tot_len += 1 + vb->seqlenlen + vb->seqlen;
vb = vb->prev;
}
/* varbind-list seq */
root->seqlen = tot_len;
snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen);
tot_len += 1 + root->seqlenlen;
return tot_len;
}
/**
* Encodes response header from head to tail.
*/
static u16_t
snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p)
{
u16_t ofs;
s32_t snmp_req_ver;
ofs = 0;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen);
ofs += m_stat->rhl.seqlenlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen);
ofs += m_stat->rhl.verlenlen;
snmp_req_ver = m_stat->version;
snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_req_ver);
ofs += m_stat->rhl.verlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen);
ofs += m_stat->rhl.comlenlen;
snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community);
ofs += m_stat->rhl.comlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen);
ofs += m_stat->rhl.pdulenlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen);
ofs += m_stat->rhl.ridlenlen;
snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid);
ofs += m_stat->rhl.ridlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen);
ofs += m_stat->rhl.errstatlenlen;
snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status);
ofs += m_stat->rhl.errstatlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen);
ofs += m_stat->rhl.erridxlenlen;
snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index);
ofs += m_stat->rhl.erridxlen;
return ofs;
}
/**
* Encodes trap header from head to tail.
*/
static u16_t
snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p)
{
u16_t ofs;
ofs = 0;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen);
ofs += m_trap->thl.seqlenlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen);
ofs += m_trap->thl.verlenlen;
snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version);
ofs += m_trap->thl.verlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen);
ofs += m_trap->thl.comlenlen;
snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (const u8_t *)&snmp_community_trap[0]);
ofs += m_trap->thl.comlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen);
ofs += m_trap->thl.pdulenlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen);
ofs += m_trap->thl.eidlenlen;
snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]);
ofs += m_trap->thl.eidlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen);
ofs += m_trap->thl.aaddrlenlen;
snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]);
ofs += m_trap->thl.aaddrlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen);
ofs += m_trap->thl.gtrplenlen;
snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap);
ofs += m_trap->thl.gtrplen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen);
ofs += m_trap->thl.strplenlen;
snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap);
ofs += m_trap->thl.strplen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen);
ofs += m_trap->thl.tslenlen;
snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts);
ofs += m_trap->thl.tslen;
return ofs;
}
/**
* Encodes varbind list from head to tail.
*/
static u16_t
snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)
{
struct snmp_varbind *vb;
s32_t *sint_ptr;
u32_t *uint_ptr;
u8_t *raw_ptr;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
ofs += 1;
snmp_asn1_enc_length(p, ofs, root->seqlen);
ofs += root->seqlenlen;
vb = root->head;
while (vb != NULL) {
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
ofs += 1;
snmp_asn1_enc_length(p, ofs, vb->seqlen);
ofs += vb->seqlenlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
ofs += 1;
snmp_asn1_enc_length(p, ofs, vb->olen);
ofs += vb->olenlen;
snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]);
ofs += vb->olen;
snmp_asn1_enc_type(p, ofs, vb->value_type);
ofs += 1;
snmp_asn1_enc_length(p, ofs, vb->vlen);
ofs += vb->vlenlen;
switch (vb->value_type) {
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);
break;
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
uint_ptr = (u32_t*)vb->value;
snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
raw_ptr = (u8_t*)vb->value;
snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);
break;
default:
/* unsupported type */
break;
}
ofs += vb->vlen;
vb = vb->next;
}
return ofs;
}
#endif /* LWIP_SNMP */

748
src/apps/snmp/snmp_asn1.c Normal file
View File

@ -0,0 +1,748 @@
/**
* @file
* Abstract Syntax Notation One (ISO 8824, 8825) encoding
*
* @todo not optimised (yet), favor correctness over speed, favor speed over size
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
* Martin Hentschel <info@cl-soft.de>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "snmp_asn1.h"
#define PBUF_OP_EXEC(code) \
if ((code) != ERR_OK) { \
return ERR_BUF; \
}
err_t
snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
{
u8_t data;
u8_t length_bytes_required;
/* write type */
if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
/* extended format is not used by SNMP so we do not accept those values */
return ERR_ARG;
}
if (tlv->type_len != 0) {
/* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */
return ERR_ARG;
}
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type));
tlv->type_len = 1;
/* write length */
if (tlv->value_len <= 127) {
length_bytes_required = 1;
} else if (tlv->value_len <= 255) {
length_bytes_required = 2;
} else {
length_bytes_required = 3;
}
/* check for forced min length */
if (tlv->length_len > 0) {
if (tlv->length_len < length_bytes_required) {
/* unable to code requested length in requested number of bytes */
return ERR_ARG;
}
length_bytes_required = tlv->length_len;
} else {
tlv->length_len = length_bytes_required;
}
if (length_bytes_required > 1) {
/* multi byte representation required */
length_bytes_required--;
data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
while (length_bytes_required > 1)
{
if (length_bytes_required == 2) {
/* append high byte */
data = (u8_t)(tlv->value_len >> 8);
} else {
/* append leading 0x00 */
data = 0x00;
}
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
length_bytes_required--;
}
}
/* append low byte */
data = (u8_t)(tlv->value_len & 0xFF);
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
return ERR_OK;
}
/**
* Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode raw data into
* @param ofs points to the offset within the pbuf chain
* @param raw_len raw data length
* @param raw points raw data
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len)
{
PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len));
return ERR_OK;
}
/**
* Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode value into
* @param ofs points to the offset within the pbuf chain
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
* @param value is the host order u32_t value to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_u32t_cnt()
*/
err_t
snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value)
{
if (octets_needed > 5) {
return ERR_ARG;
}
if (octets_needed == 5) {
/* not enough bits in 'value' add leading 0x00 */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
octets_needed--;
}
while (octets_needed > 1) {
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
}
/* (only) one least significant octet */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
return ERR_OK;
}
/**
* Encodes u64_t (counter64) into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode value into
* @param ofs points to the offset within the pbuf chain
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
* @param value is the host order u32_t value to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_u64t_cnt()
*/
err_t
snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value)
{
if (octets_needed > 9) {
return ERR_ARG;
}
if (octets_needed == 9) {
/* not enough bits in 'value' add leading 0x00 */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
octets_needed--;
}
while (octets_needed > 4) {
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> ((octets_needed-4) << 3))));
}
/* skip to low u32 */
value++;
while (octets_needed > 1) {
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> (octets_needed << 3))));
}
/* always write at least one octet (also in case of value == 0) */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value)));
return ERR_OK;
}
/**
* Encodes s32_t integer into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode value into
* @param ofs points to the offset within the pbuf chain
* @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
* @param value is the host order s32_t value to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_s32t_cnt()
*/
err_t
snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value)
{
while (octets_needed > 1) {
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
}
/* (only) one least significant octet */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
return ERR_OK;
}
/**
* Encodes object identifier into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode oid into
* @param ofs points to the offset within the pbuf chain
* @param ident_len object identifier array length
* @param ident points to object identifier array
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len)
{
if (oid_len > 1) {
/* write compressed first two sub id's */
u32_t compressed_byte = ((oid[0] * 40) + oid[1]);
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte));
oid_len -= 2;
oid += 2;
} else {
/* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
/* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
return ERR_ARG;
}
while (oid_len > 0) {
u32_t sub_id;
u8_t shift, tail;
oid_len--;
sub_id = *oid;
tail = 0;
shift = 28;
while (shift > 0) {
u8_t code;
code = (u8_t)(sub_id >> shift);
if ((code != 0) || (tail != 0)) {
tail = 1;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80));
}
shift -= 7;
}
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F));
/* proceed to next sub-identifier */
oid++;
}
return ERR_OK;
}
/**
* Returns octet count for length.
*
* @param length
* @param octets_needed points to the return value
*/
void
snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
{
if (length < 0x80U) {
*octets_needed = 1;
} else if (length < 0x100U) {
*octets_needed = 2;
} else {
*octets_needed = 3;
}
}
/**
* Returns octet count for an u32_t.
*
* @param value
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
void
snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
{
if (value < 0x80UL) {
*octets_needed = 1;
} else if (value < 0x8000UL) {
*octets_needed = 2;
} else if (value < 0x800000UL) {
*octets_needed = 3;
} else if (value < 0x80000000UL) {
*octets_needed = 4;
} else {
*octets_needed = 5;
}
}
/**
* Returns octet count for an u64_t.
*
* @param value
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
void
snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed)
{
/* check if high u32 is 0 */
if (*value == 0x00)
{
/* only low u32 is important */
value++;
snmp_asn1_enc_u32t_cnt(*value, octets_needed);
} else {
/* low u32 does not matter for length determination */
snmp_asn1_enc_u32t_cnt(*value, octets_needed);
*octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */
}
}
/**
* Returns octet count for an s32_t.
*
* @param value
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed.
*/
void
snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
{
if (value < 0) {
value = ~value;
}
if (value < 0x80L) {
*octets_needed = 1;
} else if (value < 0x8000L) {
*octets_needed = 2;
} else if (value < 0x800000L) {
*octets_needed = 3;
} else {
*octets_needed = 4;
}
}
/**
* Returns octet count for an object identifier.
*
* @param ident_len object identifier array length
* @param ident points to object identifier array
* @param octets_needed points to the return value
*/
void
snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed)
{
u32_t sub_id;
*octets_needed = 0;
if (oid_len > 1) {
/* compressed prefix in one octet */
(*octets_needed)++;
oid_len -= 2;
oid += 2;
}
while (oid_len > 0) {
oid_len--;
sub_id = *oid;
sub_id >>= 7;
(*octets_needed)++;
while (sub_id > 0) {
sub_id >>= 7;
(*octets_needed)++;
}
oid++;
}
}
err_t
snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
{
u8_t data;
/* decode type first */
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
tlv->type = data;
if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
/* extended format is not used by SNMP so we do not accept those values */
return ERR_VAL;
}
tlv->type_len = 1;
/* now, decode length */
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
if (data < 0x80) { /* short form */
tlv->length_len = 1;
tlv->value_len = data;
} else if (data > 0x80) { /* long form */
u8_t length_bytes = data - 0x80;
tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */
tlv->value_len = 0;
while (length_bytes > 0) {
/* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */
if (tlv->value_len > 0xFF) {
return ERR_VAL;
}
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
tlv->value_len <<= 8;
tlv->value_len |= data;
/* take care for special value used for indefinite length */
if (tlv->value_len == 0xFFFF) {
return ERR_VAL;
}
length_bytes--;
}
} else { /* data == 0x80 indefinite length form */
/* (not allowed for SNMP; RFC 1157, 3.2.2) */
return ERR_VAL;
//tlv->length_len = 1;
//tlv->value_len = 0xFFFF;
}
return ERR_OK;
}
/**
* Decodes positive integer (counter, gauge, timeticks) into u32_t.
*
* @param p points to a pbuf holding an ASN1 coded integer
* @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
err_t
snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
{
u8_t data;
if ((len > 0) && (len <= 5)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
/* expecting sign bit to be zero, only unsigned please! */
if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) {
*value = data;
len--;
while (len > 0)
{
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
*value <<= 8;
*value |= data;
}
return ERR_OK;
}
}
return ERR_VAL;
}
/**
* Decodes large positive integer (counter64) into 2x u32_t.
*
* @param p points to a pbuf holding an ASN1 coded integer
* @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
err_t
snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
{
u8_t data;
if (len <= 4) {
/* high u32 is 0 */
*value = 0;
/* directly skip to low u32 */
value++;
}
if ((len > 0) && (len <= 9)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
/* expecting sign bit to be zero, only unsigned please! */
if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) {
*value = data;
len--;
while (len > 0)
{
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
if (len == 4) {
/* skip to low u32 */
value++;
*value = 0;
} else {
*value <<= 8;
}
*value |= data;
len--;
}
return ERR_OK;
}
}
return ERR_VAL;
}
/**
* Decodes integer into s32_t.
*
* @param p points to a pbuf holding an ASN1 coded integer
* @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed!
*/
err_t
snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value)
{
#if BYTE_ORDER == LITTLE_ENDIAN
u8_t *lsb_ptr = (u8_t*)value;
#endif
#if BYTE_ORDER == BIG_ENDIAN
u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
#endif
u8_t sign;
u8_t data;
if ((len > 0) && (len < 5)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
if (data & 0x80) {
/* negative, start from -1 */
*value = -1;
sign = 1;
*lsb_ptr &= data;
} else {
/* positive, start from 0 */
*value = 0;
sign = 0;
*lsb_ptr |= data;
}
/* OR/AND octets with value */
while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
#if BYTE_ORDER == LITTLE_ENDIAN
*value <<= 8;
#endif
#if BYTE_ORDER == BIG_ENDIAN
*value >>= 8;
#endif
if (sign) {
*lsb_ptr |= 255;
*lsb_ptr &= data;
} else {
*lsb_ptr |= data;
}
}
return ERR_OK;
}
return ERR_VAL;
}
/**
* Decodes object identifier from incoming message into array of u32_t.
*
* @param p points to a pbuf holding an ASN1 coded object identifier
* @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier
* @param len length of the coded object identifier
* @param oid return object identifier struct
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len)
{
u32_t *oid_ptr;
u8_t data;
*oid_len = 0;
oid_ptr = oid;
if (len > 0) {
if (oid_max_len < 2) {
return ERR_MEM;
}
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
/* first compressed octet */
if (data == 0x2B) {
/* (most) common case 1.3 (iso.org) */
*oid_ptr = 1;
oid_ptr++;
*oid_ptr = 3;
oid_ptr++;
} else if (data < 40) {
*oid_ptr = 0;
oid_ptr++;
*oid_ptr = data;
oid_ptr++;
} else if (data < 80) {
*oid_ptr = 1;
oid_ptr++;
*oid_ptr = data - 40;
oid_ptr++;
} else {
*oid_ptr = 2;
oid_ptr++;
*oid_ptr = data - 80;
oid_ptr++;
}
*oid_len = 2;
} else {
/* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */
return ERR_OK;
}
while ((len > 0) && (*oid_len < oid_max_len)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
if ((data & 0x80) == 0x00) {
/* sub-identifier uses single octet */
*oid_ptr = data;
} else {
/* sub-identifier uses multiple octets */
u32_t sub_id = (data & ~0x80);
while ((len > 0) && ((data & 0x80) != 0)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
sub_id = (sub_id << 7) + (data & ~0x80);
}
if ((data & 0x80) != 0) {
/* "more bytes following" bit still set at end of len */
return ERR_VAL;
}
*oid_ptr = sub_id;
}
oid_ptr++;
(*oid_len)++;
}
if (len > 0) {
/* OID to long to fit in our buffer */
return ERR_MEM;
}
return ERR_OK;
}
/**
* Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
* from incoming message into array.
*
* @param p points to a pbuf holding an ASN1 coded raw data
* @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data
* @param len length of the coded raw data (zero is valid, e.g. empty string!)
* @param raw_len length of the raw return value
* @param raw return raw bytes
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len)
{
if (len > buf_max_len) {
/* not enough dst space */
return ERR_MEM;
}
*buf_len = len;
while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf));
buf++;
len--;
}
return ERR_OK;
}
#endif /* LWIP_SNMP */

105
src/apps/snmp/snmp_asn1.h Normal file
View File

@ -0,0 +1,105 @@
/**
* @file
* Abstract Syntax Notation One (ISO 8824, 8825) codec.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
* Martin Hentschel <info@cl-soft.de>
*/
#ifndef LWIP_HDR_APPS_SNMP_ASN1_H
#define LWIP_HDR_APPS_SNMP_ASN1_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP
#include "lwip/err.h"
#include "lwip/apps/snmp_core.h"
#include "snmp_pbuf_stream.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SNMP_ASN1_TLV_INDEFINITE_LENGTH 0x80
#define SNMP_ASN1_CLASS_MASK 0xC0
#define SNMP_ASN1_CONTENTTYPE_MASK 0x20
#define SNMP_ASN1_DATATYPE_MASK 0x1F
#define SNMP_ASN1_DATATYPE_EXTENDED 0x1F // DataType indicating that datatype is encoded in following bytes
/* context specific (SNMP) tags (from SNMP spec. RFC1157) */
#define SNMP_ASN1_CONTEXT_PDU_GET_REQ 0
#define SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ 1
#define SNMP_ASN1_CONTEXT_PDU_GET_RESP 2
#define SNMP_ASN1_CONTEXT_PDU_SET_REQ 3
#define SNMP_ASN1_CONTEXT_PDU_TRAP 4
#define SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ 5
#define SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT 0
#define SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW 2
struct snmp_asn1_tlv
{
u8_t type; /* only U8 because extended types are not specified by SNMP */
u8_t type_len; /* encoded length of 'type' field (normally 1) */
u8_t length_len; /* indicates how many bytes are required to encode the 'value_len' field */
u16_t value_len; /* encoded length of the value */
};
#define SNMP_ASN1_TLV_LENGTH(tlv) ((tlv).type_len + (tlv).length_len + (tlv).value_len)
#define SNMP_ASN1_SET_TLV_PARAMS(tlv, type_, length_len_, value_len_) do { (tlv).type = (type_); (tlv).type_len = 0; (tlv).length_len = (length_len_); (tlv).value_len = (value_len_); } while (0);
err_t snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv);
err_t snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value);
err_t snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value);
err_t snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value);
err_t snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len);
err_t snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len);
err_t snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv);
void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);
void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);
void snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed);
void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
void snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed);
err_t snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len);
err_t snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value);
err_t snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value);
err_t snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value);
err_t snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_ASN1_H */

942
src/apps/snmp/snmp_core.c Normal file
View File

@ -0,0 +1,942 @@
/**
* @file
* MIB tree access/construction functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
* Martin Hentschel <info@cl-soft.de>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "snmp_core_priv.h"
#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))
#error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
#endif
#if (!LWIP_UDP && LWIP_SNMP)
#error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
struct snmp_statistics snmp_stats;
static const struct snmp_obj_id snmp_device_enterprise_oid_default = {SNMP_DEVICE_ENTERPRISE_OID_LEN, SNMP_DEVICE_ENTERPRISE_OID};
static const struct snmp_obj_id* snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default;
const u32_t snmp_zero_dot_zero_values[] = { 0, 0 };
const struct snmp_obj_id_const_ref snmp_zero_dot_zero = { LWIP_ARRAYSIZE(snmp_zero_dot_zero_values), snmp_zero_dot_zero_values };
#if SNMP_LWIP_MIB2
#include "lwip/apps/snmp_mib2.h"
static const struct snmp_mib *default_mibs[] = { &mib2 };
static u8_t snmp_num_mibs = 1;
#else
static const struct snmp_mib *default_mibs[] = { NULL };
static u8_t snmp_num_mibs = 0;
#endif
/* List of known mibs */
static struct snmp_mib const **snmp_mibs = default_mibs;
/**
* Sets the MIBs to use.
* Example: call snmp_set_mibs() as follows:
* static const struct snmp_mib *my_snmp_mibs[] = {
* &mib2,
* &private_mib
* };
* snmp_set_mibs(my_snmp_mibs, LWIP_ARRAYSIZE(my_snmp_mibs));
*/
void
snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs)
{
LWIP_ASSERT("mibs pointer must be != NULL", (mibs != NULL));
LWIP_ASSERT("num_mibs pointer must be != 0", (num_mibs != 0));
snmp_mibs = mibs;
snmp_num_mibs = num_mibs;
}
void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_oid)
{
if (device_enterprise_oid == NULL) {
snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default;
} else {
snmp_device_enterprise_oid = device_enterprise_oid;
}
}
const struct snmp_obj_id* snmp_get_device_enterprise_oid(void)
{
return snmp_device_enterprise_oid;
}
/**
* Conversion from oid to lwIP ip_addr
* @param ident points to u32_t ident[4] input
* @param ip points to output struct
*/
u8_t
snmp_oid_to_ip(const u32_t *oid, ip4_addr_t *ip)
{
if((oid[0] > 0xFF) ||
(oid[1] > 0xFF) ||
(oid[2] > 0xFF) ||
(oid[3] > 0xFF)) {
ip4_addr_copy(*ip, *IP4_ADDR_ANY);
return 0;
}
IP4_ADDR(ip, oid[0], oid[1], oid[2], oid[3]);
return 1;
}
/**
* Conversion from lwIP ip_addr to oid
* @param ip points to input struct
* @param ident points to u32_t ident[4] output
*/
void
snmp_ip_to_oid(const ip4_addr_t *ip, u32_t *oid)
{
oid[0] = ip4_addr1(ip);
oid[1] = ip4_addr2(ip);
oid[2] = ip4_addr3(ip);
oid[3] = ip4_addr4(ip);
}
void
snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
{
LWIP_ASSERT("oid_len <= LWIP_SNMP_OBJ_ID_LEN", oid_len <= SNMP_MAX_OBJ_ID_LEN);
target->len = oid_len;
if (oid_len > 0) {
MEMCPY(target->id, oid, oid_len * sizeof(u32_t));
}
}
void
snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
{
LWIP_ASSERT("target->len + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN);
if (oid_len > 0)
{
/* move existing OID to make room at the beginning for OID to insert */
int i;
for (i = target->len-1; i>=0; i--)
{
target->id[i + oid_len] = target->id[i];
}
/* paste oid at the beginning */
MEMCPY(target->id, oid, oid_len * sizeof(u32_t));
}
}
void
snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
{
snmp_oid_assign(target, oid1, oid1_len);
snmp_oid_append(target, oid2, oid2_len);
}
void
snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
{
LWIP_ASSERT("offset + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN);
if(oid_len > 0) {
MEMCPY(&target->id[target->len], oid, oid_len * sizeof(u32_t));
target->len += oid_len;
}
}
s8_t
snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
{
u8_t level = 0;
LWIP_ASSERT("'oid1' param must not be NULL or 'oid1_len' param be 0!", (oid1 != NULL) || (oid1_len == 0));
LWIP_ASSERT("'oid2' param must not be NULL or 'oid2_len' param be 0!", (oid2 != NULL) || (oid2_len == 0));
while ((level < oid1_len) && (level < oid2_len))
{
if (*oid1 < *oid2)
{
return -1;
}
if (*oid1 > *oid2)
{
return 1;
}
level++;
oid1++;
oid2++;
}
/* common part of both OID's is equal, compare length */
if (oid1_len < oid2_len)
{
return -1;
}
if (oid1_len > oid2_len)
{
return 1;
}
/* they are equal */
return 0;
}
u8_t
snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
{
return (snmp_oid_compare(oid1, oid1_len, oid2, oid2_len) == 0)? 1 : 0;
}
static const struct snmp_mib*
snmp_get_mib_from_oid(const u32_t *oid, u8_t oid_len)
{
const u32_t* list_oid;
const u32_t* searched_oid;
u8_t i, l;
u8_t max_match_len = 0;
const struct snmp_mib* matched_mib = NULL;
LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL));
LWIP_ASSERT("'oid_len' param must be greater than 0!", (oid_len > 0));
for (i=0; i<snmp_num_mibs; i++)
{
LWIP_ASSERT("MIB array not initialized correctly", (snmp_mibs[i] != NULL));
LWIP_ASSERT("MIB array not initialized correctly - base OID is NULL", (snmp_mibs[i]->base_oid != NULL));
if (oid_len >= snmp_mibs[i]->base_oid_len)
{
l = snmp_mibs[i]->base_oid_len;
list_oid = snmp_mibs[i]->base_oid;
searched_oid = oid;
while (l > 0)
{
if (*list_oid != *searched_oid)
{
break;
}
l--;
list_oid++;
searched_oid++;
}
if ((l == 0) && (snmp_mibs[i]->base_oid_len > max_match_len))
{
max_match_len = snmp_mibs[i]->base_oid_len;
matched_mib = snmp_mibs[i];
}
}
}
return matched_mib;
}
static const struct snmp_mib*
snmp_get_next_mib(const u32_t *oid, u8_t oid_len)
{
u8_t i;
const struct snmp_mib* next_mib = NULL;
LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL));
LWIP_ASSERT("'oid_len' param must be greater than 0!", (oid_len > 0));
for (i=0; i<snmp_num_mibs; i++)
{
if (snmp_mibs[i]->base_oid != NULL)
{
/* check if mib is located behind starting point */
if (snmp_oid_compare(snmp_mibs[i]->base_oid, snmp_mibs[i]->base_oid_len, oid, oid_len) > 0)
{
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))
{
next_mib = snmp_mibs[i];
}
}
}
}
return next_mib;
}
static const struct snmp_mib*
snmp_get_mib_between(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
{
const struct snmp_mib* next_mib = snmp_get_next_mib(oid1, oid1_len);
LWIP_ASSERT("'oid2' param must not be NULL!", (oid2 != NULL));
LWIP_ASSERT("'oid2_len' param must be greater than 0!", (oid2_len > 0));
if (next_mib != NULL)
{
if (snmp_oid_compare(next_mib->base_oid, next_mib->base_oid_len, oid2, oid2_len) < 0)
{
return next_mib;
}
}
return NULL;
}
u8_t
snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance)
{
u8_t result = SNMP_ERR_NOSUCHOBJECT;
const struct snmp_mib *mib;
const struct snmp_node *mn = NULL;
mib = snmp_get_mib_from_oid(oid, oid_len);
if (mib != NULL) {
u8_t oid_instance_len;
mn = snmp_mib_tree_resolve_exact(mib, oid, oid_len, &oid_instance_len);
if ((mn != NULL) && (mn->node_type != SNMP_NODE_TREE)) {
/* get instance */
const struct snmp_leaf_node* leaf_node = (const struct snmp_leaf_node*)mn;
node_instance->node = mn;
snmp_oid_assign(&node_instance->instance_oid, oid + (oid_len - oid_instance_len), oid_instance_len);
result = leaf_node->get_instance(
oid,
oid_len - oid_instance_len,
node_instance);
#ifdef LWIP_DEBUG
if(result == SNMP_ERR_NOERROR) {
if(((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != 0) && (node_instance->get_value == NULL)) {
LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is readable but no get_value function is specified\n"));
}
if(((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != 0) && (node_instance->set_value == NULL)) {
LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is writable but no set_value and/or set_test function is specified\n"));
}
}
#endif
}
}
return result;
}
u8_t
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)
{
const struct snmp_mib *mib;
const struct snmp_node *mn = NULL;
const u32_t* start_oid = NULL;
u8_t start_oid_len = 0;
/* resolve target MIB from passed OID */
mib = snmp_get_mib_from_oid(oid, oid_len);
if (mib == NULL) {
/* passed OID does not reference any known MIB, start at the next closest MIB */
mib = snmp_get_next_mib(oid, oid_len);
if (mib != NULL) {
start_oid = mib->base_oid;
start_oid_len = mib->base_oid_len;
}
} else {
start_oid = oid;
start_oid_len = oid_len;
}
/* resolve target node from MIB, skip to next MIB if no suitable node is found in current MIB */
while ((mib != NULL) && (mn == NULL)) {
u8_t oid_instance_len;
/* check if OID directly references a node inside current MIB, in this case we have to ask this node for the next instance */
mn = snmp_mib_tree_resolve_exact(mib, start_oid, start_oid_len, &oid_instance_len);
if (mn != NULL) {
snmp_oid_assign(node_oid, start_oid, start_oid_len - oid_instance_len); /* set oid to node */
snmp_oid_assign(&node_instance->instance_oid, start_oid + (start_oid_len - oid_instance_len), oid_instance_len); /* set (relative) instance oid */
} else {
/* 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 */
mn = snmp_mib_tree_resolve_next(mib, start_oid, start_oid_len, node_oid);
node_instance->instance_oid.len = 0;
}
/* 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 */
node_instance->node = mn;
while (mn != NULL)
{
u8_t result;
/* clear fields which may have values from previous loops */
node_instance->asn1_type = 0;
node_instance->access = SNMP_NODE_INSTANCE_NOT_ACCESSIBLE;
node_instance->get_value = NULL;
node_instance->set_test = NULL;
node_instance->set_value = NULL;
node_instance->release_instance = NULL;
node_instance->reference.ptr = NULL;
node_instance->reference_len = 0;
result = ((const struct snmp_leaf_node*)mn)->get_next_instance(
node_oid->id,
node_oid->len,
node_instance);
if (result == SNMP_ERR_NOERROR)
{
#ifdef LWIP_DEBUG
if(((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != 0) && (node_instance->get_value == NULL)) {
LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is readable but no get_value function is specified\n"));
}
if(((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != 0) && (node_instance->set_value == NULL)) {
LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is writable but no set_value function is specified\n"));
}
#endif
/* validate node because the node may be not accessible for example (but let the caller decide what is valid */
if ((validate_node_instance_method == NULL) || (validate_node_instance_method(node_instance, validate_node_instance_arg) == SNMP_ERR_NOERROR))
{
/* node_oid "returns" the full result OID (including the instance part) */
snmp_oid_append(node_oid, node_instance->instance_oid.id, node_instance->instance_oid.len);
break;
}
if (node_instance->release_instance != NULL) {
node_instance->release_instance(node_instance);
}
/*
the instance itself is not valid, ask for next instance from same node.
we don't have to change any variables because node_instance->instance_oid is used as input (starting point)
as well as output (resulting next OID), so we have to simply call get_next_instance method again
*/
}
else
{
if (node_instance->release_instance != NULL) {
node_instance->release_instance(node_instance);
}
/* the node has no further instance, skip to next node */
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 */
if (mn != NULL)
{
/* prepare for next loop */
snmp_oid_assign(node_oid, node_instance->instance_oid.id, node_instance->instance_oid.len);
node_instance->instance_oid.len = 0;
node_instance->node = mn;
}
}
}
if (mn != NULL) {
/*
we found a suitable next node,
now we have to check if a inner MIB is located between the searched OID and the resulting OID.
this is possible because MIB's may be located anywhere in the global tree, that means also in
the subtree of another MIB (e.g. if searched OID is .2 and resulting OID is .4, then another
MIB having .3 as root node may exist)
*/
const struct snmp_mib *intermediate_mib;
intermediate_mib = snmp_get_mib_between(start_oid, start_oid_len, node_oid->id, node_oid->len);
if (intermediate_mib != NULL) {
/* search for first node inside intermediate mib in next loop */
if (node_instance->release_instance != NULL) {
node_instance->release_instance(node_instance);
}
mn = NULL;
mib = intermediate_mib;
start_oid = mib->base_oid;
start_oid_len = mib->base_oid_len;
}
/* else { we found out target node } */
} else {
/*
there is no further (suitable) node inside this MIB, search for the next MIB with following priority
1. search for inner MIB's (whose root is located inside tree of current MIB)
2. search for surrouding MIB's (where the current MIB is the inner MIB) and continue there if any
3. take the next closest MIB (not being related to the current MIB)
*/
const struct snmp_mib *next_mib;
next_mib = snmp_get_next_mib(start_oid, start_oid_len); /* returns MIB's related to point 1 and 3 */
/* is the found MIB an inner MIB? (point 1) */
if ((next_mib != NULL) && (next_mib->base_oid_len > mib->base_oid_len) &&
(snmp_oid_compare(next_mib->base_oid, mib->base_oid_len, mib->base_oid, mib->base_oid_len) == 0)) {
/* yes it is -> continue at inner MIB */
mib = next_mib;
start_oid = mib->base_oid;
start_oid_len = mib->base_oid_len;
} else {
/* check if there is a surrounding mib where to continue (point 2) (only possible if OID length > 1) */
if (mib->base_oid_len > 1) {
mib = snmp_get_mib_from_oid(mib->base_oid, mib->base_oid_len - 1);
if (mib == NULL) {
/* no surrounding mib, use next mib encountered above (point 3) */
mib = next_mib;
if (mib != NULL) {
start_oid = mib->base_oid;
start_oid_len = mib->base_oid_len;
}
}
/* else { start_oid stays the same because we want to continue from current offset in surrounding mib (point 2) } */
}
}
}
}
if (mib == NULL)
{
// loop is only left when mib == null (error) or mib_node != NULL (success)
return SNMP_ERR_ENDOFMIBVIEW;
}
return SNMP_ERR_NOERROR;
}
/**
* Searches tree for the supplied object identifier.
*
*/
const struct snmp_node *
snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len)
{
const struct snmp_node* const* node = &mib->root_node;
u8_t oid_offset = mib->base_oid_len;
while ((oid_offset < oid_len) && ((*node)->node_type == SNMP_NODE_TREE))
{
/* search for matching sub node */
u32_t subnode_oid = *(oid + oid_offset);
u32_t i = (*(const struct snmp_tree_node* const*)node)->subnode_count;
node = (*(const struct snmp_tree_node* const*)node)->subnodes;
while ((i > 0) && ((*node)->oid != subnode_oid))
{
node++;
i--;
}
if (i == 0)
{
/* no matching subnode found */
return NULL;
}
oid_offset++;
}
if ((*node)->node_type != SNMP_NODE_TREE)
{
/* we found a leaf node */
*oid_instance_len = oid_len - oid_offset;
return (*node);
}
return NULL;
}
const struct snmp_node*
snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret)
{
u8_t oid_offset = mib->base_oid_len;
const struct snmp_node* const* node;
const struct snmp_tree_node* node_stack[SNMP_MAX_OBJ_ID_LEN];
s32_t nsi = 0; /* NodeStackIndex */
u32_t subnode_oid;
if (mib->root_node->node_type != SNMP_NODE_TREE)
{
/* a next operation on a mib with only a leaf node will always return NULL because there is no other node */
return NULL;
}
/* first build node stack related to passed oid (as far as possible), then go backwards to determine the next node */
node_stack[nsi] = (const struct snmp_tree_node*)mib->root_node;
while (oid_offset < oid_len)
{
/* search for matching sub node */
u32_t i = node_stack[nsi]->subnode_count;
node = node_stack[nsi]->subnodes;
subnode_oid = *(oid + oid_offset);
while ((i > 0) && ((*node)->oid != subnode_oid))
{
node++;
i--;
}
if ((i == 0) || ((*node)->node_type != SNMP_NODE_TREE))
{
/* no (matching) tree-subnode found */
break;
}
nsi++;
node_stack[nsi] = (const struct snmp_tree_node*)(*node);
oid_offset++;
}
if (oid_offset >= oid_len)
{
/* passed oid references a tree node -> return first useable sub node of it */
subnode_oid = 0;
}
else
{
subnode_oid = *(oid + oid_offset) + 1;
}
while (nsi >= 0)
{
const struct snmp_node* subnode = NULL;
/* find next node on current level */
s32_t i = node_stack[nsi]->subnode_count;
node = node_stack[nsi]->subnodes;
while (i > 0)
{
if ((*node)->oid == subnode_oid)
{
subnode = *node;
break;
}
else if (((*node)->oid > subnode_oid) && ((subnode == NULL) || ((*node)->oid < subnode->oid)))
{
subnode = *node;
}
node++;
i--;
}
if (subnode == NULL)
{
/* no further node found on this level, go one level up and start searching with index of current node*/
subnode_oid = node_stack[nsi]->node.oid + 1;
nsi--;
}
else
{
if (subnode->node_type == SNMP_NODE_TREE)
{
/* next is a tree node, go into it and start searching */
nsi++;
node_stack[nsi] = (const struct snmp_tree_node*)subnode;
subnode_oid = 0;
}
else
{
/* we found a leaf node -> fill oidret and return it */
snmp_oid_assign(oidret, mib->base_oid, mib->base_oid_len);
i = 1;
while (i <= nsi)
{
oidret->id[oidret->len] = node_stack[i]->node.oid;
oidret->len++;
i++;
}
oidret->id[oidret->len] = subnode->oid;
oidret->len++;
return subnode;
}
}
}
return NULL;
}
void
snmp_next_oid_init(struct snmp_next_oid_state *state,
const u32_t *start_oid, u8_t start_oid_len,
u32_t *next_oid_buf, u8_t next_oid_max_len)
{
state->start_oid = start_oid;
state->start_oid_len = start_oid_len;
state->next_oid = next_oid_buf;
state->next_oid_len = 0;
state->next_oid_max_len = next_oid_max_len;
state->status = SNMP_NEXT_OID_STATUS_NO_MATCH;
}
u8_t
snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len)
{
if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL)
{
u8_t start_oid_len = (oid_len < state->start_oid_len) ? oid_len : state->start_oid_len;
/* check passed OID is located behind start offset */
if (snmp_oid_compare(oid, oid_len, state->start_oid, start_oid_len) >= 0)
{
/* check if new oid is located closer to start oid than current closest oid */
if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) ||
(snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0))
{
return 1;
}
}
}
return 0;
}
u8_t
snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len, void* reference)
{
/* do not overwrite a fail result */
if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL)
{
/* check passed OID is located behind start offset */
if (snmp_oid_compare(oid, oid_len, state->start_oid, state->start_oid_len) > 0)
{
/* check if new oid is located closer to start oid than current closest oid */
if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) ||
(snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0))
{
if (oid_len <= state->next_oid_max_len)
{
SMEMCPY(state->next_oid, oid, oid_len * sizeof(u32_t));
state->next_oid_len = oid_len;
state->status = SNMP_NEXT_OID_STATUS_SUCCESS;
state->reference = reference;
return 1;
}
else
{
state->status = SNMP_NEXT_OID_STATUS_BUF_TO_SMALL;
}
}
}
}
return 0;
}
u8_t
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)
{
u8_t i;
if(oid_len != oid_ranges_len) {
return 0;
}
for(i=0; i<oid_ranges_len; i++)
{
if((oid_in[i] < oid_ranges[i].min) || (oid_in[i] > oid_ranges[i].max)) {
return 0;
}
}
return 1;
}
u8_t
snmp_set_test_ok(struct snmp_node_instance* instance, u16_t value_len, void* value)
{
LWIP_UNUSED_ARG(instance);
LWIP_UNUSED_ARG(value_len);
LWIP_UNUSED_ARG(value);
return SNMP_ERR_NOERROR;
}
/**
* Decodes BITS pseudotype value from ASN.1 OctetString.
*
* @note Because BITS pseudo type is encoded as OCTET STRING, it cannot directly
* be encoded/decoded by the agent. Instead call this function as required from
* get/test/set methods.
*
* @param buf points to a buffer holding the ASN1 octet string
* @param buf_len length of octet string
* @param bit_value decoded Bit value with Bit0 == LSB
* @return ERR_OK if successful, ERR_ARG if bit value contains more than 32 bit
*/
err_t
snmp_decode_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value)
{
u8_t b;
u8_t bits_processed = 0;
*bit_value = 0;
while (buf_len > 0) {
/* any bit set in this byte? */
if (*buf != 0x00) {
if (bits_processed >= 32) {
/* accept more than 4 bytes, but only when no bits are set */
return ERR_VAL;
}
b = *buf;
do {
if (b & 0x80) {
*bit_value |= (1 << bits_processed);
}
bits_processed++;
b <<= 1;
}
while ((bits_processed % 8) != 0);
} else {
bits_processed += 8;
}
buf_len--;
buf++;
}
return ERR_OK;
}
err_t
snmp_decode_truthvalue(const s32_t *asn1_value, u8_t *bool_value)
{
/* defined by RFC1443:
TruthValue ::= TEXTUAL-CONVENTION
STATUS current
DESCRIPTION
"Represents a boolean value."
SYNTAX INTEGER { true(1), false(2) }
*/
if ((asn1_value == NULL) || (bool_value == NULL)) {
return ERR_ARG;
}
if (*asn1_value == 1) {
*bool_value = 1;
} else if (*asn1_value == 2) {
*bool_value = 0;
} else {
return ERR_VAL;
}
return ERR_OK;
}
/**
* Encodes BITS pseudotype value into ASN.1 OctetString.
*
* @note Because BITS pseudo type is encoded as OCTET STRING, it cannot directly
* be encoded/decoded by the agent. Instead call this function as required from
* get/test/set methods.
*
* @param buf points to a buffer where the resulting ASN1 octet string is stored to
* @param buf_len max length of the bufffer
* @param bit_value Bit value to encode with Bit0 == LSB
* @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)
* @return number of bytes used from buffer to store the resulting OctetString
*/
u8_t
snmp_encode_bits(u8_t *buf, u32_t buf_len, u32_t bit_value, u8_t bit_count)
{
u8_t len = 0;
u8_t min_bytes = (bit_count + 7) / 8;
while ((buf_len > 0) && (bit_value != 0x00)) {
s8_t i = 7;
*buf = 0x00;
while (i >= 0) {
if (bit_value & 0x01) {
*buf |= 0x01;
}
if (i > 0) {
*buf <<= 1;
}
bit_value >>= 1;
i--;
}
buf++;
buf_len--;
len++;
}
if (len < min_bytes)
{
buf += len;
buf_len -= len;
while ((len < min_bytes) && (buf_len > 0))
{
*buf = 0x00;
buf++;
buf_len--;
len++;
}
}
return len;
}
u8_t
snmp_encode_truthvalue(s32_t *asn1_value, u32_t bool_value)
{
/* defined by RFC1443:
TruthValue ::= TEXTUAL-CONVENTION
STATUS current
DESCRIPTION
"Represents a boolean value."
SYNTAX INTEGER { true(1), false(2) }
*/
if (asn1_value == NULL) {
return 0;
}
if (bool_value) {
*asn1_value = 1; /* defined by RFC1443 */
} else {
*asn1_value = 2; /* defined by RFC1443 */
}
return sizeof(s32_t);
}
#endif /* LWIP_SNMP */

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#ifndef LWIP_HDR_APPS_SNMP_CORE_PRIV_H
#define LWIP_HDR_APPS_SNMP_CORE_PRIV_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_core.h"
#include "snmp_asn1.h"
#ifdef __cplusplus
extern "C" {
#endif
/* (outdated) SNMPv1 error codes
* shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request
*/
#define SNMP_ERR_NOSUCHNAME 2
#define SNMP_ERR_BADVALUE 3
#define SNMP_ERR_READONLY 4
/* error codes which are internal and shall not be used by MIBS
* shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request
*/
#define SNMP_ERR_TOOBIG 1
#define SNMP_ERR_AUTHORIZATIONERROR 16
#define SNMP_ERR_NOSUCHOBJECT SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT
#define SNMP_ERR_ENDOFMIBVIEW SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW
const struct snmp_node* snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len);
const struct snmp_node* snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret);
typedef u8_t (*snmp_validate_node_instance_method)(struct snmp_node_instance*, void*);
u8_t snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance);
u8_t 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);
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_CORE_PRIV_H */

2243
src/apps/snmp/snmp_mib2.c Normal file

File diff suppressed because it is too large Load Diff

1183
src/apps/snmp/snmp_msg.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -30,24 +30,22 @@
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
* Martin Hentschel <info@cl-soft.de>
*/
#ifndef LWIP_HDR_SNMP_MSG_H
#define LWIP_HDR_SNMP_MSG_H
#ifndef LWIP_HDR_APPS_SNMP_MSG_H
#define LWIP_HDR_APPS_SNMP_MSG_H
#include "lwip/apps/snmp_opts.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_structs.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#if LWIP_SNMP
#if SNMP_PRIVATE_MIB
/* When using a private MIB, you have to create a file 'private_mib.h' that contains
* a 'struct mib_array_node mib_private' which contains your MIB. */
#include "private_mib.h"
#endif
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "snmp_pbuf_stream.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
@ -64,249 +62,87 @@ extern "C" {
#define SNMP_TRAP_PORT 162
#endif
#define SNMP_ES_NOERROR 0
#define SNMP_ES_TOOBIG 1
#define SNMP_ES_NOSUCHNAME 2
#define SNMP_ES_BADVALUE 3
#define SNMP_ES_READONLY 4
#define SNMP_ES_GENERROR 5
#define SNMP_GENTRAP_COLDSTART 0
#define SNMP_GENTRAP_WARMSTART 1
#define SNMP_GENTRAP_AUTHFAIL 4
#define SNMP_GENTRAP_ENTERPRISESPC 6
/* version defines used in PDU */
#define SNMP_VERSION_1 0
#define SNMP_VERSION_2c 1
struct snmp_varbind
{
/* next pointer, NULL for last in list */
struct snmp_varbind *next;
/* previous pointer, NULL for first in list */
struct snmp_varbind *prev;
/* object identifier */
struct snmp_obj_id oid;
/* object identifier length (in s32_t) */
u8_t ident_len;
/* object identifier array */
s32_t *ident;
/* object value ASN1 type */
u8_t value_type;
/* value ASN1 type */
u8_t type;
/* object value length */
u16_t value_len;
/* object value */
void *value;
/* encoding varbind seq length length */
u8_t seqlenlen;
/* encoding object identifier length length */
u8_t olenlen;
/* encoding object value length length */
u8_t vlenlen;
/* encoding varbind seq length */
u16_t seqlen;
/* encoding object identifier length */
u16_t olen;
/* encoding object value length */
u16_t vlen;
};
struct snmp_varbind_root
struct snmp_varbind_enumerator
{
struct snmp_varbind *head;
struct snmp_varbind *tail;
/* number of variable bindings in list */
u8_t count;
/* encoding varbind-list seq length length */
u8_t seqlenlen;
/* encoding varbind-list seq length */
u16_t seqlen;
struct snmp_pbuf_stream pbuf_stream;
u16_t varbind_count;
};
/** output response message header length fields */
struct snmp_resp_header_lengths
typedef u8_t snmp_vb_enumerator_err_t;
#define SNMP_VB_ENUMERATOR_ERR_OK 0
#define SNMP_VB_ENUMERATOR_ERR_EOVB 1
#define SNMP_VB_ENUMERATOR_ERR_ASN1ERROR 2
#define SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH 3
void snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length);
snmp_vb_enumerator_err_t snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind);
struct snmp_request
{
/* encoding error-index length length */
u8_t erridxlenlen;
/* encoding error-status length length */
u8_t errstatlenlen;
/* encoding request id length length */
u8_t ridlenlen;
/* encoding pdu length length */
u8_t pdulenlen;
/* encoding community length length */
u8_t comlenlen;
/* encoding version length length */
u8_t verlenlen;
/* encoding sequence length length */
u8_t seqlenlen;
/* encoding error-index length */
u16_t erridxlen;
/* encoding error-status length */
u16_t errstatlen;
/* encoding request id length */
u16_t ridlen;
/* encoding pdu length */
u16_t pdulen;
/* encoding community length */
u16_t comlen;
/* encoding version length */
u16_t verlen;
/* encoding sequence length */
u16_t seqlen;
};
/** output response message header length fields */
struct snmp_trap_header_lengths
{
/* encoding timestamp length length */
u8_t tslenlen;
/* encoding specific-trap length length */
u8_t strplenlen;
/* encoding generic-trap length length */
u8_t gtrplenlen;
/* encoding agent-addr length length */
u8_t aaddrlenlen;
/* encoding enterprise-id length length */
u8_t eidlenlen;
/* encoding pdu length length */
u8_t pdulenlen;
/* encoding community length length */
u8_t comlenlen;
/* encoding version length length */
u8_t verlenlen;
/* encoding sequence length length */
u8_t seqlenlen;
/* encoding timestamp length */
u16_t tslen;
/* encoding specific-trap length */
u16_t strplen;
/* encoding generic-trap length */
u16_t gtrplen;
/* encoding agent-addr length */
u16_t aaddrlen;
/* encoding enterprise-id length */
u16_t eidlen;
/* encoding pdu length */
u16_t pdulen;
/* encoding community length */
u16_t comlen;
/* encoding version length */
u16_t verlen;
/* encoding sequence length */
u16_t seqlen;
};
/* Accepting new SNMP messages. */
#define SNMP_MSG_EMPTY 0
/* Search for matching object for variable binding. */
#define SNMP_MSG_SEARCH_OBJ 1
/* Perform SNMP operation on in-memory object.
Pass-through states, for symmetry only. */
#define SNMP_MSG_INTERNAL_GET_OBJDEF 2
#define SNMP_MSG_INTERNAL_GET_VALUE 3
#define SNMP_MSG_INTERNAL_SET_TEST 4
#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5
#define SNMP_MSG_INTERNAL_SET_VALUE 6
/* Perform SNMP operation on object located externally.
In theory this could be used for building a proxy agent.
Practical use is for an enterprise spc. app. gateway. */
#define SNMP_MSG_EXTERNAL_GET_OBJDEF 7
#define SNMP_MSG_EXTERNAL_GET_VALUE 8
#define SNMP_MSG_EXTERNAL_SET_TEST 9
#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10
#define SNMP_MSG_EXTERNAL_SET_VALUE 11
#define SNMP_COMMUNITY_STR_LEN 64
struct snmp_msg_pstat
{
/* lwIP local port (161) binding */
struct udp_pcb *pcb;
/* Communication handle */
void *handle;
/* source IP address */
ip_addr_t sip;
const ip_addr_t *source_ip;
/* source UDP port */
u16_t sp;
u16_t source_port;
/* incoming snmp version */
u8_t version;
/* community name (zero terminated) */
u8_t community[SNMP_MAX_COMMUNITY_STR_LEN + 1];
/* community string length (exclusive zero term) */
u16_t community_strlen;
/* request type */
u8_t rt;
u8_t request_type;
/* request ID */
s32_t rid;
s32_t request_id;
/* error status */
s32_t error_status;
/* error index */
s32_t error_index;
/* community name (zero terminated) */
u8_t community[SNMP_COMMUNITY_STR_LEN + 1];
/* community string length (exclusive zero term) */
u8_t com_strlen;
/* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */
u8_t state;
/* saved arguments for MSG_EXTERNAL_x */
const struct mib_external_node *ext_mib_node;
struct snmp_name_ptr ext_name_ptr;
struct obj_def ext_object_def;
struct snmp_obj_id ext_oid;
/* index into input variable binding list */
u8_t vb_idx;
/* ptr into input variable binding list */
struct snmp_varbind *vb_ptr;
/* list of variable bindings from input */
struct snmp_varbind_root invb;
/* list of variable bindings to output */
struct snmp_varbind_root outvb;
/* output response lengths used in ASN encoding */
struct snmp_resp_header_lengths rhl;
/* non-repeaters (getBulkRequest (SNMPv2c)) */
s32_t non_repeaters;
/* max-repetitions (getBulkRequest (SNMPv2c)) */
s32_t max_repetitions;
struct pbuf *inbound_pbuf;
struct snmp_varbind_enumerator inbound_varbind_enumerator;
u16_t inbound_varbind_offset;
u16_t inbound_varbind_len;
struct pbuf *outbound_pbuf;
struct snmp_pbuf_stream outbound_pbuf_stream;
u16_t outbound_pdu_offset;
u16_t outbound_error_status_offset;
u16_t outbound_error_index_offset;
u16_t outbound_varbind_offset;
u8_t value_buffer[SNMP_MAX_VALUE_SIZE];
};
struct snmp_msg_trap
{
/* lwIP local port (161) binding */
struct udp_pcb *pcb;
/* destination IP address in network order */
ip_addr_t dip;
/* source enterprise ID (sysObjectID) */
const struct snmp_obj_id *enterprise;
/* source IP address, raw network order format */
u8_t sip_raw[4];
/* source IP address length */
u8_t sip_raw_len;
/* generic trap code */
u32_t gen_trap;
/* specific trap code */
u32_t spc_trap;
/* timestamp */
u32_t ts;
/* list of variable bindings to output */
struct snmp_varbind_root outvb;
/* output trap lengths used in ASN encoding */
struct snmp_trap_header_lengths thl;
};
/** Agent Version constant, 0 = v1 oddity */
extern const s32_t snmp_version;
/** Agent community string */
extern const char *snmp_community;
#if SNMP_COMMUNITY_EXT
/** Agent community string for write access */
extern const char *snmp_community_write;
/** Agent community string for sending traps */
extern const char *snmp_community_trap;
#endif /* SNMP_COMMUNITY_EXT */
extern struct snmp_msg_trap trap_msg;
/** Varbind-list functions. */
struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u16_t len);
void snmp_varbind_free(struct snmp_varbind *vb);
void snmp_varbind_list_free(struct snmp_varbind_root *root);
void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb);
struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root);
/** Handle an internal (recv) or external (private response) event. */
err_t snmp_send_response(struct snmp_msg_pstat *m_stat);
err_t snmp_send_trap(s8_t generic_trap, const struct snmp_obj_id *eoid, s32_t specific_trap);
void snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port);
err_t snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port);
#ifdef __cplusplus
}
@ -314,4 +150,4 @@ err_t snmp_send_trap(s8_t generic_trap, const struct snmp_obj_id *eoid, s32_t sp
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_SNMP_MSG_H */
#endif /* LWIP_HDR_APPS_SNMP_MSG_H */

View File

@ -0,0 +1,97 @@
/**
* @file
* SNMP netconn frontend.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP && SNMP_USE_NETCONN
#include "lwip/api.h"
#include "lwip/udp.h"
#include "snmp_msg.h"
#include "lwip/sys.h"
/** SNMP netconn API worker thread */
static void
snmp_netconn_thread(void *arg)
{
struct netconn *conn;
struct netbuf *buf;
err_t err;
LWIP_UNUSED_ARG(arg);
conn = netconn_new(NETCONN_UDP);
LWIP_ERROR("snmp_netconn: invalid conn", (conn != NULL), return;);
//trap_msg.handle = conn;
//trap_msg.lip = &conn->pcb.udp->local_ip;
/* Bind to SNMP port with default IP address */
netconn_bind(conn, IP_ADDR_ANY, SNMP_IN_PORT);
do {
err = netconn_recv(conn, &buf);
if (err == ERR_OK) {
snmp_receive(conn, buf->p, &buf->addr, buf->port);
}
if(buf != NULL) {
netbuf_delete(buf);
}
} while(1);
}
err_t
snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port)
{
err_t result;
struct netbuf buf;
memset(&buf, 0, sizeof(buf));
buf.p = p;
result = netconn_sendto((struct netconn*)handle, &buf, dst, port);
return result;
}
/**
* Starts SNMP Agent.
*/
void
snmp_init(void)
{
sys_thread_new("snmp_netconn", snmp_netconn_thread, NULL, SNMP_STACK_SIZE, SNMP_THREAD_PRIO);
}
#endif /* LWIP_SNMP && SNMP_USE_NETCONN */

View File

@ -0,0 +1,246 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "snmp_pbuf_stream.h"
#include "lwip/def.h"
err_t
snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length)
{
pbuf_stream->offset = offset;
pbuf_stream->length = length;
// skip to matching buffer
while (offset >= p->len) {
offset -= p->len;
p = p->next;
if (p == NULL) {
return ERR_BUF;
}
}
pbuf_stream->pbuffer = p;
pbuf_stream->pbuf_len = p->len;
if (offset > 0) {
pbuf_stream->pbuf_len-= offset;
pbuf_stream->pData = (u8_t*)(p->payload) + offset;
} else {
pbuf_stream->pData = (u8_t*)(p->payload);
}
return ERR_OK;
}
err_t
snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data)
{
if (pbuf_stream->length == 0) {
return ERR_BUF;
}
if (pbuf_stream->pbuf_len == 0) {
/* we are at the end of current pbuf, skip to next */
pbuf_stream->pbuffer = pbuf_stream->pbuffer->next;
if ((pbuf_stream->pbuffer == NULL) || (pbuf_stream->pbuffer->len == 0)) {
return ERR_BUF;
}
pbuf_stream->pbuf_len = pbuf_stream->pbuffer->len;
pbuf_stream->pData = (u8_t*)(pbuf_stream->pbuffer->payload);
}
*data = *pbuf_stream->pData;
pbuf_stream->pData++;
pbuf_stream->pbuf_len--;
pbuf_stream->offset++;
pbuf_stream->length--;
return ERR_OK;
}
err_t
snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data)
{
if (pbuf_stream->length == 0) {
return ERR_BUF;
}
if (pbuf_stream->pbuf_len == 0) {
/* we are at the end of current pbuf, skip to next */
pbuf_stream->pbuffer = pbuf_stream->pbuffer->next;
if ((pbuf_stream->pbuffer == NULL) || (pbuf_stream->pbuffer->len == 0)) {
return ERR_BUF;
}
pbuf_stream->pbuf_len = pbuf_stream->pbuffer->len;
pbuf_stream->pData = (u8_t*)(pbuf_stream->pbuffer->payload);
}
*pbuf_stream->pData = data;
pbuf_stream->pData++;
pbuf_stream->pbuf_len--;
pbuf_stream->offset++;
pbuf_stream->length--;
return ERR_OK;
}
err_t
snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len)
{
if (pbuf_stream->length < buf_len) {
return ERR_BUF;
}
while (buf_len > 0) {
u16_t chunk_len;
if (pbuf_stream->pbuf_len == 0) {
/* we are at the end of current pbuf, skip to next */
pbuf_stream->pbuffer = pbuf_stream->pbuffer->next;
if ((pbuf_stream->pbuffer == NULL) || (pbuf_stream->pbuffer->len == 0)) {
return ERR_BUF;
}
pbuf_stream->pbuf_len = pbuf_stream->pbuffer->len;
pbuf_stream->pData = (u8_t*)(pbuf_stream->pbuffer->payload);
}
chunk_len = LWIP_MIN(buf_len, pbuf_stream->pbuf_len);
MEMCPY(pbuf_stream->pData, buf, chunk_len);
pbuf_stream->pData += chunk_len;
pbuf_stream->pbuf_len -= chunk_len;
pbuf_stream->offset += chunk_len;
pbuf_stream->length -= chunk_len;
buf_len -= chunk_len;
buf = (const u8_t*)buf + chunk_len;
}
return ERR_OK;
}
err_t
snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len)
{
if ((pbuf_stream == NULL) || (target_pbuf_stream == NULL)) {
return ERR_ARG;
}
if ((len > pbuf_stream->length) || (len > target_pbuf_stream->length)) {
return ERR_ARG;
}
if (len == 0) {
len = LWIP_MIN(pbuf_stream->length, target_pbuf_stream->length);
}
while (len > 0) {
u16_t chunk_len;
err_t err;
if (pbuf_stream->pbuf_len == 0) {
/* we are at the end of current pbuf, skip to next */
pbuf_stream->pbuffer = pbuf_stream->pbuffer->next;
if ((pbuf_stream->pbuffer == NULL) || (pbuf_stream->pbuffer->len == 0)) {
return ERR_BUF;
}
pbuf_stream->pbuf_len = pbuf_stream->pbuffer->len;
pbuf_stream->pData = (u8_t*)(pbuf_stream->pbuffer->payload);
}
chunk_len = LWIP_MIN(len, pbuf_stream->pbuf_len);
err = snmp_pbuf_stream_writebuf(target_pbuf_stream, pbuf_stream->pData, chunk_len);
if (err != ERR_OK) {
return err;
}
pbuf_stream->pData += chunk_len;
pbuf_stream->pbuf_len -= chunk_len;
pbuf_stream->offset += chunk_len;
pbuf_stream->length -= chunk_len;
len -= chunk_len;
}
return ERR_OK;
}
err_t
snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset)
{
if ((offset < 0) || (offset > pbuf_stream->length)) {
/* we cannot seek backwards or forward behind stream end */
return ERR_ARG;
}
pbuf_stream->offset += (u16_t)offset;
pbuf_stream->length -= (u16_t)offset;
// skipt to matching buffer
while (offset > pbuf_stream->pbuf_len) {
offset -= pbuf_stream->pbuf_len;
pbuf_stream->pbuffer = pbuf_stream->pbuffer->next;
if ((pbuf_stream->pbuffer == NULL) || (pbuf_stream->pbuffer->len == 0)) {
return ERR_BUF;
}
pbuf_stream->pbuf_len = pbuf_stream->pbuffer->len;
pbuf_stream->pData = (u8_t*)pbuf_stream->pbuffer->payload;
}
if (offset > 0) {
pbuf_stream->pbuf_len -= (u16_t)offset;
pbuf_stream->pData = pbuf_stream->pData + offset;
}
return ERR_OK;
}
err_t
snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset)
{
s32_t rel_offset = offset - pbuf_stream->offset;
return snmp_pbuf_stream_seek(pbuf_stream, rel_offset);
}
#endif /* LWIP_SNMP */

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#ifndef LWIP_HDR_APPS_SNMP_PBUF_STREAM_H
#define LWIP_HDR_APPS_SNMP_PBUF_STREAM_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP
#include "lwip/err.h"
#include "lwip/pbuf.h"
#ifdef __cplusplus
extern "C" {
#endif
struct snmp_pbuf_stream
{
struct pbuf* pbuffer;
u16_t pbuf_len;
u8_t* pData;
u16_t offset;
u16_t length;
};
err_t snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length);
err_t snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data);
err_t snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data);
err_t snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len);
err_t snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len);
err_t snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset);
err_t snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_PBUF_STREAM_H */

81
src/apps/snmp/snmp_raw.c Normal file
View File

@ -0,0 +1,81 @@
/**
* @file
* SNMP RAW API frontend.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP && SNMP_USE_RAW
#include "lwip/udp.h"
#include "snmp_msg.h"
/* UDP Protocol Control Block */
static struct udp_pcb *snmp_pcb;
/* lwIP UDP receive callback function */
static void
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
LWIP_UNUSED_ARG(arg);
snmp_receive(pcb, p, addr, port);
pbuf_free(p);
}
err_t
snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port)
{
err_t result = udp_sendto((struct udp_pcb*)handle, p, dst, port);
return result;
}
/**
* Starts SNMP Agent.
* Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.
*/
void
snmp_init(void)
{
snmp_pcb = udp_new();
if (snmp_pcb != NULL) {
//trap_msg.handle = snmp_pcb;
//trap_msg.lip = &snmp_pcb->local_ip;
udp_recv(snmp_pcb, snmp_recv, (void *)SNMP_IN_PORT);
udp_bind(snmp_pcb, IP_ADDR_ANY, SNMP_IN_PORT);
}
}
#endif /* LWIP_SNMP && SNMP_USE_RAW */

232
src/apps/snmp/snmp_scalar.c Normal file
View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_scalar.h"
#include "lwip/apps/snmp_core.h"
static u16_t snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value);
static snmp_err_t snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value);
static snmp_err_t snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value);
snmp_err_t
snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_scalar_node* scalar_node = (const struct snmp_scalar_node*)instance->node;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* scalar only has one dedicated instance: .0 */
if ((instance->instance_oid.len != 1) || (instance->instance_oid.id[0] != 0))
{
return SNMP_ERR_NOSUCHINSTANCE;
}
instance->access = scalar_node->access;
instance->asn1_type = scalar_node->asn1_type;
instance->get_value = scalar_node->get_value;
instance->set_test = scalar_node->set_test;
instance->set_value = scalar_node->set_value;
return SNMP_ERR_NOERROR;
}
snmp_err_t
snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
/* because our only instance is .0 we can only return a next instance if no instance oid is passed */
if (instance->instance_oid.len == 0)
{
instance->instance_oid.len = 1;
instance->instance_oid.id[0] = 0;
return snmp_scalar_get_instance(root_oid, root_oid_len, instance);
}
return SNMP_ERR_NOSUCHINSTANCE;
}
snmp_err_t
snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
if ((instance->instance_oid.len == 2) && (instance->instance_oid.id[1] == 0))
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes;
u32_t i = 0;
while (i < array_node->array_node_count)
{
if (array_node_def->oid == instance->instance_oid.id[0])
{
break;
}
array_node_def++;
i++;
}
if (i < array_node->array_node_count)
{
instance->access = array_node_def->access;
instance->asn1_type = array_node_def->asn1_type;
instance->get_value = snmp_scalar_array_get_value;
instance->set_test = snmp_scalar_array_set_test;
instance->set_value = snmp_scalar_array_set_value;
instance->reference.const_ptr = array_node_def;
return SNMP_ERR_NOERROR;
}
}
return SNMP_ERR_NOSUCHINSTANCE;
}
snmp_err_t
snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes;
const struct snmp_scalar_array_node_def* result = NULL;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
if ((instance->instance_oid.len == 0) && (array_node->array_node_count > 0))
{
/* return node with lowest OID */
u16_t i = 0;
result = array_node_def;
array_node_def++;
for (i = 1; i < array_node->array_node_count; i++)
{
if (array_node_def->oid < result->oid)
{
result = array_node_def;
}
array_node_def++;
}
}
else if (instance->instance_oid.len >= 1)
{
if (instance->instance_oid.len == 1)
{
/* if we have the requested OID we return its instance, otherwise we search for the next available */
u16_t i = 0;
while (i < array_node->array_node_count)
{
if (array_node_def->oid == instance->instance_oid.id[0])
{
result = array_node_def;
break;
}
array_node_def++;
i++;
}
}
if (result == NULL)
{
u32_t oid_dist = 0xFFFFFFFFUL;
u16_t i = 0;
array_node_def = array_node->array_nodes; /* may be already at the end when if case before was executed without result -> reinitialize to start */
while (i < array_node->array_node_count)
{
if ((array_node_def->oid > instance->instance_oid.id[0]) && ((u32_t)(array_node_def->oid - instance->instance_oid.id[0]) < oid_dist))
{
result = array_node_def;
oid_dist = array_node_def->oid - instance->instance_oid.id[0];
}
array_node_def++;
i++;
}
}
}
if (result == NULL)
{
/* nothing to return */
return SNMP_ERR_NOSUCHINSTANCE;
}
instance->instance_oid.len = 2;
instance->instance_oid.id[0] = result->oid;
instance->instance_oid.id[1] = 0;
instance->access = result->access;
instance->asn1_type = result->asn1_type;
instance->get_value = snmp_scalar_array_get_value;
instance->set_test = snmp_scalar_array_set_test;
instance->set_value = snmp_scalar_array_set_value;
instance->reference.const_ptr = result;
return SNMP_ERR_NOERROR;
}
static u16_t
snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
return array_node->get_value(array_node_def, value);
}
static snmp_err_t
snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
return array_node->set_test(array_node_def, value_len, value);
}
static snmp_err_t
snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
return array_node->set_value(array_node_def, value_len, value);
}
#endif /* LWIP_SNMP */

362
src/apps/snmp/snmp_table.c Normal file
View File

@ -0,0 +1,362 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_table.h"
snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE;
const struct snmp_table_node* table_node = (const struct snmp_table_node*)instance->node;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check min. length (fixed row entry definition, column, row instance oid with at least one entry */
/* fixed row entry always has oid 1 */
if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1))
{
/* search column */
const struct snmp_table_col_def* col_def = table_node->columns;
u16_t i = table_node->column_count;
while (i > 0)
{
if (col_def->index == instance->instance_oid.id[1])
{
break;
}
col_def++;
i--;
}
if (i > 0)
{
/* everything may be overwritten by get_cell_instance_method() in order to implement special handling for single columns/cells */
instance->asn1_type = col_def->asn1_type;
instance->access = col_def->access;
instance->get_value = table_node->get_value;
instance->set_test = table_node->set_test;
instance->set_value = table_node->set_value;
ret = table_node->get_cell_instance(
&(instance->instance_oid.id[1]),
&(instance->instance_oid.id[2]),
instance->instance_oid.len-2,
instance);
}
}
return ret;
}
snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_table_node* table_node = (const struct snmp_table_node*)instance->node;
const struct snmp_table_col_def* col_def;
struct snmp_obj_id row_oid;
u32_t column = 0;
snmp_err_t result;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check that first part of id is 0 or 1, referencing fixed row entry */
if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1))
{
return SNMP_ERR_NOSUCHINSTANCE;
}
if (instance->instance_oid.len > 1)
{
column = instance->instance_oid.id[1];
}
if (instance->instance_oid.len > 2)
{
snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2);
}
else
{
row_oid.len = 0;
}
instance->get_value = table_node->get_value;
instance->set_test = table_node->set_test;
instance->set_value = table_node->set_value;
/* resolve column and value */
do
{
u16_t i;
const struct snmp_table_col_def* next_col_def = NULL;
col_def = table_node->columns;
for (i=0; i<table_node->column_count; i++)
{
if (col_def->index == column)
{
next_col_def = col_def;
break;
}
else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index)))
{
next_col_def = col_def;
}
col_def++;
}
if (next_col_def == NULL)
{
/* no further column found */
return SNMP_ERR_NOSUCHINSTANCE;
}
instance->asn1_type = next_col_def->asn1_type;
instance->access = next_col_def->access;
result = table_node->get_next_cell_instance(
&next_col_def->index,
&row_oid,
instance);
if (result == SNMP_ERR_NOERROR)
{
col_def = next_col_def;
break;
}
row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */
column = next_col_def->index + 1;
}
while (1);
// build resulting oid
instance->instance_oid.len = 2;
instance->instance_oid.id[0] = 1;
instance->instance_oid.id[1] = col_def->index;
snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len);
return SNMP_ERR_NOERROR;
}
snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE;
const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)instance->node;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check min. length (fixed row entry definition, column, row instance oid with at least one entry */
/* fixed row entry always has oid 1 */
if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1))
{
ret = table_node->get_cell_value(
&(instance->instance_oid.id[1]),
&(instance->instance_oid.id[2]),
instance->instance_oid.len-2,
&instance->reference,
&instance->reference_len);
if (ret == SNMP_ERR_NOERROR)
{
/* search column */
const struct snmp_table_simple_col_def* col_def = table_node->columns;
u32_t i = table_node->column_count;
while (i > 0)
{
if (col_def->index == instance->instance_oid.id[1])
{
break;
}
col_def++;
i--;
}
if (i > 0)
{
instance->asn1_type = col_def->asn1_type;
instance->access = SNMP_NODE_INSTANCE_READ_ONLY;
instance->set_test = NULL;
instance->set_value = NULL;
switch (col_def->data_type)
{
case SNMP_VARIANT_VALUE_TYPE_U32: instance->get_value = snmp_table_extract_value_from_u32ref; break;
case SNMP_VARIANT_VALUE_TYPE_S32: instance->get_value = snmp_table_extract_value_from_s32ref; break;
case SNMP_VARIANT_VALUE_TYPE_PTR: // fall through
case SNMP_VARIANT_VALUE_TYPE_CONST_PTR: instance->get_value = snmp_table_extract_value_from_refconstptr; break;
default:
LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type));
return SNMP_ERR_GENERROR;
}
ret = SNMP_ERR_NOERROR;
}
else
{
ret = SNMP_ERR_NOSUCHINSTANCE;
}
}
}
return ret;
}
snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)instance->node;
const struct snmp_table_simple_col_def* col_def;
struct snmp_obj_id row_oid;
u32_t column = 0;
snmp_err_t result;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check that first part of id is 0 or 1, referencing fixed row entry */
if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1))
{
return SNMP_ERR_NOSUCHINSTANCE;
}
if (instance->instance_oid.len > 1)
{
column = instance->instance_oid.id[1];
}
if (instance->instance_oid.len > 2)
{
snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2);
}
else
{
row_oid.len = 0;
}
/* resolve column and value */
do
{
u32_t i;
const struct snmp_table_simple_col_def* next_col_def = NULL;
col_def = table_node->columns;
for (i=0; i<table_node->column_count; i++)
{
if (col_def->index == column)
{
next_col_def = col_def;
break;
}
else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index)))
{
next_col_def = col_def;
}
col_def++;
}
if (next_col_def == NULL)
{
/* no further column found */
return SNMP_ERR_NOSUCHINSTANCE;
}
result = table_node->get_next_cell_instance_and_value(
&next_col_def->index,
&row_oid,
&instance->reference,
&instance->reference_len);
if (result == SNMP_ERR_NOERROR)
{
col_def = next_col_def;
break;
}
row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */
column = next_col_def->index + 1;
}
while (1);
instance->asn1_type = col_def->asn1_type;
instance->access = SNMP_NODE_INSTANCE_READ_ONLY;
instance->set_test = NULL;
instance->set_value = NULL;
switch (col_def->data_type)
{
case SNMP_VARIANT_VALUE_TYPE_U32: instance->get_value = snmp_table_extract_value_from_u32ref; break;
case SNMP_VARIANT_VALUE_TYPE_S32: instance->get_value = snmp_table_extract_value_from_s32ref; break;
case SNMP_VARIANT_VALUE_TYPE_PTR: // fall through
case SNMP_VARIANT_VALUE_TYPE_CONST_PTR: instance->get_value = snmp_table_extract_value_from_refconstptr; break;
default:
LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type));
return SNMP_ERR_GENERROR;
}
// build resulting oid
instance->instance_oid.len = 2;
instance->instance_oid.id[0] = 1;
instance->instance_oid.id[1] = col_def->index;
snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len);
return SNMP_ERR_NOERROR;
}
u16_t
snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value)
{
s32_t *dst = (s32_t*)value;
*dst = instance->reference.s32;
return sizeof(*dst);
}
u16_t
snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value)
{
u32_t *dst = (u32_t*)value;
*dst = instance->reference.u32;
return sizeof(*dst);
}
u16_t
snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value)
{
SMEMCPY(value, instance->reference.const_ptr, instance->reference_len);
return (u16_t)instance->reference_len;
}
#endif /* LWIP_SNMP */

View File

@ -0,0 +1,230 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_threadsync.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/mem.h"
#include "lwip/sys.h"
struct threadsync_data
{
union {
snmp_err_t u8;
u16_t u16;
} retval;
union {
const u32_t *root_oid;
void *value;
} arg1;
union {
u8_t root_oid_len;
u16_t len;
} arg2;
const struct snmp_threadsync_node *threadsync_node;
struct snmp_node_instance proxy_instance;
};
static void
call_synced_function(struct threadsync_data *call_data, snmp_threadsync_called_fn fn)
{
sys_mutex_lock(&call_data->threadsync_node->locks->sem_usage_mutex);
call_data->threadsync_node->locks->sync_fn(fn, call_data);
sys_sem_wait(&call_data->threadsync_node->locks->sem);
sys_mutex_unlock(&call_data->threadsync_node->locks->sem_usage_mutex);
}
static void
threadsync_get_value_synced(void *ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->retval.u16 = call_data->proxy_instance.get_value(&call_data->proxy_instance, call_data->arg1.value);
sys_sem_signal(&call_data->threadsync_node->locks->sem);
}
static u16_t
threadsync_get_value(struct snmp_node_instance* instance, void* value)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
call_data->arg1.value = value;
call_synced_function(call_data, threadsync_get_value_synced);
return call_data->retval.u16;
}
static void
threadsync_set_test_synced(void *ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->retval.u8 = call_data->proxy_instance.set_test(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
sys_sem_signal(&call_data->threadsync_node->locks->sem);
}
static snmp_err_t
threadsync_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
call_data->arg1.value = value;
call_data->arg2.len = len;
call_synced_function(call_data, threadsync_set_test_synced);
return call_data->retval.u8;
}
static void
threadsync_set_value_synced(void *ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->retval.u8 = call_data->proxy_instance.set_value(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
sys_sem_signal(&call_data->threadsync_node->locks->sem);
}
static snmp_err_t
threadsync_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
call_data->arg1.value = value;
call_data->arg2.len = len;
call_synced_function(call_data, threadsync_set_value_synced);
return call_data->retval.u8;
}
static void
threadsync_release_instance_synced(void* ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->proxy_instance.release_instance(&call_data->proxy_instance);
sys_sem_signal(&call_data->threadsync_node->locks->sem);
}
static void
threadsync_release_instance(struct snmp_node_instance *instance)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
if(call_data->proxy_instance.release_instance != NULL) {
call_synced_function(call_data, threadsync_release_instance_synced);
}
mem_free(call_data);
}
static void
get_instance_synced(void* ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)call_data->proxy_instance.node;
call_data->retval.u8 = leaf->get_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance);
sys_sem_signal(&call_data->threadsync_node->locks->sem);
}
static void
get_next_instance_synced(void* ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)call_data->proxy_instance.node;
call_data->retval.u8 = leaf->get_next_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance);
sys_sem_signal(&call_data->threadsync_node->locks->sem);
}
static snmp_err_t
do_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance, snmp_threadsync_called_fn fn)
{
const struct snmp_threadsync_node *threadsync_node = (const struct snmp_threadsync_node*)instance->node;
struct threadsync_data *call_data;
if(threadsync_node->node.node.oid != threadsync_node->target->node.oid) {
LWIP_DEBUGF(SNMP_DEBUG, ("Sync node OID does not match target node OID"));
return SNMP_ERR_NOSUCHINSTANCE;
}
call_data = (struct threadsync_data*)mem_malloc(sizeof(struct threadsync_data));
if(call_data != NULL) {
memset(&call_data->proxy_instance, 0, sizeof(call_data->proxy_instance));
instance->reference.ptr = call_data;
snmp_oid_assign(&call_data->proxy_instance.instance_oid, instance->instance_oid.id, instance->instance_oid.len);
call_data->proxy_instance.node = &threadsync_node->target->node;
call_data->threadsync_node = threadsync_node;
call_data->arg1.root_oid = root_oid;
call_data->arg2.root_oid_len = root_oid_len;
call_synced_function(call_data, fn);
instance->access = call_data->proxy_instance.access;
instance->asn1_type = call_data->proxy_instance.asn1_type;
instance->release_instance = threadsync_release_instance;
instance->get_value = (call_data->proxy_instance.get_value != NULL)? threadsync_get_value : NULL;
instance->set_value = (call_data->proxy_instance.set_value != NULL)? threadsync_set_value : NULL;
instance->set_test = (call_data->proxy_instance.set_test != NULL)? threadsync_set_test : NULL;
snmp_oid_assign(&instance->instance_oid, call_data->proxy_instance.instance_oid.id, call_data->proxy_instance.instance_oid.len);
return call_data->retval.u8;
} else {
LWIP_DEBUGF(SNMP_DEBUG, ("Out of memory"));
return SNMP_ERR_NOSUCHINSTANCE;
}
}
snmp_err_t
snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
return do_sync(root_oid, root_oid_len, instance, get_instance_synced);
}
snmp_err_t
snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
return do_sync(root_oid, root_oid_len, instance, get_next_instance_synced);
}
void snmp_threadsync_init(struct snmp_threadsync_locks *locks, snmp_threadsync_synchronizer_fn sync_fn)
{
sys_mutex_new(&locks->sem_usage_mutex);
sys_sem_new(&locks->sem, 0);
locks->sync_fn = sync_fn;
}
#endif /* LWIP_SNMP */

413
src/apps/snmp/snmp_traps.c Normal file
View File

@ -0,0 +1,413 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel
* Christiaan Simons <christiaan.simons@axon.tv>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/ip_addr.h"
#define snmp_community_trap snmp_community
/** Agent community string for sending traps */
extern const char *snmp_community_trap;
struct snmp_trap_dst
{
/* destination IP address in network order */
ip_addr_t dip;
/* set to 0 when disabled, >0 when enabled */
u8_t enable;
};
static struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];
static u8_t snmp_auth_traps_enabled = 0;
/** TRAP message structure */
//struct snmp_msg_trap trap_msg;
/**
* Sets enable switch for this trap destination.
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
* @param enable switch if 0 destination is disabled >0 enabled.
*/
void
snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
{
if (dst_idx < SNMP_TRAP_DESTINATIONS) {
trap_dst[dst_idx].enable = enable;
}
}
/**
* Sets IPv4 address for this trap destination.
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
* @param dst IPv4 address in host order.
*/
void
snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst)
{
if (dst_idx < SNMP_TRAP_DESTINATIONS) {
ip_addr_set(&trap_dst[dst_idx].dip, dst);
}
}
void
snmp_set_auth_traps_enabled(u8_t enable)
{
snmp_auth_traps_enabled = enable;
}
u8_t
snmp_get_auth_traps_enabled(void)
{
return snmp_auth_traps_enabled;
}
/**
* Sends an generic or enterprise specific trap message.
*
* @param generic_trap is the trap code
* @param eoid points to enterprise object identifier
* @param specific_trap used for enterprise traps when generic_trap == 6
* @return ERR_OK when success, ERR_MEM if we're out of memory
*
* @note the caller is responsible for filling in outvb in the trap_msg
* @note the use of the enterprise identifier field
* is per RFC1215.
* Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps
* and .iso.org.dod.internet.private.enterprises.yourenterprise
* (sysObjectID) for specific traps.
*/
static err_t
snmp_send_trap(const struct snmp_obj_id *device_enterprise_oid, s32_t generic_trap, s32_t specific_trap)
{
LWIP_UNUSED_ARG(device_enterprise_oid);
LWIP_UNUSED_ARG(generic_trap);
LWIP_UNUSED_ARG(specific_trap);
return ERR_OK;
//struct snmp_trap_dst *td;
//struct netif *dst_if;
//const ip_addr_t* dst_ip;
//struct pbuf *p;
//u16_t i,tot_len;
//err_t err = ERR_OK;
//for (i = 0, td = &trap_dst[0]; i < SNMP_TRAP_DESTINATIONS; i++, td++) {
// if ((td->enable != 0) && !ip_addr_isany(&td->dip)) {
// /* network order trap destination */
// ip_addr_copy(trap_msg.dip, td->dip);
// /* lookup current source address for this dst */
// ip_route_get_local_ip(IP_IS_V6(trap_msg.lip), trap_msg.lip,
// &td->dip, dst_if, dst_ip);
// if ((dst_if != NULL) && (dst_ip != NULL)) {
// trap_msg.sip_raw_len = (IP_IS_V6_VAL(*dst_ip) ? 16 : 4);
// MEMCPY(trap_msg.sip_raw, dst_ip, trap_msg.sip_raw_len);
// if (device_enterprise_oid == NULL) {
// trap_msg.enterprise = snmp_get_device_enterprise_oid();
// } else {
// trap_msg.enterprise = device_enterprise_oid;
// }
// trap_msg.gen_trap = generic_trap;
// if (generic_trap == SNMP_GENTRAP_ENTERPRISE_SPECIFIC) {
// trap_msg.spc_trap = specific_trap;
// } else {
// trap_msg.spc_trap = 0;
// }
// MIB2_COPY_SYSUPTIME_TO(&trap_msg.ts);
// /* pass 0, calculate length fields */
// tot_len = snmp_varbind_list_sum(&trap_msg.outvb);
// tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
// /* allocate pbuf(s) */
// p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM);
// if (p != NULL) {
// u16_t ofs;
// /* pass 1, encode packet ino the pbuf(s) */
// ofs = snmp_trap_header_enc(&trap_msg, p);
// snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);
// snmp_stats.outtraps++;
// snmp_stats.outpkts++;
// /** send to the TRAP destination */
// snmp_sendto(trap_msg.handle, p, &trap_msg.dip, SNMP_TRAP_PORT);
// } else {
// err = ERR_MEM;
// }
// } else {
// /* routing error */
// err = ERR_RTE;
// }
// }
//}
//return err;
}
err_t
snmp_send_trap_generic(s32_t generic_trap)
{
return snmp_send_trap(NULL, generic_trap, 0);
}
err_t snmp_send_trap_specific(s32_t specific_trap)
{
return snmp_send_trap(NULL, SNMP_GENTRAP_ENTERPRISE_SPECIFIC, specific_trap);
}
void
snmp_coldstart_trap(void)
{
//trap_msg.outvb.head = NULL;
//trap_msg.outvb.tail = NULL;
//trap_msg.outvb.count = 0;
snmp_send_trap_generic(SNMP_GENTRAP_COLDSTART);
}
void
snmp_authfail_trap(void)
{
if (snmp_auth_traps_enabled != 0) {
//trap_msg.outvb.head = NULL;
//trap_msg.outvb.tail = NULL;
//trap_msg.outvb.count = 0;
snmp_send_trap_generic(SNMP_GENTRAP_AUTH_FAILURE);
}
}
//extern struct snmp_msg_trap trap_msg;
//struct snmp_msg_trap
//{
// /* Communication handle */
// void *handle;
// /* local IP address */
// ip_addr_t *lip;
// /* destination IP address */
// ip_addr_t dip;
//
// /* source enterprise ID (sysObjectID) */
// const struct snmp_obj_id *enterprise;
// /* source IP address, raw network order format */
// u8_t sip_raw[4];
// /* source IP address length */
// u8_t sip_raw_len;
// /* generic trap code */
// u32_t gen_trap;
// /* specific trap code */
// u32_t spc_trap;
// /* timestamp */
// u32_t ts;
// ///* list of variable bindings to output */
// //struct snmp_varbind_root outvb;
// ///* output trap lengths used in ASN encoding */
// //struct snmp_trap_header_lengths thl;
//};
/** output response message header length fields */
//struct snmp_trap_header_lengths
//{
// /* encoding timestamp length length */
// u8_t tslenlen;
// /* encoding specific-trap length length */
// u8_t strplenlen;
// /* encoding generic-trap length length */
// u8_t gtrplenlen;
// /* encoding agent-addr length length */
// u8_t aaddrlenlen;
// /* encoding enterprise-id length length */
// u8_t eidlenlen;
// /* encoding pdu length length */
// u8_t pdulenlen;
// /* encoding community length length */
// u8_t comlenlen;
// /* encoding version length length */
// u8_t verlenlen;
// /* encoding sequence length length */
// u8_t seqlenlen;
//
// /* encoding timestamp length */
// u16_t tslen;
// /* encoding specific-trap length */
// u16_t strplen;
// /* encoding generic-trap length */
// u16_t gtrplen;
// /* encoding agent-addr length */
// u16_t aaddrlen;
// /* encoding enterprise-id length */
// u16_t eidlen;
// /* encoding pdu length */
// u16_t pdulen;
// /* encoding community length */
// u16_t comlen;
// /* encoding version length */
// u16_t verlen;
// /* encoding sequence length */
// u16_t seqlen;
//};
/**
* Sums trap header field lengths from tail to head and
* returns trap_header_lengths for second encoding pass.
*
* @param vb_len varbind-list length
* @param thl points to returned header lengths
* @return the required length for encoding the trap header
*/
//static u16_t
//snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len)
//{
// u16_t tot_len;
// struct snmp_trap_header_lengths *thl;
//
// thl = &m_trap->thl;
// tot_len = vb_len;
//
// snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen);
// snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen);
// tot_len += 1 + thl->tslen + thl->tslenlen;
//
// snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen);
// snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen);
// tot_len += 1 + thl->strplen + thl->strplenlen;
//
// snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen);
// snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen);
// tot_len += 1 + thl->gtrplen + thl->gtrplenlen;
//
// thl->aaddrlen = m_trap->sip_raw_len;
// snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen);
// tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen;
//
// snmp_asn1_enc_oid_cnt(&m_trap->enterprise->id[0], m_trap->enterprise->len, &thl->eidlen);
// snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen);
// tot_len += 1 + thl->eidlen + thl->eidlenlen;
//
// thl->pdulen = tot_len;
// snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen);
// tot_len += 1 + thl->pdulenlen;
//
// thl->comlen = (u16_t)strlen(snmp_community_trap);
// snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen);
// tot_len += 1 + thl->comlenlen + thl->comlen;
//
// snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen);
// snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen);
// tot_len += 1 + thl->verlen + thl->verlenlen;
//
// thl->seqlen = tot_len;
// snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen);
// tot_len += 1 + thl->seqlenlen;
//
// return tot_len;
//}
/**
* Encodes trap header from head to tail.
*/
//static u16_t
//snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p)
//{
// u16_t ofs;
//
// ofs = 0;
// snmp_asn1_enc_type(p, ofs, SNMP_ASN1_TYPE_SEQUENCE);
// ofs += 1;
// snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen);
// ofs += m_trap->thl.seqlenlen;
//
// snmp_asn1_enc_type(p, ofs, SNMP_ASN1_TYPE_INTEGER);
// ofs += 1;
// snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen);
// ofs += m_trap->thl.verlenlen;
// snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version);
// ofs += m_trap->thl.verlen;
//
// snmp_asn1_enc_type(p, ofs, SNMP_ASN1_TYPE_OCTET_STRING);
// ofs += 1;
// snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen);
// ofs += m_trap->thl.comlenlen;
// snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (const u8_t *)&snmp_community_trap[0]);
// ofs += m_trap->thl.comlen;
//
// snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP));
// ofs += 1;
// snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen);
// ofs += m_trap->thl.pdulenlen;
//
// snmp_asn1_enc_type(p, ofs, SNMP_ASN1_TYPE_OBJECT_ID);
// ofs += 1;
// snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen);
// ofs += m_trap->thl.eidlenlen;
// snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]);
// ofs += m_trap->thl.eidlen;
//
// snmp_asn1_enc_type(p, ofs, SNMP_ASN1_TYPE_IPADDR);
// ofs += 1;
// snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen);
// ofs += m_trap->thl.aaddrlenlen;
// snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]);
// ofs += m_trap->thl.aaddrlen;
//
// snmp_asn1_enc_type(p, ofs, SNMP_ASN1_TYPE_INTEGER);
// ofs += 1;
// snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen);
// ofs += m_trap->thl.gtrplenlen;
// snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap);
// ofs += m_trap->thl.gtrplen;
//
// snmp_asn1_enc_type(p, ofs, SNMP_ASN1_TYPE_INTEGER);
// ofs += 1;
// snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen);
// ofs += m_trap->thl.strplenlen;
// snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap);
// ofs += m_trap->thl.strplen;
//
// snmp_asn1_enc_type(p, ofs, SNMP_ASN1_TYPE_TIMETICKS);
// ofs += 1;
// snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen);
// ofs += m_trap->thl.tslenlen;
// snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts);
// ofs += m_trap->thl.tslen;
//
// return ofs;
//}
#endif

View File

@ -28,6 +28,7 @@
* This file is part of the lwIP TCP/IP stack.
*
* Author: Leon Woestenberg <leon.woestenberg@axon.tv>
* Martin Hentschel <info@cl-soft.de>
*
*/
#ifndef LWIP_HDR_APPS_SNMP_H
@ -41,55 +42,60 @@ extern "C" {
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip.h"
/** fixed maximum length for object identifier type */
#define LWIP_SNMP_OBJ_ID_LEN 32
/** internal object identifier representation */
struct snmp_obj_id
{
u8_t len;
s32_t id[LWIP_SNMP_OBJ_ID_LEN];
};
#include "lwip/err.h"
#include "lwip/apps/snmp_core.h"
/** Agent setup, start listening to port 161. */
void snmp_init(void);
void snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs);
/**
* 'device enterprise oid' is used for 'device OID' field in trap PDU's (for identification of generating device)
* as well as for value returned by MIB-2 'sysObjectID' field (if internal MIB2 implementation is used).
* The 'device enterprise oid' shall point to an OID located under 'private-enterprises' branch (1.3.6.1.4.1.XXX). If a vendor
* wants to provide a custom object there, he has to get its own enterprise oid from IANA (http://www.iana.org). It
* is not allowed to use LWIP enterprise ID!
* In order to identify a specific device it is recommended to create a dedicated OID for each device type under its own
* enterprise oid.
* e.g.
* device a > 1.3.6.1.4.1.XXX(ent-oid).1(devices).1(device a)
* device b > 1.3.6.1.4.1.XXX(ent-oid).1(devices).2(device b)
* for more details see description of 'sysObjectID' field in RFC1213-MIB
*/
void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_oid);
const struct snmp_obj_id* snmp_get_device_enterprise_oid(void);
void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable);
void snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst);
#define SNMP_GENTRAP_COLDSTART 0
#define SNMP_GENTRAP_WARMSTART 1
#define SNMP_GENTRAP_LINKDOWN 2
#define SNMP_GENTRAP_LINKUP 3
#define SNMP_GENTRAP_AUTH_FAILURE 4
#define SNMP_GENTRAP_EGP_NEIGHBOR_LOSS 5
#define SNMP_GENTRAP_ENTERPRISE_SPECIFIC 6
err_t snmp_send_trap_generic(s32_t generic_trap);
err_t snmp_send_trap_specific(s32_t specific_trap);
#define SNMP_AUTH_TRAPS_DISABLED 0
#define SNMP_AUTH_TRAPS_ENABLED 1
void snmp_set_auth_traps_enabled(u8_t enable);
u8_t snmp_get_auth_traps_enabled(void);
const char * snmp_get_community(void);
void snmp_set_community(const char * const community);
#if SNMP_COMMUNITY_EXT
const char * snmp_get_community_write(void);
const char * snmp_get_community_trap(void);
void snmp_set_community(const char * const community);
void snmp_set_community_write(const char * const community);
void snmp_set_community_trap(const char * const community);
#endif /* SNMP_COMMUNITY_EXT */
/* system */
void snmp_set_sysdescr(const u8_t* str, const u8_t* len);
void snmp_set_sysobjid(const struct snmp_obj_id *oid);
void snmp_get_sysobjid_ptr(const struct snmp_obj_id **oid);
void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen, u8_t bufsize);
void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen, u8_t bufsize);
void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen, u8_t bufsize);
void snmp_set_snmpenableauthentraps(u8_t *value);
void snmp_msg_event(u8_t request_id);
void snmp_coldstart_trap(void);
void snmp_authfail_trap(void);
#else
/* LWIP_SNMP support not available */
/* define everything to be empty */
/* system */
#define snmp_set_sysdescr(str, len)
#define snmp_set_sysobjid(oid)
#define snmp_get_sysobjid_ptr(oid)
#define snmp_set_syscontact(ocstr, ocstrlen, bufsize)
#define snmp_set_sysname(ocstr, ocstrlen, bufsize)
#define snmp_set_syslocation(ocstr, ocstrlen, bufsize)
#define snmp_set_snmpenableauthentraps(value)
typedef void (*snmp_write_callback_fct)(const u32_t* oid, u8_t oid_len, void* callback_arg);
void snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg);
#endif /* LWIP_SNMP */
#ifdef __cplusplus

View File

@ -1,105 +0,0 @@
/**
* @file
* Abstract Syntax Notation One (ISO 8824, 8825) codec.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
*/
#ifndef LWIP_HDR_APPS_SNMP_ASN1_H
#define LWIP_HDR_APPS_SNMP_ASN1_H
#include "lwip/apps/snmp_opts.h"
#include "lwip/err.h"
#include "lwip/pbuf.h"
#include "lwip/apps/snmp.h"
#if LWIP_SNMP
#ifdef __cplusplus
extern "C" {
#endif
#define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */
#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */
#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */
#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */
#define SNMP_ASN1_PRIMIT (0) /* (!0x20) */
/* universal tags (from ASN.1 spec.) */
#define SNMP_ASN1_INTEG 2
#define SNMP_ASN1_OC_STR 4
#define SNMP_ASN1_NUL 5
#define SNMP_ASN1_OBJ_ID 6
#define SNMP_ASN1_SEQ 16
/* application specific (SNMP) tags (from SNMPv2-SMI) */
#define SNMP_ASN1_IPADDR 0 /* [APPLICATION 0] IMPLICIT OCTET STRING (SIZE (4)) */
#define SNMP_ASN1_COUNTER 1 /* [APPLICATION 1] IMPLICIT INTEGER (0..4294967295) => u32_t */
#define SNMP_ASN1_GAUGE 2 /* [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) => u32_t */
#define SNMP_ASN1_TIMETICKS 3 /* [APPLICATION 3] IMPLICIT INTEGER (0..4294967295) => u32_t */
#define SNMP_ASN1_OPAQUE 4 /* [APPLICATION 4] IMPLICIT OCTET STRING */
#define SNMP_ASN1_COUNTER64 6 /* [APPLICATION 6] IMPLICIT INTEGER (0..18446744073709551615) */
/* context specific (SNMP) tags (from SNMP spec. RFC1157) */
#define SNMP_ASN1_PDU_GET_REQ 0
#define SNMP_ASN1_PDU_GET_NEXT_REQ 1
#define SNMP_ASN1_PDU_GET_RESP 2
#define SNMP_ASN1_PDU_SET_REQ 3
#define SNMP_ASN1_PDU_TRAP 4
err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type);
err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length);
err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value);
err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value);
err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid);
err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw);
void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);
void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);
void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
void snmp_asn1_enc_oid_cnt(u16_t ident_len, const s32_t *ident, u16_t *octets_needed);
err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type);
err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length);
err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value);
err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value);
err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u16_t ident_len, const s32_t *ident);
err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, const u8_t *raw);
err_t snmp_asn1_dec_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value);
u8_t snmp_asn1_enc_bits(u8_t *buf, u32_t buf_len, u32_t bit_value);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_ASN1_H */

View File

@ -0,0 +1,349 @@
/**
* @file
* Generic MIB tree structures.
*
* @todo namespace prefixes
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
* Martin Hentschel <info@cl-soft.de>
*/
#ifndef LWIP_HDR_APPS_SNMP_CORE_H
#define LWIP_HDR_APPS_SNMP_CORE_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
/* basic ASN1 defines */
#define SNMP_ASN1_CLASS_UNIVERSAL 0x00
#define SNMP_ASN1_CLASS_APPLICATION 0x40
#define SNMP_ASN1_CLASS_CONTEXT 0x80
#define SNMP_ASN1_CLASS_PRIVATE 0xC0
#define SNMP_ASN1_CONTENTTYPE_PRIMITIVE 0x00
#define SNMP_ASN1_CONTENTTYPE_CONSTRUCTED 0x20
/* universal tags (from ASN.1 spec.) */
#define SNMP_ASN1_UNIVERSAL_END_OF_CONTENT 0
#define SNMP_ASN1_UNIVERSAL_INTEGER 2
#define SNMP_ASN1_UNIVERSAL_OCTET_STRING 4
#define SNMP_ASN1_UNIVERSAL_NULL 5
#define SNMP_ASN1_UNIVERSAL_OBJECT_ID 6
#define SNMP_ASN1_UNIVERSAL_SEQUENCE_OF 16
/* application specific (SNMP) tags (from SNMPv2-SMI) */
#define SNMP_ASN1_APPLICATION_IPADDR 0 /* [APPLICATION 0] IMPLICIT OCTET STRING (SIZE (4)) */
#define SNMP_ASN1_APPLICATION_COUNTER 1 /* [APPLICATION 1] IMPLICIT INTEGER (0..4294967295) => u32_t */
#define SNMP_ASN1_APPLICATION_GAUGE 2 /* [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) => u32_t */
#define SNMP_ASN1_APPLICATION_TIMETICKS 3 /* [APPLICATION 3] IMPLICIT INTEGER (0..4294967295) => u32_t */
#define SNMP_ASN1_APPLICATION_OPAQUE 4 /* [APPLICATION 4] IMPLICIT OCTET STRING */
#define SNMP_ASN1_APPLICATION_COUNTER64 6 /* [APPLICATION 6] IMPLICIT INTEGER (0..18446744073709551615) */
/* context specific (SNMP) tags (from RFC 1905) */
#define SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_INSTANCE 1
/* full ASN1 type defines */
#define SNMP_ASN1_TYPE_END_OF_CONTENT (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_END_OF_CONTENT)
#define SNMP_ASN1_TYPE_INTEGER (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_INTEGER)
#define SNMP_ASN1_TYPE_OCTET_STRING (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_OCTET_STRING)
#define SNMP_ASN1_TYPE_NULL (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_NULL)
#define SNMP_ASN1_TYPE_OBJECT_ID (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_OBJECT_ID)
#define SNMP_ASN1_TYPE_SEQUENCE (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_UNIVERSAL_SEQUENCE_OF)
#define SNMP_ASN1_TYPE_IPADDR (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_IPADDR)
#define SNMP_ASN1_TYPE_COUNTER (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_COUNTER)
#define SNMP_ASN1_TYPE_GAUGE (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_GAUGE)
#define SNMP_ASN1_TYPE_TIMETICKS (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_TIMETICKS)
#define SNMP_ASN1_TYPE_OPAQUE (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_OPAQUE)
#define SNMP_ASN1_TYPE_COUNTER64 (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_COUNTER64)
typedef u8_t snmp_err_t;
/* error codes predefined by SNMP prot. */
#define SNMP_ERR_NOERROR 0
/*
outdated v1 error codes. do not use anmore!
#define SNMP_ERR_NOSUCHNAME 2 // use SNMP_ERR_NOSUCHINSTANCE instead
#define SNMP_ERR_BADVALUE 3 // use SNMP_ERR_WRONGTYPE,SNMP_ERR_WRONGLENGTH,SNMP_ERR_WRONGENCODING or SNMP_ERR_WRONGVALUE instead
#define SNMP_ERR_READONLY 4 // use SNMP_ERR_NOTWRITABLE instead
*/
#define SNMP_ERR_GENERROR 5
#define SNMP_ERR_NOACCESS 6
#define SNMP_ERR_WRONGTYPE 7
#define SNMP_ERR_WRONGLENGTH 8
#define SNMP_ERR_WRONGENCODING 9
#define SNMP_ERR_WRONGVALUE 10
#define SNMP_ERR_NOCREATION 11
#define SNMP_ERR_INCONSISTENTVALUE 12
#define SNMP_ERR_RESOURCEUNAVAILABLE 13
#define SNMP_ERR_COMMITFAILED 14
#define SNMP_ERR_UNDOFAILED 15
#define SNMP_ERR_NOTWRITABLE 17
#define SNMP_ERR_INCONSISTENTNAME 18
#define SNMP_VARBIND_EXCEPTION_OFFSET 0xF0
#define SNMP_VARBIND_EXCEPTION_MASK 0x0F
#define SNMP_ERR_NOSUCHINSTANCE SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_INSTANCE
/** internal object identifier representation */
struct snmp_obj_id
{
u8_t len;
u32_t id[SNMP_MAX_OBJ_ID_LEN];
};
struct snmp_obj_id_const_ref
{
u8_t len;
const u32_t* id;
};
extern const struct snmp_obj_id_const_ref snmp_zero_dot_zero; /* administrative identifier from SNMPv2-SMI */
union snmp_variant_value
{
void* ptr;
const void* const_ptr;
u32_t u32;
s32_t s32;
};
#define SNMP_VARIANT_VALUE_TYPE_U32 0
#define SNMP_VARIANT_VALUE_TYPE_S32 1
#define SNMP_VARIANT_VALUE_TYPE_PTR 2
#define SNMP_VARIANT_VALUE_TYPE_CONST_PTR 3
/**
SNMP MIB node types
tree node is the only node the stack can process in order to walk the tree,
all other nodes are assumed to be leaf nodes.
This cannot be an enum because users may want to define their own node types.
*/
#define SNMP_NODE_TREE 0x00
/* predefined leaf node types */
#define SNMP_NODE_SCALAR 0x01
#define SNMP_NODE_SCALAR_ARRAY 0x02
#define SNMP_NODE_TABLE 0x03
#define SNMP_NODE_THREADSYNC 0x04
/** node "base class" layout, the mandatory fields for a node */
struct snmp_node
{
/** one out of SNMP_NODE_TREE or any leaf node type (like SNMP_NODE_SCALAR) */
u8_t node_type;
/** the number assigned to this node which used as part of the full OID */
u32_t oid;
};
/* SNMP node instance access types */
typedef enum {
SNMP_NODE_INSTANCE_ACCESS_READ = 1,
SNMP_NODE_INSTANCE_ACCESS_WRITE = 2,
SNMP_NODE_INSTANCE_READ_ONLY = SNMP_NODE_INSTANCE_ACCESS_READ,
SNMP_NODE_INSTANCE_READ_WRITE = (SNMP_NODE_INSTANCE_ACCESS_READ | SNMP_NODE_INSTANCE_ACCESS_WRITE),
SNMP_NODE_INSTANCE_WRITE_ONLY = SNMP_NODE_INSTANCE_ACCESS_WRITE,
SNMP_NODE_INSTANCE_NOT_ACCESSIBLE = 0
} snmp_access_t;
struct snmp_node_instance;
typedef u16_t (*node_instance_get_value_method)(struct snmp_node_instance*, void*);
typedef snmp_err_t (*node_instance_set_test_method)(struct snmp_node_instance*, u16_t, void*);
typedef snmp_err_t (*node_instance_set_value_method)(struct snmp_node_instance*, u16_t, void*);
typedef void (*node_instance_release_method)(struct snmp_node_instance*);
#define SNMP_GET_VALUE_RAW_DATA 0x8000
struct snmp_node_instance
{
/** prefilled with the node, get_instance() is called on; may be changed by user to any value to pass an arbitrary node between calls to get_instance() and get_value/test_value/set_value */
const struct snmp_node* node;
/** prefilled with the instance id requested; for get_instance() this is the exact oid requested; for get_next_instance() this is the relative starting point, stack expects relative oid of next node here */
struct snmp_obj_id instance_oid;
/** ASN type for this object (see snmp_asn1.h for definitions) */
u8_t asn1_type;
/** one out of instance access types defined above (SNMP_NODE_INSTANCE_READ_ONLY,...) */
snmp_access_t access;
/** returns object value for the given object identifier */
node_instance_get_value_method get_value;
/** tests length and/or range BEFORE setting */
node_instance_set_test_method set_test;
/** sets object value, only called when set_test() was successful */
node_instance_set_value_method set_value;
/** called in any case when the instance is not required anymore by stack (useful for freeing memory allocated in get_instance/get_next_instance methods) */
node_instance_release_method release_instance;
/** reference to pass arbitrary value between calls to get_instance() and get_value/test_value/set_value */
union snmp_variant_value reference;
/** see reference (if reference is a pointer, the length of underlying data may be stored here or anything else) */
u32_t reference_len;
};
struct snmp_tree_node
{
/* inherited "base class" members */
struct snmp_node node;
u16_t subnode_count;
const struct snmp_node* const *subnodes;
};
#define SNMP_CREATE_TREE_NODE(oid, subnodes) \
{{ SNMP_NODE_TREE, (oid) }, \
(u16_t)LWIP_ARRAYSIZE(subnodes), (subnodes) }
#define SNMP_CREATE_EMPTY_TREE_NODE(oid) \
{{ SNMP_NODE_TREE, (oid) }, \
0, NULL }
struct snmp_leaf_node
{
/* inherited "base class" members */
struct snmp_node node;
u8_t (*get_instance)(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
u8_t (*get_next_instance)(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
};
/* represents a single mib with its base oid and root node */
struct snmp_mib
{
const u32_t *base_oid;
u8_t base_oid_len;
const struct snmp_node *root_node;
};
#define SNMP_MIB_CREATE(oid_list, root_node) { (oid_list), (u8_t)LWIP_ARRAYSIZE(oid_list), root_node }
/** OID range structure */
struct snmp_oid_range
{
u32_t min;
u32_t max;
};
/** checks if incoming OID length and values are in allowed ranges */
u8_t 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);
/** state for next_oid_init / next_oid_check functions */
struct snmp_next_oid_state
{
const u32_t* start_oid;
u8_t start_oid_len;
u32_t* next_oid;
u8_t next_oid_len;
u8_t next_oid_max_len;
u8_t status;
void* reference;
};
#define SNMP_NEXT_OID_STATUS_SUCCESS 0
#define SNMP_NEXT_OID_STATUS_NO_MATCH 1
#define SNMP_NEXT_OID_STATUS_BUF_TO_SMALL 2
/** initialize struct next_oid_state using this function before passing it to next_oid_check */
void snmp_next_oid_init(struct snmp_next_oid_state *state,
const u32_t *start_oid, u8_t start_oid_len,
u32_t *next_oid_buf, u8_t next_oid_max_len);
/** checks if the passed incomplete OID may be a possible candidate for snmp_next_oid_check();
this methid is intended if the complete OID is not yet known but it is very expensive to build it up,
so it is possible to test the starting part before building up the complete oid and pass it to snmp_next_oid_check()*/
u8_t snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len);
/** 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 */
u8_t snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len, void* reference);
void snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len);
void snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len);
void snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len);
void snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len);
u8_t snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len);
s8_t snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len);
u8_t snmp_oid_to_ip(const u32_t *oid, ip4_addr_t *ip);
void snmp_ip_to_oid(const ip4_addr_t *ip, u32_t *oid);
u8_t snmp_set_test_ok(struct snmp_node_instance* instance, u16_t value_len, void* value); /* generic function which can be used if test is always successful */
err_t snmp_decode_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value);
err_t snmp_decode_truthvalue(const s32_t *asn1_value, u8_t *bool_value);
u8_t snmp_encode_bits(u8_t *buf, u32_t buf_len, u32_t bit_value, u8_t bit_count);
u8_t snmp_encode_truthvalue(s32_t *asn1_value, u32_t bool_value);
struct snmp_statistics
{
u32_t inpkts;
u32_t outpkts;
u32_t inbadversions;
u32_t inbadcommunitynames;
u32_t inbadcommunityuses;
u32_t inasnparseerrs;
u32_t intoobigs;
u32_t innosuchnames;
u32_t inbadvalues;
u32_t inreadonlys;
u32_t ingenerrs;
u32_t intotalreqvars;
u32_t intotalsetvars;
u32_t ingetrequests;
u32_t ingetnexts;
u32_t insetrequests;
u32_t ingetresponses;
u32_t intraps;
u32_t outtoobigs;
u32_t outnosuchnames;
u32_t outbadvalues;
u32_t outgenerrs;
u32_t outgetrequests;
u32_t outgetnexts;
u32_t outsetrequests;
u32_t outgetresponses;
u32_t outtraps;
};
extern struct snmp_statistics snmp_stats;
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_CORE_H */

View File

@ -0,0 +1,79 @@
/**
* @file
* MIB2 callback functions called from throughout the stack to integrate a MIB2
* into lwIP (together with MIB2_STATS).
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
*
*/
#ifndef LWIP_HDR_APPS_SNMP_MIB2_H
#define LWIP_HDR_APPS_SNMP_MIB2_H
#include "lwip/apps/snmp_opts.h"
#ifdef __cplusplus
extern "C" {
#endif
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#if SNMP_LWIP_MIB2
#include "lwip/apps/snmp_core.h"
extern const struct snmp_mib mib2;
#if SNMP_USE_NETCONN
#include "lwip/apps/snmp_threadsync.h"
void snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void* arg);
extern struct snmp_threadsync_locks snmp_mib2_lwip_locks;
#endif
#ifndef SNMP_SYSSERVICES
#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2))
#endif
void snmp_mib2_set_sysdescr(const u8_t* str, const u16_t* len); /* read-only be defintion */
void snmp_mib2_set_syscontact(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize);
void snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen);
void snmp_mib2_set_sysname(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize);
void snmp_mib2_set_sysname_readonly(const u8_t *ocstr, const u16_t *ocstrlen);
void snmp_mib2_set_syslocation(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize);
void snmp_mib2_set_syslocation_readonly(const u8_t *ocstr, const u16_t *ocstrlen);
#endif /* SNMP_LWIP_MIB2 */
#endif /* LWIP_SNMP */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_APPS_SNMP_MIB2_H */

View File

@ -29,17 +29,11 @@
* Author: Dirk Ziegelmeier
*
*/
#ifndef LWIP_HDR_APPS_SNMP_OPTS_H
#define LWIP_HDR_APPS_SNMP_OPTS_H
#ifndef LWIP_HDR_SNMP_OPTS_H
#define LWIP_HDR_SNMP_OPTS_H
#include "lwip/opt.h"
/*
----------------------------------
---------- SNMP options ----------
----------------------------------
*/
/**
* LWIP_SNMP==1: This enables the lwIP SNMP agent. UDP must be available
* for SNMP transport.
@ -53,14 +47,47 @@
#endif
/**
* SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will
* allow. At least one request buffer is required.
* Does not have to be changed unless external MIBs answer request asynchronously
* SNMP_USE_NETCONN: Use netconn API instead of raw API.
* Makes SNMP agent run in a worker thread, so blocking operations
* can be done in MIB calls.
*/
#ifndef SNMP_CONCURRENT_REQUESTS
#define SNMP_CONCURRENT_REQUESTS 1
#ifndef SNMP_USE_NETCONN
#define SNMP_USE_NETCONN 0
#endif
/**
* SNMP_USE_RAW: Use raw API.
* SNMP agent does not run in a worker thread, so blocking operations
* should not be done in MIB calls.
*/
#ifndef SNMP_USE_RAW
#define SNMP_USE_RAW 1
#endif
#if SNMP_USE_NETCONN && SNMP_USE_RAW
#error SNMP stack can use only one of the APIs {raw, netconn}
#endif
#if LWIP_SNMP && !SNMP_USE_NETCONN && !SNMP_USE_RAW
#error SNMP stack needs a receive API and UDP {raw, netconn}
#endif
#if SNMP_USE_NETCONN
/**
* SNMP_STACK_SIZE: Stack size of SNMP worker thread
*/
#ifndef SNMP_STACK_SIZE
#define SNMP_STACK_SIZE DEFAULT_THREAD_STACKSIZE
#endif
/**
* SNMP_THREAD_PRIO: SNMP worker thread priority
*/
#ifndef SNMP_THREAD_PRIO
#define SNMP_THREAD_PRIO DEFAULT_THREAD_PRIO
#endif
#endif /* SNMP_USE_NETCONN */
/**
* SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap
* destination is required
@ -69,15 +96,6 @@
#define SNMP_TRAP_DESTINATIONS 1
#endif
/**
* SNMP_PRIVATE_MIB:
* When using a private MIB, you have to create a file 'private_mib.h' that contains
* a 'struct mib_array_node mib_private' which contains your MIB.
*/
#ifndef SNMP_PRIVATE_MIB
#define SNMP_PRIVATE_MIB 0
#endif
/**
* Only allow SNMP write actions that are 'safe' (e.g. disabling netifs is not
* a safe action and disabled when SNMP_SAFE_REQUESTS = 1).
@ -88,28 +106,26 @@
#endif
/**
* The maximum length of strings used. This affects the size of
* MEMP_SNMP_VALUE elements.
* The maximum length of strings used.
*/
#ifndef SNMP_MAX_OCTET_STRING_LEN
#define SNMP_MAX_OCTET_STRING_LEN 127
#endif
/**
* The maximum depth of the SNMP tree.
* With private MIBs enabled, this depends on your MIB!
* This affects the size of MEMP_SNMP_VALUE elements.
* The maximum number of Sub ID's inside an object identifier.
* Indirectly this also limits the maximum depth of SNMP tree.
*/
#ifndef SNMP_MAX_TREE_DEPTH
#define SNMP_MAX_TREE_DEPTH 15
#ifndef SNMP_MAX_OBJ_ID_LEN
#define SNMP_MAX_OBJ_ID_LEN 32
#endif
/**
* The size of the MEMP_SNMP_VALUE elements, normally calculated from
* SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH.
* The maximum size of a value.
*/
#ifndef SNMP_MAX_VALUE_SIZE
#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH))
#define SNMP_MIN_VALUE_SIZE (2 * sizeof(u32_t*)) // size required to store the basic types (8 bytes for counter64)
#define SNMP_MAX_VALUE_SIZE LWIP_MAX(LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN), sizeof(u32_t)*(SNMP_MAX_OBJ_ID_LEN)), SNMP_MIN_VALUE_SIZE)
#endif
/**
@ -120,16 +136,9 @@
#define SNMP_COMMUNITY "public"
#endif
/**
* Set this to 1 to enable support for dedicated write-access and trap communities.
*/
#ifndef SNMP_COMMUNITY_EXT
#define SNMP_COMMUNITY_EXT 0
#endif
#if SNMP_COMMUNITY_EXT
/**
* The snmp write-access community.
* Set this community to "" in order to disallow any write access.
*/
#ifndef SNMP_COMMUNITY_WRITE
#define SNMP_COMMUNITY_WRITE "private"
@ -141,48 +150,43 @@
#ifndef SNMP_COMMUNITY_TRAP
#define SNMP_COMMUNITY_TRAP "public"
#endif
#endif /* SNMP_COMMUNITY_EXT */
/**
* SNMP_NUM_NODE: the number of leafs in the SNMP tree.
* The maximum length of community string.
* If community names shall be adjusted at runtime via snmp_set_community() calls,
* enter here the possible maximum length (+1 for terminating null character).
*/
#ifndef SNMP_NUM_NODE
#define SNMP_NUM_NODE 50
#ifndef SNMP_MAX_COMMUNITY_STR_LEN
#define SNMP_MAX_COMMUNITY_STR_LEN LWIP_MAX(LWIP_MAX(sizeof(SNMP_COMMUNITY), sizeof(SNMP_COMMUNITY_WRITE)), sizeof(SNMP_COMMUNITY_TRAP))
#endif
/**
* SNMP_NUM_ROOTNODE: the number of branches in the SNMP tree.
* Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least!
* The OID identifiying the device. This may be the enterprise OID itself or any OID located below it in tree.
*/
#ifndef SNMP_NUM_ROOTNODE
#define SNMP_NUM_ROOTNODE 30
#ifndef SNMP_DEVICE_ENTERPRISE_OID
/**
* IANA assigned enterprise ID for lwIP is 26381
* @see http://www.iana.org/assignments/enterprise-numbers
*
* @note this enterprise ID is assigned to the lwIP project,
* all object identifiers living under this ID are assigned
* by the lwIP maintainers!
* @note don't change this define, use snmp_set_device_enterprise_oid()
*
* If you need to create your own private MIB you'll need
* to apply for your own enterprise ID with IANA:
* http://www.iana.org/numbers.html
*/
#define SNMP_LWIP_ENTERPRISE_OID 26381
#define SNMP_DEVICE_ENTERPRISE_OID {1, 3, 6, 1, 4, 1, SNMP_LWIP_ENTERPRISE_OID}
#define SNMP_DEVICE_ENTERPRISE_OID_LEN 7
#endif
/**
* SNMP_NUM_VARBIND: influences the number of concurrent requests:
* 2 of these are used per request (1 for input, 1 for output), so this needs
* to be increased only if you want to support concurrent requests or multiple
* variables per request/response.
* SNMP_DEBUG: Enable debugging for SNMP messages.
*/
#ifndef SNMP_NUM_VARBIND
#define SNMP_NUM_VARBIND 2
#endif
/**
* SNMP_NUM_VALUE: the number of OID or values concurrently used
* (does not have to be changed normally) - >=3 of these are used per request
* (1 for the value read and 2 for OIDs - input and output on getnext, or more
* if you want to support multiple varibles per request/response)
*/
#ifndef SNMP_NUM_VALUE
#define SNMP_NUM_VALUE 3
#endif
/**
* SNMP_MSG_DEBUG: Enable debugging for SNMP messages.
*/
#ifndef SNMP_MSG_DEBUG
#define SNMP_MSG_DEBUG LWIP_DBG_OFF
#ifndef SNMP_DEBUG
#define SNMP_DEBUG LWIP_DBG_OFF
#endif
/**
@ -192,4 +196,54 @@
#define SNMP_MIB_DEBUG LWIP_DBG_OFF
#endif
#endif /* LWIP_HDR_APPS_SNMP_OPTS_H */
/**
* Indicates if the MIB2 implementation of LWIP SNMP stack is used.
*/
#ifndef SNMP_LWIP_MIB2
#define SNMP_LWIP_MIB2 LWIP_SNMP
#endif
/**
* Value return for sysDesc field of MIB2.
*/
#ifndef SNMP_LWIP_MIB2_SYSDESC
#define SNMP_LWIP_MIB2_SYSDESC "lwIP"
#endif
/**
* Value return for sysName field of MIB2.
* To make sysName field settable, call snmp_mib2_set_sysname() to provide the necessary buffers.
*/
#ifndef SNMP_LWIP_MIB2_SYSNAME
#define SNMP_LWIP_MIB2_SYSNAME "FQDN-unk"
#endif
/**
* Value return for sysContact field of MIB2.
* To make sysContact field settable, call snmp_mib2_set_syscontact() to provide the necessary buffers.
*/
#ifndef SNMP_LWIP_MIB2_SYSCONTACT
#define SNMP_LWIP_MIB2_SYSCONTACT ""
#endif
/**
* Value return for sysLocation field of MIB2.
* To make sysLocation field settable, call snmp_mib2_set_syslocation() to provide the necessary buffers.
*/
#ifndef SNMP_LWIP_MIB2_SYSLOCATION
#define SNMP_LWIP_MIB2_SYSLOCATION ""
#endif
/**
* This value is used to limit the repetitions processed in GetBulk requests (value == 0 means no limitation).
* This may be useful to limit the load for a single request.
* According to SNMP RFC 1905 it is allowed to not return all requested variables from a GetBulk request if system load would be too high.
* so the effect is that the client will do more requests to gather all data.
* For the stack this could be useful in case that SNMP processing is done in TCP/IP thread. In this situation a request with many
* repetitions could block the thread for a longer time. Setting limit here will keep the stack more responsive.
*/
#ifndef SNMP_LWIP_GETBULK_MAX_REPETITIONS
#define SNMP_LWIP_GETBULK_MAX_REPETITIONS 0
#endif
#endif /* SNMP_LWIP_MIB2 */

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#ifndef LWIP_HDR_APPS_SNMP_SCALAR_H
#define LWIP_HDR_APPS_SNMP_SCALAR_H
#include "lwip/apps/snmp_opts.h"
#include "lwip/apps/snmp_core.h"
#ifdef __cplusplus
extern "C" {
#endif
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
/* basic scalar node */
struct snmp_scalar_node
{
/* inherited "base class" members */
struct snmp_leaf_node node;
u8_t asn1_type;
snmp_access_t access;
node_instance_get_value_method get_value;
node_instance_set_test_method set_test;
node_instance_set_value_method set_value;
};
snmp_err_t snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
snmp_err_t snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
#define SNMP_SCALAR_CREATE_NODE(oid, access, asn1_type, get_value_method, set_test_method, set_value_method) \
{{{ SNMP_NODE_SCALAR, (oid) }, \
snmp_scalar_get_instance, \
snmp_scalar_get_next_instance }, \
(asn1_type), (access), (get_value_method), (set_test_method), (set_value_method) }
#define SNMP_SCALAR_CREATE_NODE_READONLY(oid, asn1_type, get_value_method) SNMP_SCALAR_CREATE_NODE(oid, SNMP_NODE_INSTANCE_READ_ONLY, asn1_type, get_value_method, NULL, NULL)
/* scalar array node - a tree node which contains scalars only as children */
struct snmp_scalar_array_node_def
{
u32_t oid;
u8_t asn1_type;
snmp_access_t access;
};
typedef u16_t (*snmp_scalar_array_get_value_method)(const struct snmp_scalar_array_node_def*, void*);
typedef snmp_err_t (*snmp_scalar_array_set_test_method)(const struct snmp_scalar_array_node_def*, u16_t, void*);
typedef snmp_err_t (*snmp_scalar_array_set_value_method)(const struct snmp_scalar_array_node_def*, u16_t, void*);
struct snmp_scalar_array_node
{
/* inherited "base class" members */
struct snmp_leaf_node node;
u16_t array_node_count;
const struct snmp_scalar_array_node_def* array_nodes;
snmp_scalar_array_get_value_method get_value;
snmp_scalar_array_set_test_method set_test;
snmp_scalar_array_set_value_method set_value;
};
snmp_err_t snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
snmp_err_t snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
#define SNMP_SCALAR_CREATE_ARRAY_NODE(oid, array_nodes, get_value_method, set_test_method, set_value_method) \
{{{ SNMP_NODE_SCALAR_ARRAY, (oid) }, \
snmp_scalar_array_get_instance, \
snmp_scalar_array_get_next_instance }, \
(u16_t)LWIP_ARRAYSIZE(array_nodes), (array_nodes), (get_value_method), (set_test_method), (set_value_method) }
#endif /* LWIP_SNMP */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_APPS_SNMP_SCALAR_H */

View File

@ -1,271 +0,0 @@
/**
* @file
* Generic MIB tree structures.
*
* @todo namespace prefixes
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
*/
#ifndef LWIP_HDR_APPS_SNMP_STRUCTS_H
#define LWIP_HDR_APPS_SNMP_STRUCTS_H
#include "lwip/opt.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp.h"
#include "lwip/memp.h"
LWIP_MEMPOOL_PROTOTYPE(SNMP_ROOTNODE);
LWIP_MEMPOOL_PROTOTYPE(SNMP_NODE);
#if SNMP_PRIVATE_MIB
/* When using a private MIB, you have to create a file 'private_mib.h' that contains
* a 'struct mib_array_node mib_private' which contains your MIB. */
#include "private_mib.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* MIB object instance */
#define MIB_OBJECT_NONE 0
#define MIB_OBJECT_SCALAR 1
#define MIB_OBJECT_TAB 2
/* MIB access types */
#define MIB_ACCESS_READ 1
#define MIB_ACCESS_WRITE 2
/* MIB object access */
#define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ
#define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE)
#define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE
#define MIB_OBJECT_NOT_ACCESSIBLE 0
/** object definition returned by (get_object_def)() */
struct obj_def
{
/* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */
u8_t instance;
/* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */
u8_t access;
/* ASN type for this object */
u8_t asn_type;
/* length of instance part of supplied object identifier */
u8_t id_inst_len;
/* instance part of supplied object identifier */
s32_t *id_inst_ptr;
};
struct snmp_name_ptr
{
u8_t ident_len;
s32_t *ident;
};
/** MIB const scalar (.0) node */
#define MIB_NODE_SC 0x01
/** MIB const array node */
#define MIB_NODE_AR 0x02
/** MIB list root node (memp_malloced from RAM) */
#define MIB_NODE_LR 0x04
/** MIB node for external objects */
#define MIB_NODE_EX 0x05
/** node "base class" layout, the mandatory fields for a node */
struct mib_node
{
/** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */
u8_t node_type;
};
/** derived node for scalars .0 index */
struct mib_scalar_node
{
/* inherited "base class" members */
struct mib_node node;
/** returns struct obj_def for the given object identifier */
void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
/** returns object value for the given object identifier */
u16_t (*get_value)(struct obj_def *od, void *value);
/** tests length and/or range BEFORE setting */
u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
/** sets object value, only to be called when set_test() */
void (*set_value)(struct obj_def *od, u16_t len, void *value);
};
/** describes an array entry (objid/node pair) */
struct mib_array_node_entry
{
s32_t objid;
const struct mib_node *nptr;
};
/** derived node, points to a fixed size array
of sub-identifiers plus a 'child' pointer */
struct mib_array_node
{
/* inherited "base class" members */
struct mib_node node;
/* additional struct members */
u16_t maxlength;
const struct mib_array_node_entry *entries;
};
struct mib_list_node
{
struct mib_list_node *prev;
struct mib_list_node *next;
s32_t objid;
struct mib_node *nptr;
};
/** derived node, points to a doubly linked list
of sub-identifiers plus a 'child' pointer */
struct mib_list_rootnode
{
/* inherited "base class" members */
struct mib_scalar_node scalar;
/* additional struct members */
struct mib_list_node *head;
struct mib_list_node *tail;
/* counts list nodes in list */
u16_t count;
};
/** derived node, has access functions for mib object in external memory or device
using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */
struct mib_external_node
{
/* inherited "base class" members */
struct mib_node node;
/* additional struct members */
/** points to an external (in memory) record of some sort of addressing
information, passed to and interpreted by the functions below */
void* addr_inf;
/** tree levels under this node */
u8_t tree_levels;
/** number of objects at this level */
u16_t (*level_length)(void* addr_inf, u8_t level);
/** compares object sub identifier with external id
return zero when equal, nonzero when unequal */
s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id);
void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id);
/** async Questions */
void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident);
void (*get_value_q)(u8_t rid, struct obj_def *od);
void (*set_test_q)(u8_t rid, struct obj_def *od);
void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value);
/** async Answers */
void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od);
u16_t (*get_value_a)(u8_t rid, struct obj_def *od, void *value);
u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);
void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);
/** async Panic Close (agent returns error reply,
e.g. used for external transaction cleanup) */
void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident);
void (*get_value_pc)(u8_t rid, struct obj_def *od);
void (*set_test_pc)(u8_t rid, struct obj_def *od);
void (*set_value_pc)(u8_t rid, struct obj_def *od);
};
/** export MIB tree from mib2.c */
extern const struct mib_array_node internet;
/** dummy function pointers for non-leaf MIB nodes from mib2.c */
void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
u16_t noleafs_get_value(struct obj_def *od, void *value);
u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value);
void noleafs_set_value(struct obj_def *od, u16_t len, void *value);
void snmp_oidtoip(s32_t *ident, ip4_addr_t *ip);
void snmp_iptooid(const ip4_addr_t *ip, s32_t *ident);
void snmp_ifindextonetif(s32_t ifindex, struct netif **netif);
void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx);
struct mib_list_node* snmp_mib_ln_alloc(s32_t id);
void snmp_mib_ln_free(struct mib_list_node *ln);
struct mib_list_rootnode* snmp_mib_lrn_alloc(void);
void snmp_mib_lrn_free(struct mib_list_rootnode *lrn);
s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn);
s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn);
struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n);
const struct mib_node* snmp_search_tree(const struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np);
const struct mib_node* snmp_expand_tree(const struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);
u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident);
u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);
/* SNMP stack internal MIB2 statistics */
void mib2_inc_snmpinpkts(void);
void mib2_inc_snmpoutpkts(void);
void mib2_inc_snmpinbadversions(void);
void mib2_inc_snmpinbadcommunitynames(void);
void mib2_inc_snmpinbadcommunityuses(void);
void mib2_inc_snmpinasnparseerrs(void);
void mib2_inc_snmpintoobigs(void);
void mib2_inc_snmpinnosuchnames(void);
void mib2_inc_snmpinbadvalues(void);
void mib2_inc_snmpinreadonlys(void);
void mib2_inc_snmpingenerrs(void);
void mib2_add_snmpintotalreqvars(u8_t value);
void mib2_add_snmpintotalsetvars(u8_t value);
void mib2_inc_snmpingetrequests(void);
void mib2_inc_snmpingetnexts(void);
void mib2_inc_snmpinsetrequests(void);
void mib2_inc_snmpingetresponses(void);
void mib2_inc_snmpintraps(void);
void mib2_inc_snmpouttoobigs(void);
void mib2_inc_snmpoutnosuchnames(void);
void mib2_inc_snmpoutbadvalues(void);
void mib2_inc_snmpoutgenerrs(void);
void mib2_inc_snmpoutgetrequests(void);
void mib2_inc_snmpoutgetnexts(void);
void mib2_inc_snmpoutsetrequests(void);
void mib2_inc_snmpoutgetresponses(void);
void mib2_inc_snmpouttraps(void);
void mib2_get_snmpgrpid_ptr(const struct snmp_obj_id **oid);
void mib2_get_snmpenableauthentraps(u8_t *value);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_STRUCTS_H */

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#ifndef LWIP_HDR_APPS_SNMP_TABLE_H
#define LWIP_HDR_APPS_SNMP_TABLE_H
#include "lwip/apps/snmp_opts.h"
#include "lwip/apps/snmp_core.h"
#ifdef __cplusplus
extern "C" {
#endif
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
/* default (customizable) read/write table */
struct snmp_table_col_def
{
u32_t index;
u8_t asn1_type;
snmp_access_t access;
};
struct snmp_table_node
{
/* inherited "base class" members */
struct snmp_leaf_node node;
u16_t column_count;
const struct snmp_table_col_def* columns;
snmp_err_t (*get_cell_instance)(const u32_t* column, const u32_t* row_oid, const u8_t row_oid_len, struct snmp_node_instance* cell_instance);
snmp_err_t (*get_next_cell_instance)(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance);
/** returns object value for the given object identifier */
node_instance_get_value_method get_value;
/** tests length and/or range BEFORE setting */
node_instance_set_test_method set_test;
/** sets object value, only called when set_test() was successful */
node_instance_set_value_method set_value;
};
snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
#define SNMP_TABLE_CREATE(oid, columns, get_cell_instance_method, get_next_cell_instance_method, get_value_method, set_test_method, set_value_method) \
{{{ SNMP_NODE_TABLE, (oid) }, \
snmp_table_get_instance, \
snmp_table_get_next_instance }, \
(u16_t)LWIP_ARRAYSIZE(columns), (columns), \
(get_cell_instance_method), (get_next_cell_instance_method), \
(get_value_method), (set_test_method), (set_value_method)}
#define SNMP_TABLE_GET_COLUMN_FROM_OID(oid) ((oid)[1]) /* first array value is (fixed) row entry (fixed to 1) and 2nd value is column, follow3ed by instance */
/* simple read-only table */
struct snmp_table_simple_col_def
{
u32_t index;
u8_t asn1_type;
u8_t data_type; /* any of SNMP_VARIANT_VALUE_TYPE_*, depending of what union member is used to store the value*/
};
struct snmp_table_simple_node
{
/* inherited "base class" members */
struct snmp_leaf_node node;
u16_t column_count;
const struct snmp_table_simple_col_def* columns;
snmp_err_t (*get_cell_value)(const u32_t* column, const u32_t* row_oid, const u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len);
snmp_err_t (*get_next_cell_instance_and_value)(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len);
};
snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
#define SNMP_TABLE_CREATE_SIMPLE(oid, columns, get_cell_value_method, get_next_cell_instance_and_value_method) \
{{{ SNMP_NODE_TABLE, (oid) }, \
snmp_table_simple_get_instance, \
snmp_table_simple_get_next_instance }, \
(u16_t)LWIP_ARRAYSIZE(columns), (columns), (get_cell_value_method), (get_next_cell_instance_and_value_method) }
u16_t snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value);
u16_t snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value);
u16_t snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value);
#endif /* LWIP_SNMP */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_APPS_SNMP_TABLE_H */

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
*
*/
#ifndef LWIP_HDR_APPS_SNMP_THREADSYNC_H
#define LWIP_HDR_APPS_SNMP_THREADSYNC_H
#include "lwip/apps/snmp_opts.h"
#ifdef __cplusplus
extern "C" {
#endif
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_core.h"
#include "lwip/sys.h"
typedef void (*snmp_threadsync_called_fn)(void* arg);
typedef void (*snmp_threadsync_synchronizer_fn)(snmp_threadsync_called_fn fn, void* arg);
struct snmp_threadsync_locks
{
sys_sem_t sem;
sys_mutex_t sem_usage_mutex;
snmp_threadsync_synchronizer_fn sync_fn;
};
/* thread sync node */
struct snmp_threadsync_node
{
/* inherited "base class" members */
struct snmp_leaf_node node;
const struct snmp_leaf_node *target;
struct snmp_threadsync_locks *locks;
};
snmp_err_t snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
snmp_err_t snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance);
#define SNMP_CREATE_THREAD_SYNC_NODE(oid, target, locks) \
{{{ SNMP_NODE_THREADSYNC, (oid) }, \
snmp_threadsync_get_instance, \
snmp_threadsync_get_next_instance }, \
(target), \
(locks) }
void snmp_threadsync_init(struct snmp_threadsync_locks *locks, snmp_threadsync_synchronizer_fn sync_fn);
#endif /* LWIP_SNMP */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_APPS_SNMP_THREADSYNC_H */