Added minimalistic SNMP GET functionality.

This commit is contained in:
christiaans 2006-07-14 12:54:38 +00:00
parent 5c628d2a61
commit d8922d0410
7 changed files with 1431 additions and 127 deletions

View File

@ -25,6 +25,30 @@ HISTORY
* [Enter new changes just after this line - do not remove this line]
++ New features:
2006-07-14 Christiaan Simons
* mib_structs.c: added
* include/lwip/snmp_structs.h: added
* netif.{c,h}, netif/ethernetif.c: added SNMP statistics to netif struct
* mib2.c: changed, inserted object tree
* msg_{in,out}.c: changed, added minimalistic GET functionality (needs work)
2006-07-06 Christiaan Simons
* snmp/asn1_{enc,dec}.c added
* snmp/mib2.c added
* snmp/msg_{in,out}.c added
* include/lwip/snmp_asn1.h added
* include/lwip/snmp_msg.h added
* doc/snmp_agent.txt added
2006-03-29 Christiaan Simons
* inet.c, inet.h: Added platform byteswap support.
Added LWIP_PLATFORM_BYTESWAP define (defaults to 0) and
optional LWIP_PLATFORM_HTONS(), LWIP_PLATFORM_HTONL() macros.
++ Bug fixes:
2006-06-27 Christiaan Simons
* api_msg.c: Applied patch for cold case (bug #11135).
In accept_function() ensure newconn->callback is always initialized.
@ -41,11 +65,6 @@ HISTORY
* api_lib.c: Removed conn->sem creation and destruction
from netconn_write() and added sys_sem_new to netconn_new_*.
2006-03-29 Christiaan Simons
* inet.c, inet.h: Added platform byteswap support.
Added LWIP_PLATFORM_BYTESWAP define (defaults to 0) and
optional LWIP_PLATFORM_HTONS(), LWIP_PLATFORM_HTONL() macros.
(STABLE-1_1_1)
2006-03-03 Christiaan Simons

File diff suppressed because it is too large Load Diff

224
src/core/snmp/mib_structs.c Normal file
View File

@ -0,0 +1,224 @@
/**
* @file
* [EXPERIMENTAL] Generic MIB tree access/construction functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/opt.h"
#include "lwip/snmp_structs.h"
#if LWIP_SNMP
/**
* Searches tree for the supplied (scalar?) object identifier.
*
* @param node points to the root of the tree ('.internet')
* @param ident_len the length of the supplied object identifier
* @param ident points to the array of sub identifiers
* @param object_def points to the object definition to return
* @return pointer to the requested parent (!) node if success, NULL otherwise
*/
struct mib_node *
snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct obj_def *object_def)
{
u8_t node_type;
LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F,(void*)node,*ident));
while (node != NULL)
{
node_type = node->node_type;
if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
{
struct mib_array_node *an;
u16_t i;
/* array node (internal ROM or RAM, fixed length) */
an = (struct mib_array_node *)node;
i = 0;
while ((i < an->maxlength) && (an->objid[i] != *ident))
{
i++;
}
if (i < an->maxlength)
{
if (ident_len > 0)
{
/* found it, if available proceed to child, otherwise inspect leaf */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F,i,an->objid[i],*ident));
if (an->nptr[i] == NULL)
{
/* a scalar leaf OR table,
inspect remaining instance number / table index */
/* retrieve object definition with get_object_def()
is it scalar, or a valid table item, or non-existent? */
an->get_object_def(ident_len, ident, object_def);
if (object_def->instance != MIB_OBJECT_NONE)
{
/** @todo return something more usefull ?? */
return (struct mib_node*)an;
}
else
{
/* search failed, object id points to unknown object (nosuchname) */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, object not in this MIB"));
return NULL;
}
}
else
{
/* follow next child pointer */
ident++;
ident_len--;
node = an->nptr[i];
}
}
else
{
/* search failed, short object identifier (nosuchname) */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, short object identifier"));
return NULL;
}
}
else
{
/* search failed, identifier mismatch (nosuchname) */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed *ident==%"S32_F,*ident));
return NULL;
}
}
else if(node_type == MIB_NODE_LR)
{
struct mib_list_rootnode *lrn;
struct mib_list_node *ln;
/* list root node (internal 'RAM', variable length) */
lrn = (struct mib_list_rootnode *)node;
ln = lrn->head;
/* iterate over list, head to tail */
while ((ln != NULL) && (ln->objid != *ident))
{
ln = ln->next;
}
if (ln != NULL)
{
if (ident_len > 0)
{
/* found it, proceed to child */;
LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F,ln->objid,*ident));
if (ln->nptr == NULL)
{
lrn->get_object_def(ident_len, ident, object_def);
if (object_def->instance != MIB_OBJECT_NONE)
{
/** @todo return something more usefull ?? */
return (struct mib_node*)lrn;
}
else
{
/* search failed, object id points to unknown object (nosuchname) */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, object not in this MIB"));
return NULL;
}
}
else
{
/* follow next child pointer */
ident_len--;
ident++;
node = ln->nptr;
}
}
else
{
/* search failed, short object identifier (nosuchname) */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, short object identifier"));
return NULL;
}
}
else
{
/* search failed */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed *ident==%"S32_F,*ident));
return NULL;
}
}
else if(node_type == MIB_NODE_EX)
{
struct mib_external_node *en;
u16_t i;
/* external node (addressing and access via functions) */
en = (struct mib_external_node *)node;
i = 0;
while ((i < en->count) && en->ident_cmp(i,*ident))
{
i++;
}
if (i < en->count)
{
if (ident_len > 0)
{
if (en->get_nptr(i) == NULL)
{
/** @todo, this object is elsewhere, we can only start the request,
but can't return something usefull yet.*/
en->req_object_def(ident_len, ident);
return (struct mib_node*)en;
}
else
{
/* found it, proceed to child */
ident_len--;
ident++;
node = (struct mib_node*)en->get_nptr(i);
}
}
else
{
/* search failed, short object identifier (nosuchname) */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, short object identifier"));
return NULL;
}
}
else
{
/* search failed */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed *ident==%"S32_F,*ident));
return NULL;
}
}
}
/* done, found nothing */
LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p",(void*)node));
return NULL;
}
#endif /* LWIP_SNMP */

View File

@ -47,9 +47,11 @@
#include "lwip/snmp_asn1.h"
#include "lwip/snmp_msg.h"
#include "lwip/snmp_structs.h"
#if LWIP_SNMP
#define LWIP_SNMP_DBG_LOOPBACK_TST 0
#define SNMP_CONCURRENT_REQUESTS 2
/* public (non-static) constants */
@ -72,8 +74,16 @@ 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);
/** @todo: move this to header */
extern const struct mib_array_node internet;
extern const struct mib_array_node sys_tem; /* test only */
void snmp_init(void)
/**
* Starts SNMP Agent.
* Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.
*/
void
snmp_init(void)
{
struct snmp_msg_pstat *msg_ps;
u8_t i;
@ -95,6 +105,14 @@ void snmp_init(void)
trap_msg.pcb = snmp1_pcb;
}
/**
*
*/
void
snmp_msg_event(void)
{
}
/* 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)
@ -155,14 +173,65 @@ snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr,
err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
if (err_ret == ERR_OK)
{
struct mib_node *mn;
struct obj_def object_def;
/* 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 EXPERIMENTAL 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;
if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)
{
/** @todo check if count > 0 and if we got .iso.dod.internet and iterate from vb 0 .. count-1 */
mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->invb.head->ident_len - 2 /* trim iso.dod.internet */,
msg_ps->invb.head->ident + 2, &object_def);
if (mn != NULL)
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv mn=%p sys_tem=%p node_typ=%"U16_F,
(void*)mn,(void*)&sys_tem,(u16_t)mn->node_type));
if (msg_ps->invb.head->value != NULL)
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv free value before vb recycle"));
mem_free(msg_ps->invb.head->value);
}
msg_ps->invb.head->value_type = object_def.asn_type;
msg_ps->invb.head->value_len = object_def.v_len;
msg_ps->invb.head->value = mem_malloc(object_def.v_len);
if (msg_ps->invb.head->value != NULL)
{
mn->get_value(object_def.id_inst_len, object_def.id_inst_ptr, object_def.v_len, msg_ps->invb.head->value);
}
else
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate variable space"));
}
msg_ps->outvb = msg_ps->invb;
}
else
{
/* mn == NULL, noSuchName */
msg_ps->error_status = SNMP_ES_NOSUCHNAME;
/** @todo current varbind index */
msg_ps->error_index = 1;
msg_ps->outvb.head = NULL;
msg_ps->outvb.tail = NULL;
msg_ps->outvb.count = 0;
msg_ps->outvb.seqlen = 0;
msg_ps->outvb.seqlenlen = 1;
}
}
else
{
/* request != GET */
/** @todo EXPERIMENTAL 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;
msg_ps->error_status = SNMP_ES_NOERROR;
msg_ps->error_index = 0;
}
err_ret = snmp_send_response(msg_ps);
if (err_ret == ERR_MEM)
{

View File

@ -76,7 +76,7 @@ static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *
* @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 ...
* and provide error-status and index (except for tooBig errors) ...
*/
err_t
snmp_send_response(struct snmp_msg_pstat *m_stat)
@ -86,9 +86,6 @@ snmp_send_response(struct snmp_msg_pstat *m_stat)
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);
@ -207,12 +204,12 @@ snmp_send_trap(struct ip_addr *dst, s8_t generic_trap, s32_t specific_trap)
if (generic_trap == 6)
{
/* enterprise-Specific trap */
snmp_get_sysobjid(&trap_msg.enterprise);
snmp_get_sysobjid_ptr(&trap_msg.enterprise);
}
else
{
/* generic (MIB-II) trap */
snmp_get_snmpgrpid(&trap_msg.enterprise);
snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);
}
snmp_get_sysuptime(&trap_msg.ts);

View File

@ -49,7 +49,7 @@ struct snmp_obj_id
};
/* system */
void snmp_set_sysdesr(char* str, u8_t strlen);
void snmp_set_sysdesr(u8_t* str, u8_t strlen);
void snmp_set_sysobjid(struct snmp_obj_id *oid);
void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid);
void snmp_inc_sysuptime(void);

View File

@ -0,0 +1,179 @@
/**
* @file
* [EXPERIMENTAL] Generic MIB tree structures.
*
* @todo namespace prefixes
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
*/
#ifndef __LWIP_SNMP_STRUCTS_H__
#define __LWIP_SNMP_STRUCTS_H__
#include "lwip/opt.h"
#include "arch/cc.h"
#if SNMP_PRIVATE_MIB
#include "private_mib.h"
#endif
/* MIB object instance */
#define MIB_OBJECT_NONE 0
#define MIB_OBJECT_SCALAR 1
#define MIB_OBJECT_TAB 2
/* MIB object access */
#define MIB_OBJECT_READ_ONLY 0
#define MIB_OBJECT_READ_WRITE 1
#define MIB_OBJECT_WRITE_ONLY 2
#define MIB_OBJECT_NOT_ACCESSIBLE 3
/** object definition returned by (get_object_def)() */
struct obj_def
{
/* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */
u8_t instance;
/* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */
u8_t access;
/* ASN type for this object */
u8_t asn_type;
/* value length (host length) */
u16_t v_len;
/* length of instance part of supplied object identifier */
u8_t id_inst_len;
/* instance part of supplied object identifier */
s32_t *id_inst_ptr;
};
/** MIB const array node */
#define MIB_NODE_AR 0x01
/** MIB array node (mem_malloced from RAM) */
#define MIB_NODE_RA 0x02
/** MIB list root node (mem_malloced from RAM) */
#define MIB_NODE_LR 0x03
/** MIB node for external objects */
#define MIB_NODE_EX 0x04
/** node "base class" layout, the mandatory fields for a node */
struct mib_node
{
/** returns struct obj_def for the given object identifier */
void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
/** returns object value for the given object identifier,
@note the caller must allocate at least len bytes for the value */
void (*get_value)(u8_t ident_len, s32_t *ident, u16_t len, void *value);
/** @todo set_value() */
/** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */
const u8_t node_type;
/* array or max list length */
const u16_t maxlength;
};
/** derived node, points to a fixed size const array
of sub-identifiers plus a 'child' pointer */
struct mib_array_node
{
/* inherited "base class" */
const void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
const void (*get_value)(u8_t ident_len, s32_t *ident, u16_t len, void *value);
const u8_t node_type;
const u16_t maxlength;
/* aditional struct members */
const s32_t *objid;
struct mib_node* const *nptr;
};
/** derived node, points to a fixed size mem_malloced array
of sub-identifiers plus a 'child' pointer */
struct mib_ram_array_node
{
/* inherited "base class" */
void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
void (*get_value)(u8_t ident_len, s32_t *ident, u16_t len, void *value);
u8_t node_type;
u16_t maxlength;
/* aditional struct members */
s32_t *objid;
struct mib_node **nptr;
};
struct mib_list_node
{
struct mib_list_node *prev;
struct mib_list_node *next;
s32_t objid;
struct mib_node *nptr;
};
/** derived node, points to a doubly linked list
of sub-identifiers plus a 'child' pointer */
struct mib_list_rootnode
{
/* inherited "base class" */
void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
void (*get_value)(u8_t ident_len, s32_t *ident, u16_t len, void *value);
u8_t node_type;
u16_t maxlength;
/* aditional struct members */
struct mib_list_node *head;
struct mib_list_node *tail;
/* counts list nodes in list */
u16_t count;
};
/** derived node, has access functions for mib object in external memory or device
using index ('idx'), with a range 0 .. (count - 1) to address these objects */
struct mib_external_node
{
/* inherited "base class" */
void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
void (*get_value)(u8_t ident_len, s32_t *ident, u16_t len, void *value);
u8_t node_type;
u16_t maxlength;
/* aditional struct members */
void (*req_object_def)(u8_t ident_len, s32_t *ident);
void (*getreq_value)(u8_t ident_len, s32_t *ident);
/** compares object sub identifier with externally available id
return zero when equal, nonzero when unequal */
u16_t (*ident_cmp)(u16_t idx, s32_t sub_id);
/** returns next pointer for given index (NULL for scalar 'leaf') */
struct mib_extern_node* (*get_nptr)(u16_t idx);
/* counts actual number of external objects */
u16_t count;
};
struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct obj_def *object_def);
#endif