Initial commit. Expirimental code, please note this is not yet fully functional.

This commit is contained in:
christiaans 2006-07-07 09:49:31 +00:00
parent 6b2979027e
commit 333c3f18c0
7 changed files with 3540 additions and 0 deletions

614
src/core/snmp/asn1_dec.c Normal file
View File

@ -0,0 +1,614 @@
/**
* @file
* [EXPIRIMENTAL] 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/opt.h"
#include "lwip/snmp_asn1.h"
#if LWIP_SNMP
/**
* 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 successfull, 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 = 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, upto 64k
* @return ERR_OK if successfull, 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 = 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 = 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 = 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 = 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 successfull, 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 = 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 = 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 = 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 successfull, 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;
u8_t sign;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = 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)
{
*value &= *msg_ptr;
}
else
{
*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 = p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
if (sign)
{
*value &= *msg_ptr;
}
else
{
*value |= *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 successfull, 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;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr += ofs - base;
if ((len > 1) && (*msg_ptr == 0x2B))
{
s32_t *oid_ptr;
/* we have compressed 1.3 (iso.org) Z = (X * 40) + Y */
len--;
/* proceed to .dod */
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
oid->len = 0;
oid_ptr = &oid->id[0];
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 = 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 = 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;
}
}
else
{
/* length <= 1 OR prefix not 1.3 (iso.org) */
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 successfull, 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 = 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 = 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;
}
}
#endif /* LWIP_SNMP */

583
src/core/snmp/asn1_enc.c Normal file
View File

@ -0,0 +1,583 @@
/**
* @file
* [EXPIRIMENTAL] 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/opt.h"
#include "lwip/snmp_asn1.h"
#if LWIP_SNMP
/**
* 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(u8_t ident_len, s32_t *ident, u16_t *octets_needed)
{
s32_t sub_id;
u8_t cnt;
cnt = 0;
while(ident_len > 0)
{
ident_len--;
sub_id = *ident;
sub_id >>= 7;
cnt++;
while(sub_id > 0)
{
sub_id >>= 7;
cnt++;
}
ident++;
}
/* one extra for compressed iso.dod. prefix */
cnt++;
*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 successfull, 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 = 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 successfull, ERR_ARG if we can't (or won't) encode
*
* @todo also add octets_used instead of compares??
* @todo encode "type" in this function as well??
*/
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 = p->payload;
msg_ptr += ofs - base;
if (length < 0x80)
{
*msg_ptr = 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 = p->payload;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
*msg_ptr = 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 = p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
if (i == 0)
{
/* least significant length octet */
*msg_ptr = length;
}
else
{
/* most significant length octet */
*msg_ptr = 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 successfull, 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, u8_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 = 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 = p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
while (octets_needed > 1)
{
octets_needed--;
*msg_ptr = 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 = p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
/* (only) one least significant octet */
*msg_ptr = 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 successfull, 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, u8_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 = p->payload;
msg_ptr += ofs - base;
while (octets_needed > 1)
{
octets_needed--;
*msg_ptr = 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 = p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
/* (only) one least significant octet */
*msg_ptr = 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 successfull, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, 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 = p->payload;
msg_ptr += ofs - base;
/* add compressed prefix .iso.dod */
*msg_ptr = 0x2b;
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
while (ident_len > 0)
{
s32_t sub_id;
u8_t shift;
ident_len--;
sub_id = *ident;
shift = 28;
while(shift > 0)
{
u8_t code;
code = sub_id >> shift;
if (code != 0)
{
*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 = 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 = 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 successfull, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, 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 = 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 = p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
/* copy last octet */
*msg_ptr = *raw;
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
#endif /* LWIP_SNMP */

593
src/core/snmp/mib2.c Normal file
View File

@ -0,0 +1,593 @@
/**
* @file
* [EXPIRIMENTAL] Management Information Base II (RFC1213) objects and 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 "arch/cc.h"
#include "lwip/opt.h"
#include "lwip/snmp.h"
#include "lwip/snmp_asn1.h"
/* #include "lwip/snmp_structs.h" */
#if LWIP_SNMP
#ifndef SNMP_ENTERPRISE_ID
/**
* 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 (contact Christiaan Simons)!
*
* 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_ENTERPRISE_ID 26381
#endif
#ifndef SNMP_SYSOBJID_LEN
#define SNMP_SYSOBJID_LEN 5
#endif
#ifndef SNMP_SYSOBJID
#define SNMP_SYSOBJID {6, 1, 4, 1, SNMP_ENTERPRISE_ID}
#endif
/** @todo MIB-tree will be inserted here */
/** .iso.org.dod.internet.mgmt.mib-2.sysObjectID */
const struct snmp_obj_id sysobjid = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID};
/** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */
const struct snmp_obj_id snmpgrp_id = {5,{6,1,2,1,11}};
/* mib-2.system counter(s) */
static u32_t sysuptime;
/* mib-2.interfaces counter(s) */
static u32_t ifinoctets,
ifinucastpkts,
ifinnucastpkts,
ifindiscards,
ifoutoctets,
ifoutucastpkts,
ifoutnucastpkts,
ifoutdiscards;
/* mib-2.ip counter(s) */
static u32_t ipindelivers,
ipinreceives,
ipindiscards,
ipoutdiscards,
ipoutrequests,
ipunknownprotos;
/* mib-2.icmp counter(s) */
static u32_t icmpinmsgs,
icmpinerrors,
icmpindestunreachs,
icmpintimeexcds,
icmpinparmprobs,
icmpinsrcquenchs,
icmpinredirects,
icmpinechos,
icmpinechoreps,
icmpintimestamps,
icmpintimestampreps,
icmpinaddrmasks,
icmpinaddrmaskreps,
icmpoutmsgs,
icmpouterrors,
icmpoutdestunreachs,
icmpouttimeexcds,
icmpoutparmprobs,
icmpoutsrcquenchs,
icmpoutredirects,
icmpoutechos,
icmpoutechoreps,
icmpouttimestamps,
icmpouttimestampreps,
icmpoutaddrmasks,
icmpoutaddrmaskreps;
/* mib-2.tcp counter(s) */
static u32_t tcpactiveopens,
tcppassiveopens,
tcpattemptfails,
tcpestabresets,
tcpcurrestab,
tcpinsegs,
tcpoutsegs,
tcpretranssegs,
tcpinerrs,
tcpoutrsts;
/* mib-2.udp counter(s) */
static u32_t udpindatagrams,
udpnoports,
udpinerrors,
udpoutdatagrams;
/* mib-2.snmp counter(s) */
static u32_t snmpinpkts,
snmpoutpkts,
snmpinbadversions,
snmpinbadcommunitynames,
snmpinbadcommunityuses,
snmpinasnparseerrs,
snmpintoobigs,
snmpinnosuchnames,
snmpinbadvalues,
snmpinreadonlys,
snmpingenerrs,
snmpintotalreqvars,
snmpintotalsetvars,
snmpingetrequests,
snmpingetnexts,
snmpinsetrequests,
snmpingetresponses,
snmpintraps,
snmpouttoobigs,
snmpoutnosuchnames,
snmpoutbadvalues,
snmpoutgenerrs,
snmpoutgetrequests,
snmpoutgetnexts,
snmpoutsetrequests,
snmpoutgetresponses,
snmpouttraps;
/* prototypes of the following functions are in lwip/src/include/lwip/snmp.h */
/**
* Must be called at regular 10 msec interval from a timer interrupt
* or signal handler depending on your runtime environment.
*/
void snmp_inc_sysuptime(void)
{
sysuptime++;
}
void snmp_get_sysuptime(u32_t *value)
{
*value = sysuptime;
}
void snmp_get_sysobjid(const struct snmp_obj_id **oid)
{
*oid = &sysobjid;
}
void snmp_add_ifinoctets(u32_t value)
{
ifinoctets += value;
}
void snmp_inc_ifinucastpkts(void)
{
ifinucastpkts++;
}
void snmp_inc_ifinnucastpkts(void)
{
ifinnucastpkts++;
}
void snmp_inc_ifindiscards(void)
{
ifindiscards++;
}
void snmp_add_ifoutoctets(u32_t value)
{
ifoutoctets += value;
}
void snmp_inc_ifoutucastpkts(void)
{
ifoutucastpkts++;
}
void snmp_inc_ifoutnucastpkts(void)
{
ifoutnucastpkts++;
}
void snmp_inc_ifoutdiscards(void)
{
ifoutdiscards++;
}
void snmp_inc_ipindelivers(void)
{
ipindelivers++;
}
void snmp_inc_ipinreceives(void)
{
ipinreceives++;
}
void snmp_inc_ipindiscards(void)
{
ipindiscards++;
}
void snmp_inc_ipoutdiscards(void)
{
ipoutdiscards++;
}
void snmp_inc_ipoutrequests(void)
{
ipoutrequests++;
}
void snmp_inc_ipunknownprotos(void)
{
ipunknownprotos++;
}
void snmp_inc_icmpinmsgs(void)
{
icmpinmsgs++;
}
void snmp_inc_icmpinerrors(void)
{
icmpinerrors++;
}
void snmp_inc_icmpindestunreachs(void)
{
icmpindestunreachs++;
}
void snmp_inc_icmpintimeexcds(void)
{
icmpintimeexcds++;
}
void snmp_inc_icmpinparmprobs(void)
{
icmpinparmprobs++;
}
void snmp_inc_icmpinsrcquenchs(void)
{
icmpinsrcquenchs++;
}
void snmp_inc_icmpinredirects(void)
{
icmpinredirects++;
}
void snmp_inc_icmpinechos(void)
{
icmpinechos++;
}
void snmp_inc_icmpinechoreps(void)
{
icmpinechoreps++;
}
void snmp_inc_icmpintimestamps(void)
{
icmpintimestamps++;
}
void snmp_inc_icmpintimestampreps(void)
{
icmpintimestampreps++;
}
void snmp_inc_icmpinaddrmasks(void)
{
icmpinaddrmasks++;
}
void snmp_inc_icmpinaddrmaskreps(void)
{
icmpinaddrmaskreps++;
}
void snmp_inc_icmpoutmsgs(void)
{
icmpoutmsgs++;
}
void snmp_inc_icmpouterrors(void)
{
icmpouterrors++;
}
void snmp_inc_icmpoutdestunreachs(void)
{
icmpoutdestunreachs++;
}
void snmp_inc_icmpouttimeexcds(void)
{
icmpouttimeexcds++;
}
void snmp_inc_icmpoutparmprobs(void)
{
icmpoutparmprobs++;
}
void snmp_inc_icmpoutsrcquenchs(void)
{
icmpoutsrcquenchs++;
}
void snmp_inc_icmpoutredirects(void)
{
icmpoutredirects++;
}
void snmp_inc_icmpoutechos(void)
{
icmpoutechos++;
}
void snmp_inc_icmpoutechoreps(void)
{
icmpoutechoreps++;
}
void snmp_inc_icmpouttimestamps(void)
{
icmpouttimestamps++;
}
void snmp_inc_icmpouttimestampreps(void)
{
icmpouttimestampreps++;
}
void snmp_inc_icmpoutaddrmasks(void)
{
icmpoutaddrmasks++;
}
void snmp_inc_icmpoutaddrmaskreps(void)
{
icmpoutaddrmaskreps++;
}
void snmp_inc_tcpactiveopens(void)
{
tcpactiveopens++;
}
void snmp_inc_tcppassiveopens(void)
{
tcppassiveopens++;
}
void snmp_inc_tcpattemptfails(void)
{
tcpattemptfails++;
}
void snmp_inc_tcpestabresets(void)
{
tcpestabresets++;
}
void snmp_inc_tcpcurrestab(void)
{
tcpcurrestab++;
}
void snmp_inc_tcpinsegs(void)
{
tcpinsegs++;
}
void snmp_inc_tcpoutsegs(void)
{
tcpoutsegs++;
}
void snmp_inc_tcpretranssegs(void)
{
tcpretranssegs++;
}
void snmp_inc_tcpinerrs(void)
{
tcpinerrs++;
}
void snmp_inc_tcpoutrsts(void)
{
tcpoutrsts++;
}
void snmp_inc_udpindatagrams(void)
{
udpindatagrams++;
}
void snmp_inc_udpnoports(void)
{
udpnoports++;
}
void snmp_inc_udpinerrors(void)
{
udpinerrors++;
}
void snmp_inc_udpoutdatagrams(void)
{
udpoutdatagrams++;
}
void snmp_inc_snmpinpkts(void)
{
snmpinpkts++;
}
void snmp_inc_snmpoutpkts(void)
{
snmpoutpkts++;
}
void snmp_inc_snmpinbadversions(void)
{
snmpinbadversions++;
}
void snmp_inc_snmpinbadcommunitynames(void)
{
snmpinbadcommunitynames++;
}
void snmp_inc_snmpinbadcommunityuses(void)
{
snmpinbadcommunityuses++;
}
void snmp_inc_snmpinasnparseerrs(void)
{
snmpinasnparseerrs++;
}
void snmp_inc_snmpintoobigs(void)
{
snmpintoobigs++;
}
void snmp_inc_snmpinnosuchnames(void)
{
snmpinnosuchnames++;
}
void snmp_inc_snmpinbadvalues(void)
{
snmpinbadvalues++;
}
void snmp_inc_snmpinreadonlys(void)
{
snmpinreadonlys++;
}
void snmp_inc_snmpingenerrs(void)
{
snmpingenerrs++;
}
void snmp_add_snmpintotalreqvars(u8_t value)
{
snmpintotalreqvars += value;
}
void snmp_add_snmpintotalsetvars(u8_t value)
{
snmpintotalsetvars += value;
}
void snmp_inc_snmpingetrequests(void)
{
snmpingetrequests++;
}
void snmp_inc_snmpingetnexts(void)
{
snmpingetnexts++;
}
void snmp_inc_snmpinsetrequests(void)
{
snmpinsetrequests++;
}
void snmp_inc_snmpingetresponses(void)
{
snmpingetresponses++;
}
void snmp_inc_snmpintraps(void)
{
snmpintraps++;
}
void snmp_inc_snmpouttoobigs(void)
{
snmpouttoobigs++;
}
void snmp_inc_snmpoutnosuchnames(void)
{
snmpoutnosuchnames++;
}
void snmp_inc_snmpoutbadvalues(void)
{
snmpoutbadvalues++;
}
void snmp_inc_snmpoutgenerrs(void)
{
snmpoutgenerrs++;
}
void snmp_inc_snmpoutgetrequests(void)
{
snmpoutgetrequests++;
}
void snmp_inc_snmpoutgetnexts(void)
{
snmpoutgetnexts++;
}
void snmp_inc_snmpoutsetrequests(void)
{
snmpoutsetrequests++;
}
void snmp_inc_snmpoutgetresponses(void)
{
snmpoutgetresponses++;
}
void snmp_inc_snmpouttraps(void)
{
snmpouttraps++;
}
void snmp_get_snmpgrpid(const struct snmp_obj_id **oid)
{
*oid = &snmpgrp_id;
}
#endif /* LWIP_SNMP */

771
src/core/snmp/msg_in.c Normal file
View File

@ -0,0 +1,771 @@
/**
* @file
* [EXPIRIMENTAL] SNMP input message processing (RFC1157).
*
* EXPIRIMENTAL dumb echo, this is not how the agent should respond.
* This is for test purposes only, DO NOT USE THIS CODE IN REAL WORLD!!
*/
/*
* 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 <string.h>
#include "arch/cc.h"
#include "lwip/opt.h"
#include "lwip/ip_addr.h"
#include "lwip/mem.h"
#include "lwip/udp.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/snmp_asn1.h"
#include "lwip/snmp_msg.h"
#if LWIP_SNMP
#define SNMP_CONCURRENT_REQUESTS 2
/* public (non-static) constants */
/** SNMP v1 == 0 */
const s32_t snmp_version = 0;
/** default SNMP community string */
const char snmp_publiccommunity[7] = "public";
/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */
struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];
/* UDP Protocol Control Block */
struct udp_pcb *snmp1_pcb = NULL;
static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
static struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len);
static void snmp_varbind_free(struct snmp_varbind *vb);
static void snmp_varbind_list_free(struct snmp_varbind_root *root);
static void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb);
static struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root);
void snmp_init(void)
{
struct snmp_msg_pstat *msg_ps;
u8_t i;
snmp1_pcb = udp_new();
if (snmp1_pcb != NULL)
{
udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);
udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);
}
msg_ps = &msg_input_list[0];
for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++)
{
msg_ps->state = SNMP_MSG_EMPTY;
msg_ps->error_index = 0;
msg_ps->error_status = 0;
msg_ps++;
}
trap_msg.pcb = snmp1_pcb;
}
/* lwIP UDP receive callback function */
static void
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
{
struct udp_hdr *udphdr;
/* suppress unused argument warning */
if (arg);
/* peek in the UDP header (goto IP payload) */
pbuf_header(p, UDP_HLEN);
udphdr = p->payload;
/* check if datagram is really directed at us (including broadcast requests) */
if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == 161))
{
struct snmp_msg_pstat *msg_ps;
u8_t i;
/* traverse input message process list, look for SNMP_MSG_EMPTY */
msg_ps = &msg_input_list[0];
i = 0;
while ((i<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
{
i++;
msg_ps++;
}
if (i != SNMP_CONCURRENT_REQUESTS)
{
err_t err_ret;
u16_t payload_len;
u16_t payload_ofs;
u16_t varbind_ofs;
/* accepting request */
snmp_inc_snmpinpkts();
/* register 'protocol control block' used */
msg_ps->pcb = pcb;
/* source address (network order) */
msg_ps->sip = *addr;
/* source port (host order (lwIP oddity)) */
msg_ps->sp = port;
/* demultiplex variable bindings */
msg_ps->state = SNMP_MSG_DEMUX;
/* read UDP payload length from UDP header */
payload_len = ntohs(udphdr->len) - UDP_HLEN;
/* adjust to UDP payload */
payload_ofs = UDP_HLEN;
/* check total length, version, community, pdu type */
err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
if (err_ret == ERR_OK)
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
/* Builds a list of variable bindings. Copy the varbinds from the pbuf
chain to glue them when these are divided over two or more pbuf's. */
err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
if (err_ret == ERR_OK)
{
/* we've decoded the incoming message, release input msg now */
pbuf_free(p);
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
/** @todo EXPIRIMENTAL dumb echo, this is not how the agent should respond.
This is for test purposes only, do not use this in real world!! */
msg_ps->outvb = msg_ps->invb;
err_ret = snmp_send_response(msg_ps);
if (err_ret == ERR_MEM)
{
/* serious memory problem, can't return tooBig */
#if LWIP_STATS
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv pbufs.used = %"U16_F"\n",lwip_stats.pbuf.used));
#endif
}
else
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_response error_status = %"S32_F"\n",msg_ps->error_status));
}
/* free varbinds (if available) */
snmp_varbind_list_free(&msg_ps->invb);
msg_ps->state = SNMP_MSG_EMPTY;
}
else
{
/* varbind-list decode failed! */
pbuf_free(p);
/** @todo should we return SNMP_ES_GENERROR here ? */
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed"));
}
}
else
{
/* header check failed! */
pbuf_free(p);
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed"));
}
}
else
{
/* exceeding number of concurrent requests */
pbuf_free(p);
}
}
else
{
/* datagram not for us */
pbuf_free(p);
}
}
/**
* Checks and decodes incoming SNMP message header, logs header errors.
*
* @param p points to pbuf chain of SNMP message (UDP payload)
* @param ofs points to first octet of SNMP message
* @param pdu_len the length of the UDP payload
* @param ofs_ret returns the ofset of the variable bindings
* @param m_stat points to the current message request state return
* @return
* - ERR_OK SNMP header is sane and accepted
* - ERR_ARG SNMP header is either malformed or rejected
*/
static err_t
snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
{
err_t derr;
u16_t len;
u8_t len_octets;
u8_t type;
s32_t version;
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) ||
(pdu_len != (1 + len_octets + len)) ||
(type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
{
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
if (type & SNMP_ASN1_CONSTR)
{
ofs += (1 + len_octets);
}
else
{
ofs += (1 + len_octets + len);
}
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
{
/* can't decode or no integer (version) */
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);
if (derr != ERR_OK)
{
/* can't decode */
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
if (version != 0)
{
/* not version 1 */
snmp_inc_snmpinbadversions();
return ERR_ARG;
}
if (type & SNMP_ASN1_CONSTR)
{
ofs += (1 + len_octets);
}
else
{
ofs += (1 + len_octets + len);
}
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))
{
/* can't decode or no octet string (community) */
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);
if (derr != ERR_OK)
{
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
/* add zero terminator */
len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));
m_stat->community[len] = 0;
m_stat->com_strlen = len;
if (strncmp(snmp_publiccommunity, m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)
{
/** @todo: move this if we need to check more names */
snmp_inc_snmpinbadcommunitynames();
/** @todo: send authentication failure trap, if we have a trap destination */
return ERR_ARG;
}
if (type & SNMP_ASN1_CONSTR)
{
ofs += (1 + len_octets);
}
else
{
ofs += (1 + len_octets + len);
}
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if (derr != ERR_OK)
{
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
switch(type)
{
case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):
/* GetRequest PDU */
snmp_inc_snmpingetrequests();
derr = ERR_OK;
break;
case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):
/* GetNextRequest PDU */
snmp_inc_snmpingetnexts();
derr = ERR_OK;
break;
case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):
/* GetResponse PDU */
snmp_inc_snmpingetresponses();
derr = ERR_ARG;
break;
case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):
/* SetRequest PDU */
snmp_inc_snmpinsetrequests();
derr = ERR_OK;
break;
case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):
/* Trap PDU */
snmp_inc_snmpintraps();
derr = ERR_ARG;
break;
default:
snmp_inc_snmpinasnparseerrs();
derr = ERR_ARG;
break;
}
if (derr != ERR_OK)
{
/* unsupported input PDU for this agent */
return ERR_ARG;
}
m_stat->rt = type & 0x1F;
if (type & SNMP_ASN1_CONSTR)
{
ofs += (1 + len_octets);
}
else
{
ofs += (1 + len_octets + len);
}
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
{
/* can't decode or no integer (request ID) */
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);
if (derr != ERR_OK)
{
/* can't decode */
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
if (type & SNMP_ASN1_CONSTR)
{
ofs += (1 + len_octets);
}
else
{
ofs += (1 + len_octets + len);
}
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
{
/* can't decode or no integer (error-status) */
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
/* usually noError (0) for incoming messages but log errors
for mib-2 completeness and for debug purposes */
derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);
if (derr != ERR_OK)
{
/* can't decode */
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
switch (m_stat->error_status)
{
case SNMP_ES_TOOBIG:
snmp_inc_snmpintoobigs();
break;
case SNMP_ES_NOSUCHNAME:
snmp_inc_snmpinnosuchnames();
break;
case SNMP_ES_BADVALUE:
snmp_inc_snmpinbadvalues();
break;
case SNMP_ES_READONLY:
snmp_inc_snmpinreadonlys();
break;
case SNMP_ES_GENERROR:
snmp_inc_snmpingenerrs();
break;
}
if (type & SNMP_ASN1_CONSTR)
{
ofs += (1 + len_octets);
}
else
{
ofs += (1 + len_octets + len);
}
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
{
/* can't decode or no integer (error-index) */
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
/* skip 'error-index', usually 0 for incoming requests */
if (type & SNMP_ASN1_CONSTR)
{
ofs += (1 + len_octets);
}
else
{
ofs += (1 + len_octets + len);
}
*ofs_ret = ofs;
return ERR_OK;
}
static err_t
snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
{
err_t derr;
u16_t len, vb_len;
u8_t len_octets;
u8_t type;
/* variable binding list */
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);
if ((derr != ERR_OK) ||
(type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
{
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
ofs += (1 + len_octets);
/* start with empty list */
m_stat->invb.count = 0;
m_stat->invb.head = NULL;
m_stat->invb.tail = NULL;
while (vb_len > 0)
{
struct snmp_obj_id oid, oid_value;
struct snmp_varbind *vb;
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) ||
(type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
{
snmp_inc_snmpinasnparseerrs();
/* free varbinds (if available) */
snmp_varbind_list_free(&m_stat->invb);
return ERR_ARG;
}
ofs += (1 + len_octets);
vb_len -= (1 + len_octets);
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))
{
/* can't decode object name length */
snmp_inc_snmpinasnparseerrs();
/* free varbinds (if available) */
snmp_varbind_list_free(&m_stat->invb);
return ERR_ARG;
}
derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);
if (derr != ERR_OK)
{
/* can't decode object name */
snmp_inc_snmpinasnparseerrs();
/* free varbinds (if available) */
snmp_varbind_list_free(&m_stat->invb);
return ERR_ARG;
}
ofs += (1 + len_octets + len);
vb_len -= (1 + len_octets + len);
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if (derr != ERR_OK)
{
/* can't decode object value length */
snmp_inc_snmpinasnparseerrs();
/* free varbinds (if available) */
snmp_varbind_list_free(&m_stat->invb);
return ERR_ARG;
}
switch (type)
{
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));
if (vb != NULL)
{
s32_t *vptr = vb->value;
derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);
snmp_varbind_tail_add(&m_stat->invb, vb);
}
else
{
derr = ERR_ARG;
}
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):
vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));
if (vb != NULL)
{
u32_t *vptr = vb->value;
derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);
snmp_varbind_tail_add(&m_stat->invb, vb);
}
else
{
derr = ERR_ARG;
}
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
vb = snmp_varbind_alloc(&oid, type, len);
if (vb != NULL)
{
derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
snmp_varbind_tail_add(&m_stat->invb, vb);
}
else
{
derr = ERR_ARG;
}
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
vb = snmp_varbind_alloc(&oid, type, 0);
if (vb != NULL)
{
snmp_varbind_tail_add(&m_stat->invb, vb);
derr = ERR_OK;
}
else
{
derr = ERR_ARG;
}
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);
if (derr == ERR_OK)
{
vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));
if (vb != NULL)
{
u8_t i = oid_value.len;
s32_t *vptr = vb->value;
while(i > 0)
{
i--;
vptr[i] = oid_value.id[i];
}
snmp_varbind_tail_add(&m_stat->invb, vb);
derr = ERR_OK;
}
else
{
derr = ERR_ARG;
}
}
break;
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
if (len == 4)
{
/* must be exactly 4 octets! */
vb = snmp_varbind_alloc(&oid, type, 4);
if (vb != NULL)
{
derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
snmp_varbind_tail_add(&m_stat->invb, vb);
}
else
{
derr = ERR_ARG;
}
}
else
{
derr = ERR_ARG;
}
break;
default:
derr = ERR_ARG;
break;
}
if (derr != ERR_OK)
{
snmp_inc_snmpinasnparseerrs();
/* free varbinds (if available) */
snmp_varbind_list_free(&m_stat->invb);
return ERR_ARG;
}
ofs += (1 + len_octets + len);
vb_len -= (1 + len_octets + len);
}
if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)
{
snmp_add_snmpintotalsetvars(m_stat->invb.count);
}
else
{
snmp_add_snmpintotalreqvars(m_stat->invb.count);
}
*ofs_ret = ofs;
return ERR_OK;
}
static struct snmp_varbind*
snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
{
struct snmp_varbind *vb;
vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
if (vb != NULL)
{
u8_t i;
vb->next = NULL;
vb->prev = NULL;
i = oid->len;
vb->ident_len = i;
/* allocate array of s32_t for our object identifier */
vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);
if (vb->ident == NULL)
{
mem_free(vb);
return NULL;
}
while(i > 0)
{
i--;
vb->ident[i] = oid->id[i];
}
vb->value_type = type;
vb->value_len = len;
if (len > 0)
{
/* allocate raw bytes for our object value */
vb->value = mem_malloc(len);
if (vb->value == NULL)
{
mem_free(vb->ident);
mem_free(vb);
return NULL;
}
}
else
{
/* ASN1_NUL type, or zero length ASN1_OC_STR */
vb->value = NULL;
}
}
return vb;
}
static void
snmp_varbind_free(struct snmp_varbind *vb)
{
if (vb->value != NULL )
{
mem_free(vb->value);
}
if (vb->ident != NULL )
{
mem_free(vb->ident);
}
mem_free(vb);
}
static void
snmp_varbind_list_free(struct snmp_varbind_root *root)
{
struct snmp_varbind *vb;
vb = root->tail;
while ( vb != NULL )
{
snmp_varbind_free(vb);
vb = vb->prev;
}
root->count = 0;
}
static void
snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)
{
if (root->count == 0)
{
/* add first varbind to list */
root->head = vb;
root->tail = vb;
}
else
{
/* add nth varbind to list tail */
root->tail->next = vb;
vb->prev = root->tail;
root->tail = vb;
}
root->count += 1;
}
static struct snmp_varbind*
snmp_varbind_tail_remove(struct snmp_varbind_root *root)
{
struct snmp_varbind* vb;
if (root->count > 0)
{
/* remove tail varbind */
vb = root->tail;
root->tail = vb->prev;
vb->prev->next = NULL;
root->count -= 1;
}
else
{
/* nothing to remove */
vb = NULL;
}
return vb;
}
#endif /* LWIP_SNMP */

622
src/core/snmp/msg_out.c Normal file
View File

@ -0,0 +1,622 @@
/**
* @file
* [EXPIRIMENTAL] 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 "arch/cc.h"
#include "lwip/opt.h"
#include "lwip/udp.h"
#include "lwip/netif.h"
#include "lwip/snmp.h"
#include "lwip/snmp_asn1.h"
#include "lwip/snmp_msg.h"
#if LWIP_SNMP
/**
* TRAP message structure
* @todo turn this into an arg to snmp_create_trap ?
*/
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);
/**
* 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
* @todo caller must provide error-status and index ...
*/
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;
m_stat->error_status = SNMP_ES_NOERROR;
m_stat->error_index = 0;
/* 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_POOL);
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_POOL);
}
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);
if (m_stat->error_status == SNMP_ES_TOOBIG)
{
snmp_varbind_list_enc(&emptyvb, p, ofs);
}
else
{
snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
}
switch (m_stat->error_status)
{
case SNMP_ES_TOOBIG:
snmp_inc_snmpouttoobigs();
break;
case SNMP_ES_NOSUCHNAME:
snmp_inc_snmpoutnosuchnames();
break;
case SNMP_ES_BADVALUE:
snmp_inc_snmpoutbadvalues();
break;
case SNMP_ES_GENERROR:
snmp_inc_snmpoutgenerrs();
break;
}
snmp_inc_snmpoutgetresponses();
snmp_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);
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 dst points to the trap destination IPv4 address
* @param generic_trap is the trap code
* @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 enterpise 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(struct ip_addr *dst, s8_t generic_trap, s32_t specific_trap)
{
struct netif *dst_if;
struct pbuf *p;
u16_t tot_len;
/* network order trap destination */
trap_msg.dip.addr = htons(dst->addr);
/* lookup current source address for this dst */
dst_if = ip_route(dst);
trap_msg.sip_raw[0] = dst_if->ip_addr.addr >> 24;
trap_msg.sip_raw[1] = dst_if->ip_addr.addr >> 16;
trap_msg.sip_raw[2] = dst_if->ip_addr.addr >> 8;
trap_msg.sip_raw[3] = dst_if->ip_addr.addr;
trap_msg.gen_trap = generic_trap;
trap_msg.spc_trap = specific_trap;
if (generic_trap == 6)
{
/* enterprise-Specific trap */
snmp_get_sysobjid(&trap_msg.enterprise);
}
else
{
/* generic (MIB-II) trap */
snmp_get_snmpgrpid(&trap_msg.enterprise);
}
snmp_get_sysuptime(&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_POOL);
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_inc_snmpouttraps();
snmp_inc_snmpoutpkts();
/** connect to the TRAP destination */
udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT);
udp_send(trap_msg.pcb, p);
/** disassociate remote address and port with this pcb */
udp_disconnect(trap_msg.pcb);
pbuf_free(p);
return ERR_OK;
}
else
{
return ERR_MEM;
}
}
/**
* 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 lenght 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;
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_asn1_enc_s32t_cnt(snmp_version, &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 lenght 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 = 4;
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 = sizeof(snmp_publiccommunity) - 1;
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 lenght 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 = 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 = 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 = 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;
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_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version);
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, (u8_t *)&snmp_publiccommunity[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 = 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 = 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 = 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 = 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 */

View File

@ -0,0 +1,90 @@
/**
* @file
* [EXPIRIMENTAL] 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_SNMP_ASN1_H__
#define __LWIP_SNMP_ASN1_H__
#include "lwip/opt.h"
#include "arch/cc.h"
#include "lwip/err.h"
#include "lwip/pbuf.h"
#include "lwip/snmp.h"
#define SNMP_ASN1_UNIV (!0x80 | !0x40)
#define SNMP_ASN1_APPLIC (!0x80 | 0x40)
#define SNMP_ASN1_CONTXT ( 0x80 | !0x40)
#define SNMP_ASN1_CONSTR (0x20)
#define SNMP_ASN1_PRIMIT (!0x20)
/* universal tags */
#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 */
#define SNMP_ASN1_IPADDR 0 /* octet string size(4) */
#define SNMP_ASN1_COUNTER 1 /* u32_t */
#define SNMP_ASN1_GAUGE 2 /* u32_t */
#define SNMP_ASN1_TIMETICKS 3 /* u32_t */
#define SNMP_ASN1_OPAQUE 4 /* octet string */
/* context specific (SNMP) tags */
#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(u8_t ident_len, 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, u8_t octets_needed, u32_t value);
err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value);
err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident);
err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw);
#endif

267
src/include/lwip/snmp_msg.h Normal file
View File

@ -0,0 +1,267 @@
/**
* @file
* [EXPIRIMENTAL] SNMP Agent message handling structures.
*/
/*
* 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_SNMP_MSG_H__
#define __LWIP_SNMP_MSG_H__
#include "lwip/opt.h"
#include "arch/cc.h"
#include "lwip/snmp.h"
#if SNMP_PRIVATE_MIB
#include "private_mib.h"
#endif
#define SNMP_IN_PORT 161
#define SNMP_TRAP_PORT 162
#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
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 length (in s32_t) */
u8_t ident_len;
/* object identifier array */
s32_t *ident;
/* object value ASN1 type */
u8_t value_type;
/* object value length (in u8_t) */
u8_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 *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;
};
/** output response message header length fields */
struct snmp_resp_header_lengths
{
/* 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;
};
/* can accept new SNMP message */
#define SNMP_MSG_EMPTY 0
/* decode SNMP variable binding */
#define SNMP_MSG_DEMUX 1
/* perform SNMP operation on varbind for in-memory case */
#define SNMP_MSG_INTERNAL 2
/* perform SNMP operation on private varbind external case */
#define SNMP_MSG_EXTERNAL 3
#define SNMP_COMMUNITY_STR_LEN 64
struct snmp_msg_pstat
{
#if 0
struct snmp_msg_pstat *next;
#endif
/* lwIP local port (161) binding */
struct udp_pcb *pcb;
/* source IP address */
struct ip_addr sip;
/* source UDP port */
u16_t sp;
/* request type */
u8_t rt;
/* request ID */
s32_t rid;
/* 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_MGMT, MSG_PRIVATE */
u8_t state;
/* 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;
#if SNMP_PRIVATE_MIB
struct private_state ps;
#endif
};
struct snmp_msg_trap
{
#if 0
struct snmp_msg_trap *next;
#endif
/* lwIP local port (161) binding */
struct udp_pcb *pcb;
/* destination IP address in network order */
struct ip_addr dip;
/* source enterprise ID (sysObjectID) */
struct snmp_obj_id *enterprise;
/* source IP address, raw network order format */
u8_t sip_raw[4];
/* 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;
#if SNMP_PRIVATE_MIB
/** @todo is this really needed? */
struct private_state ps;
#endif
};
/** Agent Version constant, 0 = v1 oddity */
extern const s32_t snmp_version;
/** Agent default "public" community string */
extern const char snmp_publiccommunity[7];
extern struct snmp_msg_trap trap_msg;
/** Agent setup, start listening to port 161. */
void snmp_init(void);
err_t snmp_send_response(struct snmp_msg_pstat *m_stat);
err_t snmp_send_trap(struct ip_addr *dst, s8_t generic_trap, s32_t specific_trap);
#endif