0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-23 02:01:55 +00:00

SNMP: Context support and improved registering

This commit is contained in:
Vojtech Vilimek 2023-09-11 13:06:20 +02:00
parent 14bcba7040
commit 2211644ed3
9 changed files with 376 additions and 94 deletions

View File

@ -13,6 +13,8 @@
#include "subagent.h" #include "subagent.h"
#include "bgp_mib.h" #include "bgp_mib.h"
static inline void ip4_to_oid(struct oid *oid, ip4_addr addr);
/* BGP_MIB states see enum BGP_INTERNAL_STATES */ /* BGP_MIB states see enum BGP_INTERNAL_STATES */
static const char * const debug_bgp_states[] UNUSED = { static const char * const debug_bgp_states[] UNUSED = {
[BGP_INTERNAL_INVALID] = "BGP_INTERNAL_INVALID", [BGP_INTERNAL_INVALID] = "BGP_INTERNAL_INVALID",
@ -164,15 +166,16 @@ snmp_bgp_register(struct snmp_proto *p)
{ {
snmp_log("snmp_bgp_register()"); snmp_log("snmp_bgp_register()");
u32 bgp_mib_prefix[] = {1, 15, 1}; //u32 bgp_mib_prefix[] = {1, 15, 1};
u32 bgp_mib_prefix[] = { 1, 15 };
{ {
/* Register the whole BGP4-MIB::bgp root tree node */ /* Register the whole BGP4-MIB::bgp root tree node */
struct snmp_register *registering = snmp_register_create(p, SNMP_BGP4_MIB); struct snmp_register *registering = snmp_register_create(p, SNMP_BGP4_MIB);
struct oid *oid = mb_alloc(p->p.pool, snmp_oid_sizeof(2)); struct oid *oid = mb_alloc(p->p.pool, snmp_oid_sizeof(2));
put_u8(&oid->n_subid, 2); STORE_U8(oid->n_subid, 2);
put_u8(&oid->prefix, 2); STORE_U8(oid->prefix, SNMP_MGMT);
memcpy(oid->ids, bgp_mib_prefix, 2 * sizeof(u32)); memcpy(oid->ids, bgp_mib_prefix, 2 * sizeof(u32));
@ -180,9 +183,37 @@ snmp_bgp_register(struct snmp_proto *p)
add_tail(&p->register_queue, &registering->n); add_tail(&p->register_queue, &registering->n);
p->register_to_ack++; p->register_to_ack++;
/* snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 is_instance) */ /* snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 is_instance, uint contid) */
snmp_register(p, oid, 0, 1, 0); snmp_register(p, oid, 1, 0, SNMP_REGISTER_TREE, SNMP_DEFAULT_CONTEXT);
} }
u32 bgp_peer_entry[] = { 1, 15, 3, 1, 1 };
u32 bound = 24;
HASH_WALK(p->bgp_hash, next, peer)
{
if (peer->flags & SNMP_BGP_P_REGISTERED)
continue;
struct bgp_proto *bgp = (struct bgp_proto *) peer->config->c.proto;
struct snmp_register *registering = snmp_register_create(p, SNMP_BGP4_MIB);
struct oid *oid = mb_alloc(p->p.pool, snmp_oid_sizeof(9));
STORE_U8(oid->n_subid, 9);
STORE_U8(oid->prefix, SNMP_MGMT);
for (uint i = 0; i < sizeof(bgp_peer_entry)/sizeof(bgp_peer_entry[0]); i++)
STORE_U32(oid->ids[i], bgp_peer_entry[i]);
ip4_to_oid(oid, ipa_to_ip4(bgp->remote_ip));
/* index is position of x in .1.3.6.1.2.15.3.1.x (1-based) */
snmp_register(p, oid, bound, 9, SNMP_REGISTER_INSTANCE, peer->context_id);
registering->oid = oid;
add_tail(&p->register_queue, &registering->n);
p->register_to_ack++;
}
HASH_WALK_END;
} }
static int static int
@ -244,8 +275,19 @@ ip4_from_oid(const struct oid *o)
); );
} }
static inline void
ip4_to_oid(struct oid *o, ip4_addr addr)
{
u32 tmp = ip4_to_u32(addr);
ASSUME(o->n_subid >= 9);
STORE_U32(o->ids[5], (tmp & 0xFF000000) >> 24);
STORE_U32(o->ids[6], (tmp & 0x00FF0000) >> 16);
STORE_U32(o->ids[7], (tmp & 0x0000FF00) >> 8);
STORE_U32(o->ids[8], (tmp & 0x000000FF) >> 0);
}
static void static void
print_bgp_record(struct bgp_config *config) print_bgp_record(const struct bgp_config *config)
{ {
struct proto_config *cf = (struct proto_config *) config; struct proto_config *cf = (struct proto_config *) config;
struct bgp_proto *bgp_proto = (struct bgp_proto *) cf->proto; struct bgp_proto *bgp_proto = (struct bgp_proto *) cf->proto;
@ -937,7 +979,7 @@ snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, ui
static byte * static byte *
bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb, bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
struct snmp_pdu_context *c, u8 state) struct snmp_pdu *c, u8 state)
{ {
struct oid *oid = &vb->name; struct oid *oid = &vb->name;
uint size = c->size - snmp_varbind_header_size(vb); uint size = c->size - snmp_varbind_header_size(vb);
@ -1202,7 +1244,7 @@ temp, temp, pkt);
void void
snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb,
struct snmp_pdu_context *c) struct snmp_pdu *c)
{ {
u8 state = snmp_bgp_state(&vb->name); u8 state = snmp_bgp_state(&vb->name);

View File

@ -45,7 +45,7 @@ u8 snmp_bgp_getnext_valid(u8 state);
struct oid *snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid); struct oid *snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid);
enum snmp_search_res snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid); enum snmp_search_res snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid);
void snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, struct snmp_pdu_context *c); void snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, struct snmp_pdu *c);
void snmp_bgp_notify_established(struct snmp_proto *p, struct bgp_proto *bgp); void snmp_bgp_notify_established(struct snmp_proto *p, struct bgp_proto *bgp);
void snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp); void snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp);

View File

@ -16,10 +16,12 @@ CF_DEFINES
#define SNMP_CFG ((struct snmp_config *) this_proto) #define SNMP_CFG ((struct snmp_config *) this_proto)
struct snmp_bond *this_bond = NULL;
CF_DECLS CF_DECLS
CF_KEYWORDS(SNMP, PROTOCOL, BPG, LOCAL, AS, REMOTE, ADDRESS, PORT, DESCRIPTION, CF_KEYWORDS(SNMP, PROTOCOL, BPG, LOCAL, AS, REMOTE, ADDRESS, PORT, DESCRIPTION,
TIMEOUT, PRIORITY) TIMEOUT, PRIORITY, CONTEXT, DEFAULT)
CF_GRAMMAR CF_GRAMMAR
@ -66,6 +68,8 @@ snmp_proto_start: proto_start SNMP
init_list(&SNMP_CFG->bgp_entries); init_list(&SNMP_CFG->bgp_entries);
SNMP_CFG->bonds = 0; SNMP_CFG->bonds = 0;
/* We always have the default context */
SNMP_CFG->contexts = 1;
SNMP_CFG->local_ip = IPA_NONE; SNMP_CFG->local_ip = IPA_NONE;
SNMP_CFG->remote_ip = ipa_build4(127,0,0,1); SNMP_CFG->remote_ip = ipa_build4(127,0,0,1);
@ -80,18 +84,61 @@ snmp_proto_start: proto_start SNMP
proto_name ; proto_name ;
snmp_context:
/* empty */ {
if (!this_bond)
{
log(L_INFO "snmp_context no string alloc");
this_bond = cfg_alloc(sizeof(struct snmp_bond));
}
snmp_bgp_bond: BGP symbol this_bond->context = NULL;
}
| CONTEXT DEFAULT {
if (!this_bond)
{
log(L_INFO "snmp_context CONTEXT DEFAULT alloc");
this_bond = cfg_alloc(sizeof(struct snmp_bond));
}
this_bond->context = NULL;
}
| CONTEXT text {
if(!this_bond)
{
log(L_INFO "snmp_context CONTEXT text alloc");
this_bond = cfg_alloc(sizeof(struct snmp_bond));
}
this_bond->context = $2;
SNMP_CFG->contexts++;
log(L_INFO "storing context %s to bond at 0x%p", $2, this_bond);
}
;
snmp_bgp_bond: BGP symbol snmp_context
{ {
struct snmp_bond *this_bond = cfg_alloc(sizeof(struct snmp_bond)); /* the snmp_context rule sets the correct value of this_bond */
log(L_INFO "this_bond (at 0x%p) has value %s", this_bond,
(this_bond->context) ? this_bond->context : "<no_val>");
if (!this_bond)
{
log(L_INFO "snmp_bgp_bond BGP symbol ... alloc");
this_bond = cfg_alloc(sizeof(struct snmp_bond));
log(L_INFO "Unexpedted alloc in snmp_bgp_bond rule");
}
else
{
log(L_INFO, "working with this_bond (at 0x%p)", this_bond);
}
this_bond->type = SNMP_BGP; this_bond->type = SNMP_BGP;
cf_assert_symbol($2, SYM_PROTO); cf_assert_symbol($2, SYM_PROTO);
this_bond->proto = $2->proto; this_bond->proto = $2->proto;
if (!this_bond->proto) cf_error("BGP protocol %s not found", $2->name); if (!this_bond->proto) cf_error("BGP protocol %s not found", $2->name);
add_tail(&SNMP_CFG->bgp_entries, NODE this_bond); add_tail(&SNMP_CFG->bgp_entries, &this_bond->n);
SNMP_CFG->bonds++; SNMP_CFG->bonds++;
this_bond = NULL;
} }
CF_CODE CF_CODE

View File

@ -108,9 +108,13 @@ snmp_init(struct proto_config *CF)
p->timeout = cf->timeout; p->timeout = cf->timeout;
snmp_log("snmp_reconfigure() lip: %I:%u rip: %I:%u", snmp_log("snmp_init() lip: %I:%u rip: %I:%u",
cf->local_ip, cf->local_port, cf->remote_ip, cf->remote_port); cf->local_ip, cf->local_port, cf->remote_ip, cf->remote_port);
/* used when assigning the context ids in s_cont_create() */
p->context_max = 1;
p->context_id_map = NULL;
return P; return P;
} }
@ -130,7 +134,30 @@ snmp_cleanup(struct snmp_proto *p)
rfree(p->lock); rfree(p->lock);
p->lock = NULL; p->lock = NULL;
// TODO cleanup lists, hash table, trie, ... p->partial_response = NULL;
struct snmp_register *r, *r2;
WALK_LIST_DELSAFE(r, r2, p->register_queue)
{
rem_node(&r->n);
mb_free(r);
r = NULL;
}
struct snmp_registered_oid *ro, *ro2;
WALK_LIST_DELSAFE(ro, ro2, p->bgp_registered)
{
rem_node(&r->n);
mb_free(ro);
ro = NULL;
}
HASH_FREE(p->bgp_hash);
HASH_FREE(p->context_hash);
mb_free(p->context_id_map);
p->context_id_map = NULL;
// TODO cleanup trie
return (p->state = SNMP_DOWN); return (p->state = SNMP_DOWN);
} }
@ -312,16 +339,29 @@ snmp_start(struct proto *P)
/* We create copy of bonds to BGP protocols. */ /* We create copy of bonds to BGP protocols. */
HASH_INIT(p->bgp_hash, p->p.pool, 10); HASH_INIT(p->bgp_hash, p->p.pool, 10);
HASH_INIT(p->context_hash, p->p.pool, 10);
/* We always have at least the default context */
p->context_id_map = mb_allocz(p->p.pool, cf->contexts * sizeof(struct snmp_context *));
log(L_INFO "number of context allocated %d", cf->contexts);
struct snmp_context *defaultc = mb_alloc(p->p.pool, sizeof(struct snmp_context));
defaultc->context = "";
defaultc->context_id = 0;
defaultc->flags = 0; /* TODO Default context fl. */
HASH_INSERT(p->context_hash, SNMP_H_CONTEXT, defaultc);
p->context_id_map[0] = defaultc;
struct snmp_bond *b; struct snmp_bond *b;
WALK_LIST(b, cf->bgp_entries) WALK_LIST(b, cf->bgp_entries)
{ {
struct bgp_config *bc = (struct bgp_config *) b->proto; const struct bgp_config *bc = (struct bgp_config *) b->proto;
if (bc && !ipa_zero(bc->remote_ip)) if (bc && !ipa_zero(bc->remote_ip))
{ {
struct snmp_bgp_peer *peer = \ struct snmp_bgp_peer *peer = \
mb_allocz(p->p.pool, sizeof(struct snmp_bgp_peer)); mb_allocz(p->p.pool, sizeof(struct snmp_bgp_peer));
peer->config = (struct bgp_config *) b->proto; peer->config = bc;
peer->peer_ip = bc->remote_ip; peer->peer_ip = bc->remote_ip;
struct net_addr net; struct net_addr net;
@ -330,9 +370,30 @@ snmp_start(struct proto *P)
trie_add_prefix(p->bgp_trie, &net, IP4_MAX_PREFIX_LENGTH, IP4_MAX_PREFIX_LENGTH); trie_add_prefix(p->bgp_trie, &net, IP4_MAX_PREFIX_LENGTH, IP4_MAX_PREFIX_LENGTH);
HASH_INSERT(p->bgp_hash, SNMP_HASH, peer); HASH_INSERT(p->bgp_hash, SNMP_HASH, peer);
/* Handle non-default context */
if (b->context)
{
const struct snmp_context *c = snmp_cont_create(p, b->context);
snmp_log("creating snmp context %s with id %u, writing", b->context, c->context_id);
p->context_id_map[c->context_id] = c;
peer->context_id = c->context_id;
}
} }
} }
{
u32 *ptr = mb_alloc(p->p.pool, 4 * sizeof(u32));
*ptr = 1;
ptr[2] = 4;
(void)ptr[1]; (void)ptr[0]; (void)ptr[2];
mb_free(ptr);
log(L_INFO "testing alloc 3");
}
snmp_log("values of context cf %u proto %u", cf->contexts, p->context_max);
ASSUME(cf->contexts == p->context_max);
snmp_startup(p); snmp_startup(p);
return PS_START; return PS_START;
} }
@ -344,6 +405,27 @@ snmp_reconfigure(struct proto *P, struct proto_config *CF)
const struct snmp_config *new = SKIP_BACK(struct snmp_config, cf, CF); const struct snmp_config *new = SKIP_BACK(struct snmp_config, cf, CF);
const struct snmp_config *old = SKIP_BACK(struct snmp_config, cf, p->p.cf); const struct snmp_config *old = SKIP_BACK(struct snmp_config, cf, p->p.cf);
struct snmp_bond *b1, *b2;
WALK_LIST(b1, new->bgp_entries)
{
WALK_LIST(b2, old->bgp_entries)
{
if (!strcmp(b1->proto->name, b2->proto->name))
goto skip;
/* Both bonds use default context */
if (!b1->context && !b2->context)
goto skip;
/* Both bonds use same non-default context */
if (b1->context && b2->context && !strcmp(b1->context, b2->context))
goto skip;
}
return 0;
skip:;
}
return !memcmp(((byte *) old) + sizeof(struct proto_config), return !memcmp(((byte *) old) + sizeof(struct proto_config),
((byte *) new) + sizeof(struct proto_config), ((byte *) new) + sizeof(struct proto_config),
OFFSETOF(struct snmp_config, description) - sizeof(struct proto_config)) OFFSETOF(struct snmp_config, description) - sizeof(struct proto_config))
@ -391,7 +473,7 @@ snmp_show_proto_info(struct proto *P)
cli_msg(-1006, " in total: %u", bp->stats.rx_messages); cli_msg(-1006, " in total: %u", bp->stats.rx_messages);
cli_msg(-1006, " out total: %u", bp->stats.tx_messages); cli_msg(-1006, " out total: %u", bp->stats.tx_messages);
cli_msg(-1006, " fsm transitions: %u", cli_msg(-1006, " fsm transitions: %u",
bp->stats.fsm_established_transitions); bp->stats.fsm_established_transitions);
cli_msg(-1006, " fsm total time: -- (0)"); cli_msg(-1006, " fsm total time: -- (0)");
cli_msg(-1006, " retry interval: %u", bcf->connect_retry_time); cli_msg(-1006, " retry interval: %u", bcf->connect_retry_time);

View File

@ -51,10 +51,17 @@ enum snmp_proto_state {
/* hash table only store ip4 addresses */ /* hash table only store ip4 addresses */
#define SNMP_HASH_LESS(ip1, ip2) SNMP_HASH_LESS4(ip1,ip2) #define SNMP_HASH_LESS(ip1, ip2) SNMP_HASH_LESS4(ip1,ip2)
/* context hash table macros */
#define SNMP_H_CONTEXT_KEY(c) c->context
#define SNMP_H_CONTEXT_NEXT(c) c->next
#define SNMP_H_CONTEXT_EQ(s1,s2) strcmp(s1,s2)
#define SNMP_H_CONTEXT_FN(s) mem_hash(s, strlen(s))
struct snmp_bond { struct snmp_bond {
node n; node n;
struct proto_config *proto; struct proto_config *proto;
u8 type; u8 type;
const char *context;
}; };
struct snmp_config { struct snmp_config {
@ -67,15 +74,21 @@ struct snmp_config {
u8 timeout; u8 timeout;
u8 priority; u8 priority;
//struct iface *iface; //struct iface *iface;
u32 bonds;
uint contexts; /* Number of all conetexts including the default */
const char *description; const char *description;
list bgp_entries; list bgp_entries;
u32 bonds;
// TODO add support for subagent oid identification // TODO add support for subagent oid identification
}; };
#define SNMP_BGP_P_REGISTERING 0x01
#define SNMP_BGP_P_REGISTERED 0x02
struct snmp_bgp_peer { struct snmp_bgp_peer {
struct bgp_config *config; const struct bgp_config *config;
ip_addr peer_ip; ip_addr peer_ip;
uint context_id;
u8 flags;
struct snmp_bgp_peer *next; struct snmp_bgp_peer *next;
}; };
@ -93,6 +106,14 @@ struct snmp_registered_oid {
struct oid *oid; struct oid *oid;
}; };
struct snmp_context {
const char *context; /* string name */
//uint length; /* strlen() of name */
uint context_id;
u8 flags;
struct snmp_context *next;
};
struct snmp_proto { struct snmp_proto {
struct proto p; struct proto p;
struct object_lock *lock; struct object_lock *lock;
@ -121,6 +142,9 @@ struct snmp_proto {
// map // map
struct f_trie *bgp_trie; struct f_trie *bgp_trie;
HASH(struct snmp_bgp_peer) bgp_hash; HASH(struct snmp_bgp_peer) bgp_hash;
HASH(struct snmp_context) context_hash;
const struct snmp_context **context_id_map;
uint context_max;
struct tbf rl_gen; struct tbf rl_gen;
timer *ping_timer; timer *ping_timer;

View File

@ -149,11 +149,13 @@ snmp_varbind_size(struct agentx_varbind *vb, int byte_ord)
return hdr_size + snmp_str_size_from_len(LOAD_PTR(data, byte_ord)); return hdr_size + snmp_str_size_from_len(LOAD_PTR(data, byte_ord));
} }
/*
inline uint inline uint
snmp_context_size(struct agentx_context *c) snmp_context_size(struct agentx_context *c)
{ {
return (c && c->length) ? snmp_str_size_from_len(c->length) : 0; return (c && c->length) ? snmp_str_size_from_len(c->length) : 0;
} }
*/
struct agentx_varbind * struct agentx_varbind *
snmp_create_varbind(byte *buf, struct oid *oid) snmp_create_varbind(byte *buf, struct oid *oid)
@ -208,14 +210,13 @@ snmp_put_nstr(byte *buf, const char *str, uint len)
{ {
uint alen = BIRD_ALIGN(len, 4); uint alen = BIRD_ALIGN(len, 4);
// TODO check for '\0' in the str bytes?
STORE_PTR(buf, len); STORE_PTR(buf, len);
buf += 4; buf += 4;
memcpy(buf, str, len); memcpy(buf, str, len);
/* Insert zero padding in the gap at the end */ /* Insert zero padding in the gap at the end */
for (uint i = 0; i < alen - len; i++) for (uint i = 0; i < alen - len; i++)
buf[len + i] = 0x00; buf[len + i] = '\0';
return buf + alen; return buf + alen;
} }
@ -415,7 +416,7 @@ snmp_register_same(struct snmp_register *r, struct agentx_header *h, u8 class)
} }
void void
snmp_register_ack(struct snmp_proto *p, struct agentx_header *h) snmp_register_ack(struct snmp_proto *p, struct agentx_header *h, u8 class)
{ {
snmp_log("snmp_register_ack()"); snmp_log("snmp_register_ack()");
@ -428,7 +429,7 @@ h->packet_id);
// TODO add support for more mib trees (other than BGP) // TODO add support for more mib trees (other than BGP)
snmp_log("checking registration request sid: %u tid: %u pid: %u", snmp_log("checking registration request sid: %u tid: %u pid: %u",
reg->session_id, reg->transaction_id, reg->packet_id); reg->session_id, reg->transaction_id, reg->packet_id);
if (snmp_register_same(reg, h, SNMP_BGP4_MIB)) if (snmp_register_same(reg, h, class))
{ {
struct snmp_registered_oid *ro = \ struct snmp_registered_oid *ro = \
mb_alloc(p->p.pool, sizeof(struct snmp_registered_oid)); mb_alloc(p->p.pool, sizeof(struct snmp_registered_oid));
@ -575,3 +576,48 @@ snmp_search_res_to_type(enum snmp_search_res r)
return type_arr[r]; return type_arr[r];
} }
inline const struct snmp_context *
snmp_cont_find(struct snmp_proto *p, const char *name)
{
u32 *ptr = mb_alloc(p->p.pool, 4 * sizeof(u32));
*ptr = 1;
ptr[2] = 4;
(void)ptr[1]; (void)ptr[0]; (void)ptr[2];
mb_free(ptr);
return HASH_FIND(p->context_hash, SNMP_H_CONTEXT, name);
}
inline const struct snmp_context *
snmp_cont_get(struct snmp_proto *p, uint id)
{
if (id >= p->context_max)
return NULL;
return p->context_id_map[id];
}
inline const struct snmp_context *
snmp_cont_create(struct snmp_proto *p, const char *name)
{
const struct snmp_context *c = snmp_cont_find(p, name);
if (c)
return c;
struct snmp_context *c2;
c2 = mb_alloc(p->p.pool, sizeof(struct snmp_context));
c2->context = name;
c2->context_id = p->context_max++;
c2->flags = 0;
u32 *ptr = mb_alloc(p->p.pool, 4 * sizeof(u32));
*ptr = 1;
ptr[2] = 4;
(void)ptr[1]; (void)ptr[0]; (void)ptr[2];
mb_free(ptr);
HASH_INSERT(p->context_hash, SNMP_H_CONTEXT, c2);
return c2;
}

View File

@ -14,7 +14,7 @@ size_t snmp_oid_sizeof(uint n_subid);
uint snmp_varbind_hdr_size_from_oid(struct oid *oid); uint snmp_varbind_hdr_size_from_oid(struct oid *oid);
uint snmp_varbind_header_size(struct agentx_varbind *vb); uint snmp_varbind_header_size(struct agentx_varbind *vb);
uint snmp_varbind_size(struct agentx_varbind *vb, int byte_ord); uint snmp_varbind_size(struct agentx_varbind *vb, int byte_ord);
uint snmp_context_size(struct agentx_context *c); //uint snmp_context_size(struct agentx_context *c);
void snmp_oid_copy(struct oid *dest, const struct oid *src); void snmp_oid_copy(struct oid *dest, const struct oid *src);
@ -46,7 +46,7 @@ void snmp_oid_dump(struct oid *oid);
struct snmp_register *snmp_register_create(struct snmp_proto *p, u8 mib_class); struct snmp_register *snmp_register_create(struct snmp_proto *p, u8 mib_class);
void snmp_register_ack(struct snmp_proto *p, struct agentx_header *h); void snmp_register_ack(struct snmp_proto *p, struct agentx_header *h, u8 class);
byte *snmp_varbind_int(struct agentx_varbind *vb, uint size, u32 val); byte *snmp_varbind_int(struct agentx_varbind *vb, uint size, u32 val);
byte *snmp_varbind_counter32(struct agentx_varbind *vb, uint size, u32 val); byte *snmp_varbind_counter32(struct agentx_varbind *vb, uint size, u32 val);
@ -57,7 +57,13 @@ byte *snmp_varbind_nstr(struct agentx_varbind *vb, uint size, const char *str, u
void snmp_dump_packet(byte *pkt, uint size); void snmp_dump_packet(byte *pkt, uint size);
const struct snmp_context *snmp_cont_find(struct snmp_proto *p, const char *name);
const struct snmp_context *snmp_cont_get(struct snmp_proto *p, uint context_id);
const struct snmp_context *snmp_cont_create(struct snmp_proto *p, const char *name);
enum agentx_type snmp_search_res_to_type(enum snmp_search_res res); enum agentx_type snmp_search_res_to_type(enum snmp_search_res res);
int agentx_type_size(enum agentx_type t); int agentx_type_size(enum agentx_type t);
#endif #endif

View File

@ -27,15 +27,15 @@
* *
*/ */
static void snmp_mib_fill2(struct snmp_proto *p, struct oid *oid, struct snmp_pdu_context *c); static void snmp_mib_fill2(struct snmp_proto *p, struct oid *oid, struct snmp_pdu *c);
static uint parse_response(struct snmp_proto *p, byte *buf, uint size); static uint parse_response(struct snmp_proto *p, byte *buf, uint size);
static void do_response(struct snmp_proto *p, byte *buf, uint size); static void do_response(struct snmp_proto *p, byte *buf, uint size);
static uint parse_gets2_pdu(struct snmp_proto *p, byte *buf, uint size, uint *skip); static uint parse_gets2_pdu(struct snmp_proto *p, byte *buf, uint size, uint *skip);
static uint parse_close_pdu(struct snmp_proto *p, byte *buf, uint size); static uint parse_close_pdu(struct snmp_proto *p, byte *buf, uint size);
static struct agentx_response *prepare_response(struct snmp_proto *p, struct snmp_pdu_context *c); static struct agentx_response *prepare_response(struct snmp_proto *p, struct snmp_pdu *c);
static void response_err_ind(struct agentx_response *res, uint err, uint ind); static void response_err_ind(struct agentx_response *res, uint err, uint ind);
static uint update_packet_size(struct snmp_proto *p, byte *start, byte *end); static uint update_packet_size(struct snmp_proto *p, byte *start, byte *end);
static struct oid *search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_end, struct oid *o_curr, struct snmp_pdu_context *c, enum snmp_search_res *result); static struct oid *search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_end, struct oid *o_curr, struct snmp_pdu *c, enum snmp_search_res *result);
u32 snmp_internet[] = { SNMP_ISO, SNMP_ORG, SNMP_DOD, SNMP_INTERNET }; u32 snmp_internet[] = { SNMP_ISO, SNMP_ORG, SNMP_DOD, SNMP_INTERNET };
@ -83,7 +83,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
const struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf); const struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf);
sock *sk = p->sock; sock *sk = p->sock;
struct snmp_pdu_context c = SNMP_PDU_CONTEXT(sk); struct snmp_pdu c = SNMP_PDU_CONTEXT(sk);
byte *buf = c.buffer; byte *buf = c.buffer;
/* +4 for timeout (1B with 4B alignment) */ /* +4 for timeout (1B with 4B alignment) */
@ -94,6 +94,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
buf = c.buffer; buf = c.buffer;
} }
/* Function open_pdu() does not generate agentx_pkt. */
struct agentx_header *h = (struct agentx_header *) c.buffer; struct agentx_header *h = (struct agentx_header *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
SNMP_BLANK_HEADER(h, AGENTX_OPEN_PDU); SNMP_BLANK_HEADER(h, AGENTX_OPEN_PDU);
@ -123,7 +124,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
{ {
sock *sk = p->sock; sock *sk = p->sock;
struct snmp_pdu_context c = SNMP_PDU_CONTEXT(sk); struct snmp_pdu c = SNMP_PDU_CONTEXT(sk);
#define UPTIME_SIZE \ #define UPTIME_SIZE \
(6 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[4] } )*/ (6 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[4] } )*/
@ -142,6 +143,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
struct agentx_header *h = (struct agentx_header *) c.buffer; struct agentx_header *h = (struct agentx_header *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
SNMP_BLANK_HEADER(h, AGENTX_NOTIFY_PDU); SNMP_BLANK_HEADER(h, AGENTX_NOTIFY_PDU);
p->packet_id++;
SNMP_SESSION(h, p); SNMP_SESSION(h, p);
c.byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER; c.byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER;
@ -183,7 +185,6 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
ADVANCE(c.buffer, c.size, size); ADVANCE(c.buffer, c.size, size);
uint s = update_packet_size(p, sk->tbuf, c.buffer); uint s = update_packet_size(p, sk->tbuf, c.buffer);
int ret = sk_send(sk, s); int ret = sk_send(sk, s);
if (ret > 0) if (ret > 0)
snmp_log("sk_send OK!"); snmp_log("sk_send OK!");
@ -227,15 +228,24 @@ de_allocate_pdu(struct snmp_proto *p, struct oid *oid, u8 type)
/* Register-PDU / Unregister-PDU */ /* Register-PDU / Unregister-PDU */
static void static void
un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 type, u8 is_instance) un_register_pdu(struct snmp_proto *p, struct oid *oid, uint len, uint index, u8 type, u8 is_instance, uint contid)
{ {
const struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf); const struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf);
sock *sk = p->sock; sock *sk = p->sock;
struct snmp_pdu_context c = SNMP_PDU_CONTEXT(sk); struct snmp_pdu c = SNMP_PDU_CONTEXT(sk);
byte *buf = c.buffer; byte *buf = c.buffer;
/* conditional +4 for upper-bound (optinal field) */ /* conditional +4 for upper-bound (optinal field) */
if (c.size < AGENTX_HEADER_SIZE + snmp_oid_size(oid) + ((len > 1) ? 4 : 0)) uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) + ((len > 1) ? 4 : 0);
const struct snmp_context *sc = NULL;
if (contid)
{
sc = snmp_cont_get(p, contid);
sz += snmp_str_size(sc->context);
}
if (c.size < sz)
{ {
snmp_log("un_register_pdu() insufficient size"); snmp_log("un_register_pdu() insufficient size");
snmp_manage_tbuf(p, &c); snmp_manage_tbuf(p, &c);
@ -243,22 +253,28 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8
} }
snmp_log("un_register_pdu()"); snmp_log("un_register_pdu()");
struct agentx_un_register_pdu *ur = (struct agentx_un_register_pdu *)c.buffer; struct agentx_header *h = (struct agentx_header *) c.buffer;
ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_pdu)); ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
struct agentx_header *h = &ur->h;
SNMP_HEADER(h, type, is_instance ? AGENTX_FLAG_INSTANCE_REGISTRATION : 0); SNMP_HEADER(h, type, is_instance ? AGENTX_FLAG_INSTANCE_REGISTRATION : 0);
/* use new transactionID, reset packetID */
p->packet_id++; p->packet_id++;
SNMP_SESSION(h, p); SNMP_SESSION(h, p);
c.byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER; c.byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER;
log("un_register_pdu contid %u s_cont (at 0x%p) %s", contid, sc, (sc &&
sc->context) ? sc->context : "<not_avail>");
SNMP_NON_DEFAULT_CONTEXT(h, c, contid);
struct agentx_un_register_hdr *ur = (struct agentx_un_register_hdr *) c.buffer;
/* do not override timeout */ /* do not override timeout */
STORE_U8(ur->timeout, p->timeout); STORE_U8(ur->timeout, p->timeout);
/* default priority */ /* default priority */
STORE_U8(ur->priority, cf->priority); STORE_U8(ur->priority, cf->priority);
STORE_U8(ur->range_subid, (len > 1) ? index : 0); STORE_U8(ur->range_subid, (len > 1) ? index : 0);
STORE_U8(ur->pad, 0); STORE_U8(ur->pad, 0);
ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_hdr));
snmp_put_oid(c.buffer, oid); snmp_put_oid(c.buffer, oid);
ADVANCE(c.buffer, c.size, snmp_oid_size(oid)); ADVANCE(c.buffer, c.size, snmp_oid_size(oid));
@ -284,23 +300,23 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8
/* Register-PDU */ /* Register-PDU */
void void
snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 is_instance) snmp_register(struct snmp_proto *p, struct oid *oid, uint len, uint index, u8 is_instance, uint contid)
{ {
un_register_pdu(p, oid, index, len, AGENTX_REGISTER_PDU, is_instance); un_register_pdu(p, oid, len, index, AGENTX_REGISTER_PDU, is_instance, contid);
} }
/* Unregister-PDU */ /* Unregister-PDU */
void UNUSED void UNUSED
snmp_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len) snmp_unregister(struct snmp_proto *p, struct oid *oid, uint len, uint index, uint contid)
{ {
un_register_pdu(p, oid, index, len, AGENTX_UNREGISTER_PDU, 0); un_register_pdu(p, oid, len, index, AGENTX_UNREGISTER_PDU, 0, contid);
} }
static void static void
close_pdu(struct snmp_proto *p, u8 reason) close_pdu(struct snmp_proto *p, u8 reason)
{ {
sock *sk = p->sock; sock *sk = p->sock;
struct snmp_pdu_context c = SNMP_PDU_CONTEXT(sk); struct snmp_pdu c = SNMP_PDU_CONTEXT(sk);
byte *buf = c.buffer; byte *buf = c.buffer;
snmp_log("close_pdu() size: %u %c %u", c.size, (c.size > AGENTX_HEADER_SIZE + 4) snmp_log("close_pdu() size: %u %c %u", c.size, (c.size > AGENTX_HEADER_SIZE + 4)
@ -475,13 +491,13 @@ refresh_ids(struct snmp_proto *p, struct agentx_header *h)
* @size: number of packet bytes in buffer * @size: number of packet bytes in buffer
* retval number of byte parsed * retval number of byte parsed
* *
* function parse_ptk() parses response-pdu and calls do_response(). * function parse_pkt() parses response-pdu and calls do_response().
* returns number of bytes parsed by function excluding size of header. * returns number of bytes parsed by function excluding size of header.
*/ */
static uint static uint
parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip) parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip)
{ {
snmp_log("parse_ptk() pkt start: %p", pkt); snmp_log("parse_pkt() pkt start: %p", pkt);
if (size < AGENTX_HEADER_SIZE) if (size < AGENTX_HEADER_SIZE)
return 0; return 0;
@ -540,7 +556,8 @@ parse_response(struct snmp_proto *p, byte *res, uint size)
uint pkt_size = LOAD_U32(h->payload, byte_ord); uint pkt_size = LOAD_U32(h->payload, byte_ord);
snmp_log("p_res pkt_size %u", pkt_size); snmp_log("p_res pkt_size %u", pkt_size);
if (size < pkt_size + AGENTX_HEADER_SIZE) { if (size < pkt_size + AGENTX_HEADER_SIZE)
{
snmp_log("parse_response early return"); snmp_log("parse_response early return");
return 0; return 0;
} }
@ -562,13 +579,6 @@ parse_response(struct snmp_proto *p, byte *res, uint size)
return pkt_size + AGENTX_HEADER_SIZE; return pkt_size + AGENTX_HEADER_SIZE;
} }
static inline int
snmp_registered_all(struct snmp_proto *p)
{
snmp_log("snmp_registered_all() %u", list_length(&p->register_queue));
return p->register_to_ack == 0;
}
static void static void
snmp_register_mibs(struct snmp_proto *p) snmp_register_mibs(struct snmp_proto *p)
{ {
@ -580,7 +590,7 @@ snmp_register_mibs(struct snmp_proto *p)
} }
static void static void
do_response(struct snmp_proto *p, byte *buf, uint size UNUSED) do_response(struct snmp_proto *p, byte *buf, uint size)
{ {
snmp_log("do_response()"); snmp_log("do_response()");
struct agentx_response *r = (void *) buf; struct agentx_response *r = (void *) buf;
@ -607,14 +617,28 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED)
p->state = SNMP_REGISTER; p->state = SNMP_REGISTER;
snmp_register_mibs(p); snmp_register_mibs(p);
snmp_log("do_response state SNMP_INIT register list %u", list_length(&p->register_queue)); snmp_log("do_response state SNMP_INIT register list %u", list_length(&p->register_queue));
break; break;
case SNMP_REGISTER: case SNMP_REGISTER:
snmp_log("do_response state SNMP_REGISTER register list %u", list_length(&p->register_queue)); snmp_log("do_response state SNMP_REGISTER register list %u", list_length(&p->register_queue));
snmp_register_ack(p ,h);
if (snmp_registered_all(p)) { byte *pkt = buf;
ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
uint clen;
const char *context;
SNMP_LOAD_CONTEXT((struct agentx_header *) buf, pkt, context, clen);
if (size < snmp_str_size_from_len(clen))
return;
ADVANCE(pkt, size, snmp_str_size_from_len(clen));
const struct oid *oid = (void *) pkt;
snmp_register_ack(p, h, snmp_get_mib_class(oid));
if (p->register_to_ack == 0)
{
snmp_log("changing proto_snmp state to CONNECTED"); snmp_log("changing proto_snmp state to CONNECTED");
p->state = SNMP_CONN; p->state = SNMP_CONN;
proto_notify_state(&p->p, PS_UP); proto_notify_state(&p->p, PS_UP);
@ -622,11 +646,9 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED)
break; break;
case SNMP_CONN: case SNMP_CONN:
// proto_notify_state(&p->p, PS_UP);
break; break;
case SNMP_STOP: case SNMP_STOP:
snmp_down(p);
break; break;
default: default:
@ -653,7 +675,7 @@ snmp_get_mib_class(const struct oid *oid)
static void static void
snmp_get_next2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, snmp_get_next2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end,
struct snmp_pdu_context *c) struct snmp_pdu *c)
{ {
snmp_log("get_next2()"); snmp_log("get_next2()");
enum snmp_search_res r; enum snmp_search_res r;
@ -721,7 +743,7 @@ snmp_get_next2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end,
static void static void
snmp_get_bulk2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, snmp_get_bulk2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end,
struct agentx_bulk_state *state, struct snmp_pdu_context *c) struct agentx_bulk_state *state, struct snmp_pdu *c)
{ {
if (state->index <= state->getbulk.non_repeaters) if (state->index <= state->getbulk.non_repeaters)
{ {
@ -834,6 +856,7 @@ response_err_ind(struct agentx_response *res, uint err, uint ind)
static uint static uint
parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *skip) parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *skip)
{ {
// TODO checks for c.size underflow
snmp_log("parse_gets2_pdu()"); snmp_log("parse_gets2_pdu()");
struct oid *o_start = NULL, *o_end = NULL; struct oid *o_start = NULL, *o_end = NULL;
@ -844,15 +867,15 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s
uint pkt_size = LOAD_U32(h->payload, h->flags & AGENTX_NETWORK_BYTE_ORDER); uint pkt_size = LOAD_U32(h->payload, h->flags & AGENTX_NETWORK_BYTE_ORDER);
sock *sk = p->sock; sock *sk = p->sock;
struct snmp_pdu_context c = SNMP_PDU_CONTEXT(sk); struct snmp_pdu c = SNMP_PDU_CONTEXT(sk);
// TODO better handling of endianness // TODO better handling of endianness
c.byte_ord = 0; /* use little-endian */ c.byte_ord = 0; /* use little-endian */
uint clen; /* count of characters in context (without last '\0') */ uint clen; /* count of characters in context (without last '\0') */
char *context; /* newly allocated string of character */ const char *context; /* pointer to RX-buffer context */
/* alters pkt; assign context, clen */ /* alters pkt; assign context, clen */
SNMP_LOAD_CONTEXT(p, h, pkt, context, clen); SNMP_LOAD_CONTEXT(h, pkt, context, clen);
/* /*
* We need more data; for valid response we need to know full * We need more data; for valid response we need to know full
@ -1040,7 +1063,6 @@ send:
p->partial_response = NULL; p->partial_response = NULL;
mb_free(context);
mb_free(o_start); mb_free(o_start);
mb_free(o_end); mb_free(o_end);
@ -1064,9 +1086,9 @@ partial:
wait: wait:
mb_free(context);
mb_free(o_start); mb_free(o_start);
mb_free(o_end); mb_free(o_end);
p->packet_id--; /* we did not use the packetID */
return 0; return 0;
} }
@ -1163,7 +1185,7 @@ snmp_ping(struct snmp_proto *p)
sock *sk = p->sock; sock *sk = p->sock;
snmp_dump_packet(sk->tpos, AGENTX_HEADER_SIZE + 4); snmp_dump_packet(sk->tpos, AGENTX_HEADER_SIZE + 4);
snmp_log("snmp_ping sk->tpos 0x%p", sk->tpos); snmp_log("snmp_ping sk->tpos 0x%p", sk->tpos);
struct snmp_pdu_context c = SNMP_PDU_CONTEXT(sk); struct snmp_pdu c = SNMP_PDU_CONTEXT(sk);
if (c.size < AGENTX_HEADER_SIZE) if (c.size < AGENTX_HEADER_SIZE)
snmp_manage_tbuf(p, &c); snmp_manage_tbuf(p, &c);
@ -1180,6 +1202,7 @@ snmp_ping(struct snmp_proto *p)
snmp_dump_packet(sk->tpos, AGENTX_HEADER_SIZE + 4); snmp_dump_packet(sk->tpos, AGENTX_HEADER_SIZE + 4);
/* sending only header -> pkt - buf */ /* sending only header -> pkt - buf */
uint s = update_packet_size(p, sk->tpos, c.buffer); uint s = update_packet_size(p, sk->tpos, c.buffer);
int ret = sk_send(sk, s); int ret = sk_send(sk, s);
if (ret > 0) if (ret > 0)
snmp_log("sk_send OK!"); snmp_log("sk_send OK!");
@ -1231,7 +1254,7 @@ int snmp_search_check_end_oid(const struct oid *found, const struct oid *bound)
working only with o_start, o_end allocated in heap (not from buffer)*/ working only with o_start, o_end allocated in heap (not from buffer)*/
static struct oid * static struct oid *
search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_end, search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_end,
struct oid *o_curr, struct snmp_pdu_context *c, struct oid *o_curr, struct snmp_pdu *c,
enum snmp_search_res *result) enum snmp_search_res *result)
{ {
snmp_log("search_mib()"); snmp_log("search_mib()");
@ -1344,16 +1367,13 @@ snmp_prefixize(struct snmp_proto *proto, const struct oid *oid, int byte_ord)
static void static void
snmp_mib_fill2(struct snmp_proto *p, struct oid *oid, snmp_mib_fill2(struct snmp_proto *p, struct oid *oid,
struct snmp_pdu_context *c) struct snmp_pdu *c)
{ {
ASSUME(oid != NULL); ASSUME(oid != NULL);
snmp_log("critical part");
if (c->size < snmp_varbind_hdr_size_from_oid(oid)) if (c->size < snmp_varbind_hdr_size_from_oid(oid))
snmp_manage_tbuf(p, c); snmp_manage_tbuf(p, c);
snmp_log("critical part done");
struct agentx_varbind *vb = snmp_create_varbind(c->buffer, oid); struct agentx_varbind *vb = snmp_create_varbind(c->buffer, oid);
if (oid->n_subid < 2 || (oid->prefix != SNMP_MGMT && oid->ids[0] != SNMP_MIB_2)) if (oid->n_subid < 2 || (oid->prefix != SNMP_MGMT && oid->ids[0] != SNMP_MIB_2))
@ -1384,7 +1404,7 @@ snmp_mib_fill2(struct snmp_proto *p, struct oid *oid,
* are invalidated! * are invalidated!
*/ */
void void
snmp_manage_tbuf(struct snmp_proto UNUSED *p, struct snmp_pdu_context *c) snmp_manage_tbuf(struct snmp_proto UNUSED *p, struct snmp_pdu *c)
{ {
snmp_log("snmp_manage_tbuf()"); snmp_log("snmp_manage_tbuf()");
sock *sk = p->sock; sock *sk = p->sock;
@ -1403,7 +1423,7 @@ snmp_tx(sock UNUSED *sk)
static struct agentx_response * static struct agentx_response *
prepare_response(struct snmp_proto *p, struct snmp_pdu_context *c) prepare_response(struct snmp_proto *p, struct snmp_pdu *c)
{ {
snmp_log("prepare_response()"); snmp_log("prepare_response()");

View File

@ -27,6 +27,8 @@ void snmp_ping(struct snmp_proto *p);
extern u32 snmp_internet[4]; extern u32 snmp_internet[4];
#define SNMP_DEFAULT_CONTEXT 0
enum SNMP_CLASSES { enum SNMP_CLASSES {
SNMP_CLASS_INVALID = 0, SNMP_CLASS_INVALID = 0,
SNMP_CLASS_BGP = 1, SNMP_CLASS_BGP = 1,
@ -64,6 +66,9 @@ enum snmp_search_res {
#define AGENTX_PRIORITY 127 #define AGENTX_PRIORITY 127
#define SNMP_REGISTER_TREE 0
#define SNMP_REGISTER_INSTANCE 1
#define SNMP_NATIVE #define SNMP_NATIVE
#ifdef SNMP_NATIVE #ifdef SNMP_NATIVE
@ -95,7 +100,7 @@ enum snmp_search_res {
#define SNMP_BLANK_HEADER(h, t) SNMP_HEADER(h, t, AGENTX_FLAG_BLANK) #define SNMP_BLANK_HEADER(h, t) SNMP_HEADER(h, t, AGENTX_FLAG_BLANK)
#define SNMP_SESSION(h, p) \ #define SNMP_SESSION(h, p) \
STORE_U32(h->session_id, p->session_id); \ STORE_U32(h->session_id, p->session_id); \
STORE_U32(h->transaction_id, p->transaction_id); \ STORE_U32(h->transaction_id, p->transaction_id); \
STORE_U32(h->packet_id, p->packet_id) STORE_U32(h->packet_id, p->packet_id)
@ -104,23 +109,39 @@ enum snmp_search_res {
#define LOAD_U16(v, bo) ((bo) ? get_u16(&v) : (u16) (v)) #define LOAD_U16(v, bo) ((bo) ? get_u16(&v) : (u16) (v))
#define LOAD_PTR(v, bo) ((bo) ? get_u32(v) : *((u32 *) v)) #define LOAD_PTR(v, bo) ((bo) ? get_u32(v) : *((u32 *) v))
#define LOAD_STR(proto, buf, str, length, byte_order) ({ \ #define LOAD_STR(/* byte * */buf, str, length, byte_ord) ({ \
length = LOAD_PTR(buf, byte_ord); \
length > 0 ? (str = buf + 4) : (str = NULL); })
#define COPY_STR(proto, buf, str, length, byte_order) ({ \
length = LOAD_PTR(buf, byte_order); \ length = LOAD_PTR(buf, byte_order); \
log(L_INFO "LOAD_STR(), %p %u", proto->p.pool, length + 1); \ log(L_INFO "LOAD_STR(), %p %u", proto->p.pool, length + 1); \
str = mb_alloc(proto->p.pool, length + 1); \ str = mb_alloc(proto->p.pool, length + 1); \
memcpy(str, buf, length); \ memcpy(str, buf+4, length); \
str[length] = '\0'; /* set term. char */ \ str[length] = '\0'; /* set term. char */ \
buf += snmp_str_size_from_len(length); }) buf += 4 + snmp_str_size_from_len(length); })
#define SNMP_LOAD_CONTEXT(proto, hdr, buf, cont, cont_len) \ #define SNMP_LOAD_CONTEXT(hdr, buf, cont, cont_len) ({ \
if ((hdr)->flags & AGENTX_NON_DEFAULT_CONTEXT) \
LOAD_STR((buf), (cont), (cont_len), \
(hdr)->flags & AGENTX_NETWORK_BYTE_ORDER); })
#define SNMP_COPY_CONTEXT(proto, hdr, buf, cont, cont_len) ({ \
cont = NULL; cont_len = 0; \ cont = NULL; cont_len = 0; \
if (hdr->flags & AGENTX_NON_DEFAULT_CONTEXT) \ if (hdr->flags & AGENTX_NON_DEFAULT_CONTEXT) \
LOAD_STR(proto, buf, cont, cont_len, \ COPY_STR(proto, buf, cont, cont_len, \
hdr->flags & AGENTX_NETWORK_BYTE_ORDER) (hdr)->flags & AGENTX_NETWORK_BYTE_ORDER) })
#define SNMP_HAS_CONTEXT(hdr) \ #define SNMP_HAS_CONTEXT(hdr) \
hdr->flags |= AGENTX_NON_DEFAULT_CONTEXT hdr->flags |= AGENTX_NON_DEFAULT_CONTEXT
#define SNMP_NON_DEFAULT_CONTEXT(hdr,pdu,contid) ({ \
if (contid) { \
SNMP_HAS_CONTEXT(hdr); \
snmp_put_str((c).buffer, (sc)->context); \
ADVANCE((c).buffer, (c).size, snmp_str_size((sc)->context)); \
} })
#define SNMP_PUT_OID(buf, size, oid, byte_ord) \ #define SNMP_PUT_OID(buf, size, oid, byte_ord) \
({ \ ({ \
struct agentx_varbind *vb = (void *) buf; \ struct agentx_varbind *vb = (void *) buf; \
@ -191,8 +212,7 @@ struct agentx_close_pdu {
u8 reason; u8 reason;
}; };
struct agentx_un_register_pdu { struct agentx_un_register_hdr {
struct agentx_header h;
u8 timeout; u8 timeout;
u8 priority; u8 priority;
u8 range_subid; u8 range_subid;
@ -280,13 +300,8 @@ enum agentx_response_err {
AGENTX_RES_PROCESSING_ERR = 268, AGENTX_RES_PROCESSING_ERR = 268,
} PACKED; } PACKED;
struct agentx_context { /* SNMP PDU buffer info */
char *context; /* string name of this context */ struct snmp_pdu {
uint length; /* normal strlen() size */
/* XXX add buffered context hash? */
};
struct snmp_pdu_context {
byte *buffer; /* pointer to buffer */ byte *buffer; /* pointer to buffer */
uint size; /* unused space in buffer */ uint size; /* unused space in buffer */
uint context; /* context hash */ uint context; /* context hash */
@ -305,11 +320,11 @@ struct agentx_alloc_context {
int snmp_rx(sock *sk, uint size); int snmp_rx(sock *sk, uint size);
int snmp_rx_stop(sock *sk, uint size); int snmp_rx_stop(sock *sk, uint size);
void snmp_down(struct snmp_proto *p); void snmp_down(struct snmp_proto *p);
void snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 is_instance); void snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 is_instance, uint contid);
void snmp_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len); void snmp_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len, uint contid);
void snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, int include_uptime); void snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, int include_uptime);
void snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu_context *c); void snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu *c);
struct oid *snmp_prefixize(struct snmp_proto *p, const struct oid *o, int byte_ord); struct oid *snmp_prefixize(struct snmp_proto *p, const struct oid *o, int byte_ord);
u8 snmp_get_mib_class(const struct oid *oid); u8 snmp_get_mib_class(const struct oid *oid);