#include "subagent.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 */
static const char * const debug_bgp_states[] UNUSED = {
[BGP_INTERNAL_INVALID] = "BGP_INTERNAL_INVALID",
{
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 */
struct snmp_register *registering = snmp_register_create(p, SNMP_BGP4_MIB);
struct oid *oid = mb_alloc(p->p.pool, snmp_oid_sizeof(2));
- put_u8(&oid->n_subid, 2);
- put_u8(&oid->prefix, 2);
+ STORE_U8(oid->n_subid, 2);
+ STORE_U8(oid->prefix, SNMP_MGMT);
memcpy(oid->ids, bgp_mib_prefix, 2 * sizeof(u32));
add_tail(&p->register_queue, ®istering->n);
p->register_to_ack++;
- /* snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 is_instance) */
- snmp_register(p, oid, 0, 1, 0);
+ /* snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 is_instance, uint contid) */
+ 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, ®istering->n);
+ p->register_to_ack++;
+ }
+ HASH_WALK_END;
}
static int
);
}
+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
-print_bgp_record(struct bgp_config *config)
+print_bgp_record(const struct bgp_config *config)
{
struct proto_config *cf = (struct proto_config *) config;
struct bgp_proto *bgp_proto = (struct bgp_proto *) cf->proto;
static byte *
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;
uint size = c->size - snmp_varbind_header_size(vb);
void
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);
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);
-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_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp);
#define SNMP_CFG ((struct snmp_config *) this_proto)
+struct snmp_bond *this_bond = NULL;
+
CF_DECLS
CF_KEYWORDS(SNMP, PROTOCOL, BPG, LOCAL, AS, REMOTE, ADDRESS, PORT, DESCRIPTION,
- TIMEOUT, PRIORITY)
+ TIMEOUT, PRIORITY, CONTEXT, DEFAULT)
CF_GRAMMAR
init_list(&SNMP_CFG->bgp_entries);
SNMP_CFG->bonds = 0;
+ /* We always have the default context */
+ SNMP_CFG->contexts = 1;
SNMP_CFG->local_ip = IPA_NONE;
SNMP_CFG->remote_ip = ipa_build4(127,0,0,1);
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;
cf_assert_symbol($2, SYM_PROTO);
this_bond->proto = $2->proto;
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++;
+
+ this_bond = NULL;
}
CF_CODE
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);
+ /* used when assigning the context ids in s_cont_create() */
+ p->context_max = 1;
+ p->context_id_map = NULL;
+
return P;
}
rfree(p->lock);
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);
}
/* We create copy of bonds to BGP protocols. */
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;
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))
{
struct snmp_bgp_peer *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;
struct net_addr net;
trie_add_prefix(p->bgp_trie, &net, IP4_MAX_PREFIX_LENGTH, IP4_MAX_PREFIX_LENGTH);
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);
return PS_START;
}
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);
+ 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),
((byte *) new) + sizeof(struct proto_config),
OFFSETOF(struct snmp_config, description) - sizeof(struct proto_config))
cli_msg(-1006, " in total: %u", bp->stats.rx_messages);
cli_msg(-1006, " out total: %u", bp->stats.tx_messages);
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, " retry interval: %u", bcf->connect_retry_time);
/* hash table only store ip4 addresses */
#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 {
node n;
struct proto_config *proto;
u8 type;
+ const char *context;
};
struct snmp_config {
u8 timeout;
u8 priority;
//struct iface *iface;
+ u32 bonds;
+ uint contexts; /* Number of all conetexts including the default */
const char *description;
list bgp_entries;
- u32 bonds;
// TODO add support for subagent oid identification
};
+#define SNMP_BGP_P_REGISTERING 0x01
+#define SNMP_BGP_P_REGISTERED 0x02
+
struct snmp_bgp_peer {
- struct bgp_config *config;
+ const struct bgp_config *config;
ip_addr peer_ip;
+ uint context_id;
+ u8 flags;
struct snmp_bgp_peer *next;
};
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 proto p;
struct object_lock *lock;
// map
struct f_trie *bgp_trie;
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;
timer *ping_timer;
return hdr_size + snmp_str_size_from_len(LOAD_PTR(data, byte_ord));
}
+/*
inline uint
snmp_context_size(struct agentx_context *c)
{
return (c && c->length) ? snmp_str_size_from_len(c->length) : 0;
}
+*/
struct agentx_varbind *
snmp_create_varbind(byte *buf, struct oid *oid)
{
uint alen = BIRD_ALIGN(len, 4);
- // TODO check for '\0' in the str bytes?
STORE_PTR(buf, len);
buf += 4;
memcpy(buf, str, len);
/* Insert zero padding in the gap at the end */
for (uint i = 0; i < alen - len; i++)
- buf[len + i] = 0x00;
+ buf[len + i] = '\0';
return buf + alen;
}
}
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()");
// TODO add support for more mib trees (other than BGP)
snmp_log("checking registration request sid: %u tid: %u pid: %u",
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 = \
mb_alloc(p->p.pool, sizeof(struct snmp_registered_oid));
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;
+}
uint snmp_varbind_hdr_size_from_oid(struct oid *oid);
uint snmp_varbind_header_size(struct agentx_varbind *vb);
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);
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_counter32(struct agentx_varbind *vb, uint size, u32 val);
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);
int agentx_type_size(enum agentx_type t);
+
+
#endif
*
*/
-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 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_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 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 };
const struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf);
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;
/* +4 for timeout (1B with 4B alignment) */
buf = c.buffer;
}
+ /* Function open_pdu() does not generate agentx_pkt. */
struct agentx_header *h = (struct agentx_header *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
SNMP_BLANK_HEADER(h, AGENTX_OPEN_PDU);
{
sock *sk = p->sock;
- struct snmp_pdu_context c = SNMP_PDU_CONTEXT(sk);
+ struct snmp_pdu c = SNMP_PDU_CONTEXT(sk);
#define UPTIME_SIZE \
(6 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[4] } )*/
struct agentx_header *h = (struct agentx_header *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
SNMP_BLANK_HEADER(h, AGENTX_NOTIFY_PDU);
+ p->packet_id++;
SNMP_SESSION(h, p);
c.byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER;
ADVANCE(c.buffer, c.size, size);
uint s = update_packet_size(p, sk->tbuf, c.buffer);
-
int ret = sk_send(sk, s);
if (ret > 0)
snmp_log("sk_send OK!");
/* Register-PDU / Unregister-PDU */
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);
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;
/* 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_manage_tbuf(p, &c);
}
snmp_log("un_register_pdu()");
- struct agentx_un_register_pdu *ur = (struct agentx_un_register_pdu *)c.buffer;
- ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_pdu));
- struct agentx_header *h = &ur->h;
+ struct agentx_header *h = (struct agentx_header *) c.buffer;
+ ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
SNMP_HEADER(h, type, is_instance ? AGENTX_FLAG_INSTANCE_REGISTRATION : 0);
- /* use new transactionID, reset packetID */
p->packet_id++;
SNMP_SESSION(h, p);
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 */
STORE_U8(ur->timeout, p->timeout);
/* default priority */
STORE_U8(ur->priority, cf->priority);
STORE_U8(ur->range_subid, (len > 1) ? index : 0);
STORE_U8(ur->pad, 0);
+ ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_hdr));
snmp_put_oid(c.buffer, oid);
ADVANCE(c.buffer, c.size, snmp_oid_size(oid));
/* Register-PDU */
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 */
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
close_pdu(struct snmp_proto *p, u8 reason)
{
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;
snmp_log("close_pdu() size: %u %c %u", c.size, (c.size > AGENTX_HEADER_SIZE + 4)
* @size: number of packet bytes in buffer
* 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.
*/
static uint
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)
return 0;
uint pkt_size = LOAD_U32(h->payload, byte_ord);
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");
return 0;
}
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
snmp_register_mibs(struct snmp_proto *p)
{
}
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()");
struct agentx_response *r = (void *) buf;
p->state = SNMP_REGISTER;
snmp_register_mibs(p);
snmp_log("do_response state SNMP_INIT register list %u", list_length(&p->register_queue));
-
break;
case SNMP_REGISTER:
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");
p->state = SNMP_CONN;
proto_notify_state(&p->p, PS_UP);
break;
case SNMP_CONN:
- // proto_notify_state(&p->p, PS_UP);
break;
case SNMP_STOP:
- snmp_down(p);
break;
default:
static void
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()");
enum snmp_search_res r;
static void
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)
{
static uint
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()");
struct oid *o_start = NULL, *o_end = NULL;
uint pkt_size = LOAD_U32(h->payload, h->flags & AGENTX_NETWORK_BYTE_ORDER);
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
c.byte_ord = 0; /* use little-endian */
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 */
- 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
p->partial_response = NULL;
- mb_free(context);
mb_free(o_start);
mb_free(o_end);
wait:
- mb_free(context);
mb_free(o_start);
mb_free(o_end);
+ p->packet_id--; /* we did not use the packetID */
return 0;
}
sock *sk = p->sock;
snmp_dump_packet(sk->tpos, AGENTX_HEADER_SIZE + 4);
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)
snmp_manage_tbuf(p, &c);
snmp_dump_packet(sk->tpos, AGENTX_HEADER_SIZE + 4);
/* sending only header -> pkt - buf */
uint s = update_packet_size(p, sk->tpos, c.buffer);
+
int ret = sk_send(sk, s);
if (ret > 0)
snmp_log("sk_send OK!");
working only with o_start, o_end allocated in heap (not from buffer)*/
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,
+ struct oid *o_curr, struct snmp_pdu *c,
enum snmp_search_res *result)
{
snmp_log("search_mib()");
static void
snmp_mib_fill2(struct snmp_proto *p, struct oid *oid,
- struct snmp_pdu_context *c)
+ struct snmp_pdu *c)
{
ASSUME(oid != NULL);
- snmp_log("critical part");
if (c->size < snmp_varbind_hdr_size_from_oid(oid))
snmp_manage_tbuf(p, c);
- snmp_log("critical part done");
-
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))
* are invalidated!
*/
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()");
sock *sk = p->sock;
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()");
extern u32 snmp_internet[4];
+#define SNMP_DEFAULT_CONTEXT 0
+
enum SNMP_CLASSES {
SNMP_CLASS_INVALID = 0,
SNMP_CLASS_BGP = 1,
#define AGENTX_PRIORITY 127
+#define SNMP_REGISTER_TREE 0
+#define SNMP_REGISTER_INSTANCE 1
+
#define SNMP_NATIVE
#ifdef SNMP_NATIVE
#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->transaction_id, p->transaction_id); \
STORE_U32(h->packet_id, p->packet_id)
#define LOAD_U16(v, bo) ((bo) ? get_u16(&v) : (u16) (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); \
log(L_INFO "LOAD_STR(), %p %u", 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 */ \
- buf += snmp_str_size_from_len(length); })
+ buf += 4 + snmp_str_size_from_len(length); })
+
+#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_LOAD_CONTEXT(proto, hdr, buf, cont, cont_len) \
+#define SNMP_COPY_CONTEXT(proto, hdr, buf, cont, cont_len) ({ \
cont = NULL; cont_len = 0; \
if (hdr->flags & AGENTX_NON_DEFAULT_CONTEXT) \
- LOAD_STR(proto, buf, cont, cont_len, \
- hdr->flags & AGENTX_NETWORK_BYTE_ORDER)
+ COPY_STR(proto, buf, cont, cont_len, \
+ (hdr)->flags & AGENTX_NETWORK_BYTE_ORDER) })
#define SNMP_HAS_CONTEXT(hdr) \
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) \
({ \
struct agentx_varbind *vb = (void *) buf; \
u8 reason;
};
-struct agentx_un_register_pdu {
- struct agentx_header h;
+struct agentx_un_register_hdr {
u8 timeout;
u8 priority;
u8 range_subid;
AGENTX_RES_PROCESSING_ERR = 268,
} PACKED;
-struct agentx_context {
- char *context; /* string name of this context */
- uint length; /* normal strlen() size */
- /* XXX add buffered context hash? */
-};
-
-struct snmp_pdu_context {
+/* SNMP PDU buffer info */
+struct snmp_pdu {
byte *buffer; /* pointer to buffer */
uint size; /* unused space in buffer */
uint context; /* context hash */
int snmp_rx(sock *sk, uint size);
int snmp_rx_stop(sock *sk, uint size);
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_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len);
+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, uint contid);
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);
u8 snmp_get_mib_class(const struct oid *oid);