mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-10-05 22:29:49 +00:00
Initial commit. Expirimental code, please note this is not yet fully functional.
This commit is contained in:
parent
6b2979027e
commit
333c3f18c0
614
src/core/snmp/asn1_dec.c
Normal file
614
src/core/snmp/asn1_dec.c
Normal 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
583
src/core/snmp/asn1_enc.c
Normal 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
593
src/core/snmp/mib2.c
Normal 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
771
src/core/snmp/msg_in.c
Normal 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
622
src/core/snmp/msg_out.c
Normal 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 */
|
90
src/include/lwip/snmp_asn1.h
Normal file
90
src/include/lwip/snmp_asn1.h
Normal 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
267
src/include/lwip/snmp_msg.h
Normal 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
|
Loading…
Reference in New Issue
Block a user