diff --git a/proto/snmp/bgp_mib.c b/proto/snmp/bgp_mib.c index 073b3c5d..c9912bca 100644 --- a/proto/snmp/bgp_mib.c +++ b/proto/snmp/bgp_mib.c @@ -13,6 +13,8 @@ #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", @@ -164,15 +166,16 @@ snmp_bgp_register(struct snmp_proto *p) { 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)); @@ -180,9 +183,37 @@ snmp_bgp_register(struct snmp_proto *p) 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 @@ -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 -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; @@ -937,7 +979,7 @@ snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, ui 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); @@ -1202,7 +1244,7 @@ temp, temp, pkt); 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); diff --git a/proto/snmp/bgp_mib.h b/proto/snmp/bgp_mib.h index d2223498..750b168c 100644 --- a/proto/snmp/bgp_mib.h +++ b/proto/snmp/bgp_mib.h @@ -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); 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); diff --git a/proto/snmp/config.Y b/proto/snmp/config.Y index 3d9fc122..b71a9850 100644 --- a/proto/snmp/config.Y +++ b/proto/snmp/config.Y @@ -16,10 +16,12 @@ CF_DEFINES #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 @@ -66,6 +68,8 @@ snmp_proto_start: proto_start SNMP 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); @@ -80,18 +84,61 @@ snmp_proto_start: proto_start SNMP 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 : ""); + 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 diff --git a/proto/snmp/snmp.c b/proto/snmp/snmp.c index 02532d3d..33fa0d93 100644 --- a/proto/snmp/snmp.c +++ b/proto/snmp/snmp.c @@ -108,9 +108,13 @@ snmp_init(struct proto_config *CF) 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; } @@ -130,7 +134,30 @@ snmp_cleanup(struct snmp_proto *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); } @@ -312,16 +339,29 @@ snmp_start(struct proto *P) /* 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; @@ -330,9 +370,30 @@ snmp_start(struct proto *P) 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; } @@ -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 *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)) @@ -391,7 +473,7 @@ snmp_show_proto_info(struct proto *P) 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); diff --git a/proto/snmp/snmp.h b/proto/snmp/snmp.h index 96f71611..5dbfd706 100644 --- a/proto/snmp/snmp.h +++ b/proto/snmp/snmp.h @@ -51,10 +51,17 @@ enum snmp_proto_state { /* 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 { @@ -67,15 +74,21 @@ 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; }; @@ -93,6 +106,14 @@ struct snmp_registered_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 proto p; struct object_lock *lock; @@ -121,6 +142,9 @@ struct snmp_proto { // 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; diff --git a/proto/snmp/snmp_utils.c b/proto/snmp/snmp_utils.c index b4eb41df..c678f89d 100644 --- a/proto/snmp/snmp_utils.c +++ b/proto/snmp/snmp_utils.c @@ -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)); } +/* 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) @@ -208,14 +210,13 @@ snmp_put_nstr(byte *buf, const char *str, uint len) { 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; } @@ -415,7 +416,7 @@ snmp_register_same(struct snmp_register *r, struct agentx_header *h, u8 class) } 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()"); @@ -428,7 +429,7 @@ h->packet_id); // 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)); @@ -575,3 +576,48 @@ snmp_search_res_to_type(enum snmp_search_res 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; +} diff --git a/proto/snmp/snmp_utils.h b/proto/snmp/snmp_utils.h index ba38cd25..95fec870 100644 --- a/proto/snmp/snmp_utils.h +++ b/proto/snmp/snmp_utils.h @@ -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_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); @@ -46,7 +46,7 @@ void snmp_oid_dump(struct oid *oid); 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); @@ -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); +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 diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index 5da528e6..75839d80 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -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 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 }; @@ -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); 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) */ @@ -94,6 +94,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid) 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); @@ -123,7 +124,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in { 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] } )*/ @@ -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; 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; @@ -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); uint s = update_packet_size(p, sk->tbuf, c.buffer); - int ret = sk_send(sk, s); if (ret > 0) 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 */ 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); @@ -243,22 +253,28 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 } 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 : ""); + + 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)); @@ -284,23 +300,23 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 /* 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) @@ -475,13 +491,13 @@ refresh_ids(struct snmp_proto *p, struct agentx_header *h) * @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; @@ -540,7 +556,8 @@ parse_response(struct snmp_proto *p, byte *res, uint size) 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; } @@ -562,13 +579,6 @@ parse_response(struct snmp_proto *p, byte *res, uint 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 snmp_register_mibs(struct snmp_proto *p) { @@ -580,7 +590,7 @@ 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; @@ -607,14 +617,28 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED) 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); @@ -622,11 +646,9 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED) break; case SNMP_CONN: - // proto_notify_state(&p->p, PS_UP); break; case SNMP_STOP: - snmp_down(p); break; default: @@ -653,7 +675,7 @@ snmp_get_mib_class(const struct oid *oid) 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; @@ -721,7 +743,7 @@ snmp_get_next2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, 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) { @@ -834,6 +856,7 @@ response_err_ind(struct agentx_response *res, uint err, uint ind) 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; @@ -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); 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 @@ -1040,7 +1063,6 @@ send: p->partial_response = NULL; - mb_free(context); mb_free(o_start); mb_free(o_end); @@ -1064,9 +1086,9 @@ partial: wait: - mb_free(context); mb_free(o_start); mb_free(o_end); + p->packet_id--; /* we did not use the packetID */ return 0; } @@ -1163,7 +1185,7 @@ snmp_ping(struct snmp_proto *p) 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); @@ -1180,6 +1202,7 @@ snmp_ping(struct snmp_proto *p) 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!"); @@ -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)*/ 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()"); @@ -1344,16 +1367,13 @@ snmp_prefixize(struct snmp_proto *proto, const struct oid *oid, int byte_ord) 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)) @@ -1384,7 +1404,7 @@ snmp_mib_fill2(struct snmp_proto *p, struct oid *oid, * 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; @@ -1403,7 +1423,7 @@ snmp_tx(sock UNUSED *sk) 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()"); diff --git a/proto/snmp/subagent.h b/proto/snmp/subagent.h index 1664df94..537e6604 100644 --- a/proto/snmp/subagent.h +++ b/proto/snmp/subagent.h @@ -27,6 +27,8 @@ void snmp_ping(struct snmp_proto *p); extern u32 snmp_internet[4]; +#define SNMP_DEFAULT_CONTEXT 0 + enum SNMP_CLASSES { SNMP_CLASS_INVALID = 0, SNMP_CLASS_BGP = 1, @@ -64,6 +66,9 @@ enum snmp_search_res { #define AGENTX_PRIORITY 127 +#define SNMP_REGISTER_TREE 0 +#define SNMP_REGISTER_INSTANCE 1 + #define 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_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) @@ -104,23 +109,39 @@ enum snmp_search_res { #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(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; \ 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; \ @@ -191,8 +212,7 @@ struct agentx_close_pdu { u8 reason; }; -struct agentx_un_register_pdu { - struct agentx_header h; +struct agentx_un_register_hdr { u8 timeout; u8 priority; u8 range_subid; @@ -280,13 +300,8 @@ enum agentx_response_err { 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 */ @@ -305,11 +320,11 @@ struct agentx_alloc_context { 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);