From df28d1cbe89d2bf4cadf61eb00e24caa637fe2cc Mon Sep 17 00:00:00 2001 From: Vojtech Vilimek Date: Mon, 4 Sep 2023 09:25:51 +0200 Subject: [PATCH] Testing Notify-PDU --- proto/snmp/bgp_mib.c | 39 +-- proto/snmp/snmp.c | 91 +++++- proto/snmp/snmp.h | 13 + proto/snmp/subagent.c | 657 ++++++++++++++++++++++++++++++------------ 4 files changed, 589 insertions(+), 211 deletions(-) diff --git a/proto/snmp/bgp_mib.c b/proto/snmp/bgp_mib.c index 4ba03846..5247acbd 100644 --- a/proto/snmp/bgp_mib.c +++ b/proto/snmp/bgp_mib.c @@ -70,9 +70,7 @@ snmp_bgp_register(struct snmp_proto *p) add_tail(&p->register_queue, ®istering->n); p->register_to_ack++; - /* Function declartion: - * 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) */ snmp_register(p, oid, 0, 1, 0); } } @@ -114,11 +112,10 @@ bgp_get_candidate(u32 field) }; /* - * First value is in secord cell of array translation_table (as the + * First value is in secord cell of array translation_table, as the * SNMP_BPG_IDENTIFIER == 1 */ - if (field > 0 && - field <= sizeof(translation_table)/sizeof(translation_table[0]) - 1) + if (field > 0 && field <= sizeof(translation_table) / sizeof(translation_table[0]) - 1) return translation_table[field]; if (field == 0) return BGP_INTERNAL_INVALID; @@ -193,6 +190,7 @@ print_bgp_record_all(struct snmp_proto *p) snmp_log("dumping watched end"); } + /** * snmp_bgp_state - linearize oid from BGP4-MIB * @oid: prefixed object identifier from BGP4-MIB::bgp subtree @@ -402,7 +400,7 @@ update_bgp_oid(struct oid *oid, u8 state) state == BGP_INTERNAL_NO_VALUE) return oid; - /* No need to reallocate anything if the OID is has same lin. state */ + /* No need to reallocate anything if the OID has same lin. state */ if (snmp_bgp_state(oid) == state) { if (state >= BGP_INTERNAL_IDENTIFIER && @@ -537,6 +535,7 @@ update_bgp_oid(struct oid *oid, u8 state) default: /* intentionally left blank */ break; + //die("update unavailable"); } return oid; @@ -590,10 +589,7 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, const struct oid if (cmp < 0 || (cmp == 0 && snmp_is_oid_empty(o_end))) { snmp_log("ip4_less() returned true"); - struct oid *o = mb_allocz(p->p.pool, snmp_oid_sizeof(9)); - o->n_subid = 9; - - memcpy(o, o_start, snmp_oid_size(o_start)); + struct oid *o = snmp_oid_duplicate(p->p.pool, o_start); snmp_oid_ip4_index(o, 5, net4_prefix(&net)); return o; @@ -627,7 +623,7 @@ UNUSED, u8 current_state) snmp_oid_dump(o_start); next_state = snmp_bgp_next_state(next_state); - /* We search in next state is done from beginning. */ + /* The search in next state is done from beginning. */ o_start->ids[5] = o_start->ids[6] = o_start->ids[7] = o_start->ids[8] = 0; o_start->include = 1; @@ -647,7 +643,6 @@ UNUSED, u8 current_state) static int snmp_bgp_find_next_oid(struct snmp_proto *p, struct oid *oid, uint UNUSED contid) { - // TODO add o_end paramenter for faster searches ip4_addr ip4 = ip4_from_oid(oid); //ip_add4 dest = ip4_from_u32(0xFFFFFFFF); @@ -722,7 +717,7 @@ snmp_bgp_search_dynamic(struct snmp_proto *p, struct oid **searched, const struc oid->ids[5] = oid->ids[6] = oid->ids[7] = oid->ids[8] = 0; } - if (next_state <= end_state) + if (next_state < BGP_INTERNAL_END && next_state <= end_state) { *searched = oid; return SNMP_SEARCH_OK; @@ -740,6 +735,11 @@ snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid * struct oid *oid = *searched; snmp_log("snmp_bgp_search2() with state %s [%d]", debug_bgp_states[bgp_state], bgp_state); + if (bgp_state == BGP_INTERNAL_END) + { + return SNMP_SEARCH_NO_OBJECT; + } + /* TODO remove todo below, then remove this code */ if (is_dynamic(bgp_state)) { @@ -773,7 +773,8 @@ snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid * oid = *searched = update_bgp_oid(*searched, bgp_state); if (oid->n_subid == 3 && oid->ids[2] >= SNMP_BGP_VERSION && - oid->ids[2] <= SNMP_BGP_LOCAL_AS) + oid->ids[2] <= SNMP_BGP_LOCAL_AS && bgp_state != BGP_INTERNAL_END) + //oid->ids[2] <= SNMP_BGP_LOCAL_AS && bgp_state != BGP_INTERNAL_END) { snmp_log("oid matches static state"); oid->include = 0; @@ -789,8 +790,8 @@ struct oid * snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid UNUSED) { u8 start_state = snmp_bgp_state(o_start); - //u8 state_curr = snmp_bgp_state(o_start); - //u8 state_end = (o_end) ? snmp_bgp_state(o_end) : 0; + + // print debugging information print_bgp_record_all(p); if (o_start->include && snmp_bgp_has_value(start_state) && @@ -808,7 +809,7 @@ snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, ui return search_bgp_dynamic(p, o_start, o_end, contid, start_state); } - /* o_start->include == 0 */ + /* o_start is not inclusive */ u8 next_state = snmp_bgp_next_state(start_state); // TODO more checks ?!? @@ -844,6 +845,8 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb, } snmp_log(" -> ip addr %I", addr); + // TODO XXX deal with possible change of (remote) ip; BGP should restart and + // disappear struct snmp_bgp_peer *pe = HASH_FIND(p->bgp_hash, SNMP_HASH, addr); struct bgp_proto *bgp_proto = NULL; diff --git a/proto/snmp/snmp.c b/proto/snmp/snmp.c index 7cfd63b8..b46cc0ba 100644 --- a/proto/snmp/snmp.c +++ b/proto/snmp/snmp.c @@ -7,6 +7,68 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ +/** + * Simple Network Management Protocol State Machine + * + * States with main transitions + * + * + * +-----------------+ + * | SNMP_INIT | entry state after call snmp_start() + * +-----------------+ + * | + * | acquiring object lock for communication socket + * V + * +-----------------+ + * | SNMP_LOCKED | object lock aquired + * +-----------------+ + * | + * | opening communaiton socket + * V + * +-----------------+ + * | SNMP_OPEN | socket created, starting subagent + * +-----------------+ + * | + * | BIRD recieve response for Open-PDU + * V + * +-----------------+ + * | SNMP_REGISTER | session was established, subagent registers MIBs + * +-----------------+ + * | + * | subagent recieved responses for all registration requests + * V + * +-----------------+ + * | SNMP_CONN | everything is set + * +-----------------+ + * | + * | function snmp_shutdown() is called, BIRD sends Close-PDU + * V + * +-----------------+ + * | SNMP_STOP | waiting for response + * +-----------------+ + * | + * | cleaning old state information + * V + * +-----------------+ + * | SNMP_DOWN | session is closed + * +-----------------+ + * + * + * Erroneous transitions: + * SNMP is UP in states SNMP_CONN and also in SNMP_REGISTER because the + * session is establised and the GetNext request should be responsed + * without regard to MIB registration. + * + * When the session has been closed for some reason (socket error, reciept of + * Close-PDU) SNMP cleans the session information and message queue and goes + * back to the SNMP_LOCKED state. + * + * Reconfiguration is done in similar fashion to BGP, the reconfiguration + * request is declined, the protocols is stoped and started with new + * configuration. + * + */ + #include "nest/bird.h" #include "nest/cli.h" #include "nest/locks.h" @@ -26,6 +88,15 @@ static void snmp_start_locked(struct object_lock *lock); static int snmp_shutdown(struct proto *P); static const char * const snmp_state[] = { + [SNMP_ERR] = "SNMP ERROR", + [SNMP_INIT] = "SNMP INIT", + [SNMP_LOCKED] = "SNMP LOCKED", + [SNMP_OPEN] = "SNMP CONNECTION OPENED", + [SNMP_REGISTER] = "SNMP REGISTERING MIBS", + [SNMP_CONN] = "SNMP CONNECTED", + [SNMP_STOP] = "SNMP STOPING", + [SNMP_DOWN] = "SNMP DOWN", +/* [SNMP_ERR] = "SNMP ERROR", [SNMP_DELAY] = "SNMP DELAY", [SNMP_INIT] = "SNMP INIT", @@ -34,6 +105,7 @@ static const char * const snmp_state[] = { [SNMP_STOP] = "SNMP STOP", [SNMP_DOWN] = "SNMP DOWN", [SNMP_LISTEN] = "SNMP LISTEN", +*/ }; static struct proto * @@ -110,10 +182,12 @@ snmp_startup(struct snmp_proto *p) { //snmp_log("changing proto_snmp state to INIT"); - if (p->state == SNMP_CONN || - p->state == SNMP_REGISTER) + if (p->state == SNMP_LOCKED || + p->state == SNMP_OPEN || + p->state == SNMP_REGISTER || + p->state == SNMP_CONN) { - snmp_log("startup() with invalid state %u", p->state); + snmp_log("startup() already in connected state %u", p->state); return; } @@ -151,6 +225,8 @@ snmp_start_locked(struct object_lock *lock) snmp_log("snmp_start_locked() - lock acquired; preparing socket"); struct snmp_proto *p = lock->data; + p->state = SNMP_LOCKED; + sock *s = sk_new(p->p.pool); s->type = SK_TCP_ACTIVE; s->saddr = p->local_ip; @@ -185,6 +261,9 @@ snmp_connected(sock *sk) { struct snmp_proto *p = sk->data; snmp_log("snmp_connected() connection created"); + + p->state = SNMP_OPEN; + byte *buf UNUSED = sk->rpos; sk->rx_hook = snmp_rx; @@ -392,8 +471,8 @@ snmp_shutdown(struct proto *P) tm_stop(p->ping_timer); /* connection established -> close the connection */ - if (p->state == SNMP_CONN || - p->state == SNMP_REGISTER) + if (p->state == SNMP_REGISTER || + p->state == SNMP_CONN) { p->state = SNMP_STOP; @@ -407,7 +486,6 @@ snmp_shutdown(struct proto *P) return PS_STOP; } - /* no connection to close */ else { @@ -435,3 +513,4 @@ snmp_build(void) { proto_build(&proto_snmp); } + diff --git a/proto/snmp/snmp.h b/proto/snmp/snmp.h index 0c767a7b..e7b5a441 100644 --- a/proto/snmp/snmp.h +++ b/proto/snmp/snmp.h @@ -31,6 +31,17 @@ enum snmp_proto_state { SNMP_ERR = 0, + + SNMP_INIT = 1, + SNMP_LOCKED, + SNMP_OPEN, + SNMP_REGISTER, + SNMP_CONN, + SNMP_STOP, + SNMP_DOWN, + +/* + SNMP_ERR = 0, SNMP_DELAY, SNMP_INIT, SNMP_REGISTER, @@ -38,6 +49,8 @@ enum snmp_proto_state { SNMP_STOP, SNMP_DOWN, SNMP_LISTEN, + SNMP_RESET, +*/ }; /* hash table macros */ diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index 2a08a70d..0d0ab8bc 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -27,7 +27,6 @@ * */ - static void snmp_mib_fill2(struct snmp_proto *p, struct oid *oid, struct snmp_pdu_context *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); @@ -37,6 +36,7 @@ static struct agentx_response *prepare_response(struct snmp_proto *p, struct snm 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 void notify_pdu(struct snmp_proto *p, struct oid *oid, void *opaque, uint size, int include_uptime); static const char * const snmp_errs[] = { #define SNMP_ERR_SHIFT 256 @@ -80,6 +80,7 @@ static void open_pdu(struct snmp_proto *p, struct oid *oid) { sock *sk = p->sock; + struct snmp_pdu_context c = { .buffer = sk->tpos, .size = sk->tbuf + sk->tbsize - sk->tpos, @@ -90,8 +91,10 @@ open_pdu(struct snmp_proto *p, struct oid *oid) const char *str = "bird"; /* +4 for timeout (1B with 4B alignment) */ - if (c.size < AGENTX_HEADER_SIZE + snmp_oid_size(oid) + snmp_str_size(str) + 4) + if (c.size < AGENTX_HEADER_SIZE + 4 + snmp_oid_size(oid) + snmp_str_size(str)) { + return; + // TODO create and add message info into message queue snmp_manage_tbuf(p, &c); buf = c.buffer; } @@ -109,7 +112,6 @@ open_pdu(struct snmp_proto *p, struct oid *oid) c.buffer = snmp_put_oid(c.buffer, oid); c.buffer = snmp_put_str(c.buffer, str); - snmp_log("send PDU data (open) ..."); uint s = update_packet_size(p, buf, c.buffer); int ret = sk_send(sk, s); if (ret > 0) @@ -120,103 +122,136 @@ open_pdu(struct snmp_proto *p, struct oid *oid) snmp_log("sk_send error"); } -#if 0 -static int -de_allocate_pdu(struct snmp_proto *p, struct oid *oids[], uint len, - struct agentx_alloc_context *ac, u8 type) +static void +notify_pdu(struct snmp_proto *p, struct oid *oid, void *opaque, uint size, int include_uptime) { sock *sk = p->sock; - //byte *buf = sk->tbuf; - //uint size = sk->tbsize; - byte *buf = sk->tpos; - uint size = sk->tbuf + sk->tbsize - sk->tpos; - uint total_len = 0; - struct oid *o_curr = NULL; - for (uint i = 0; i < len; i++) + struct snmp_pdu_context c = { + .buffer = sk->tpos, + .size = sk->tbuf + sk->tbsize - sk->tpos, + }; + + if (c.size < AGENTX_HEADER_SIZE) { - o_curr = oids[i]; - uint sz = snmp_oid_size(o_curr); - total_len += sz; + snmp_manage_tbuf(p, &c); } - if (total_len == 0) - return 0; + struct agentx_header *h = (struct agentx_header *) c.buffer; + ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); + SNMP_BLANK_HEADER(h, AGENTX_NOTIFY_PDU); + SNMP_SESSION(h, p); - if (size < AGENTX_HEADER_SIZE + total_len) + c.byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER; + +#define UPTIME_SIZE \ + (6 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[4] } )*/ +#define TRAP0_HEADER_SIZE \ + (7 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[6] } ) */ + + uint sz = AGENTX_HEADER_SIZE + TRAP0_HEADER_SIZE + snmp_oid_size(oid) \ + + snmp_varbind_hdr_size_from_oid(oid) + size; + + if (include_uptime) + sz += UPTIME_SIZE; + + if (c.size < sz) + snmp_manage_tbuf(p, &c); + + if (include_uptime) { - // need bigger tx buffer (more mem) - return 0; + /* sysUpTime.0 oid */ + struct oid uptime = { + .n_subid = 4, + .prefix = 2, + .include = 0, + .pad = 0, + }; + u32 uptime_ids[] = { 1, 1, 3, 0 }; + + struct agentx_varbind *vb = snmp_create_varbind(c.buffer, &uptime); + for (uint i = 0; i < uptime.n_subid; i++) + STORE_U32(vb->name.ids[i], uptime_ids[i]); + ADVANCE(c.buffer, c.size, snmp_varbind_header_size(vb)); + snmp_varbind_ticks(vb, c.size, current_time() TO_S); + ADVANCE(c.buffer, c.size, agentx_type_size(AGENTX_TIME_TICKS)); } - int blank = AGENTX_FLAG_BLANK; - struct agentx_header *h; - SNMP_CREATE(buf, struct agentx_header, h); - SNMP_HEADER(h, type, - (ac->is_instance ? AGENTX_FLAG_INSTANCE_REGISTRATION : blank) - | (ac->new_index ? AGENTX_FLAG_NEW_INDEX : blank) - | (ac->any_index ? AGENTX_FLAG_ANY_INDEX : blank)); - ADVANCE(buf, size, AGENTX_HEADER_SIZE); - STORE(h->payload, total_len); + /* snmpTrapOID.0 oid */ + struct oid trap0 = { + .n_subid = 6, + .prefix = 6, + .include = 0, + .pad = 0, + }; + u32 trap0_ids[] = { 3, 1, 1, 4, 1, 0 }; + + struct agentx_varbind *trap_vb = snmp_create_varbind(c.buffer, &trap0); + for (uint i = 0; i < trap0.n_subid; i++) + STORE_U32(trap_vb->name.ids[i], trap0_ids[i]); + trap_vb->type = AGENTX_OBJECT_ID; + snmp_put_oid(SNMP_VB_DATA(trap_vb), oid); + ADVANCE(c.buffer, c.size, snmp_varbind_size(trap_vb, c.byte_ord)); - for (uint i = 0; i < len; i++) - { - o_curr = oids[i]; - // TODO fix copy to buffer - memcpy(buf, o_curr, snmp_oid_size(o_curr)); - ADVANCE(buf, size, snmp_oid_size(o_curr)); - } + // TODO fix the endianess + memcpy(c.buffer, opaque, size); + ADVANCE(c.buffer, c.size, (size + snmp_varbind_hdr_size_from_oid(oid))); - // increment p->packet_id - // queue the allocation request + uint s = update_packet_size(p, sk->tbuf, c.buffer); - int ret = sk_send(sk, total_len); - if (ret == 0) - { + int ret = sk_send(sk, s); + if (ret > 0) + snmp_log("sk_send OK!"); + else if (ret == 0) snmp_log("sk_send sleep"); - return 1; - } - else if (ret < 0) - { - snmp_log("sk_send err %d", ret); - return 1; - } else + snmp_log("sk_send error"); + +#undef TRAP0_HEADER_SIZE +#undef UPTIME_SIZE +} + +/* index allocate / deallocate pdu * / +static void +de_allocate_pdu(struct snmp_proto *p, struct oid *oid, u8 type) +{ + sock *sk = p->sock; + byte *buf, *pkt; + buf = pkt = sk->tbuf; + uint size = sk->tbsize; + + + if (size > AGENTX_HEADER_SIZE + ) { - snmp_log("sk_send ok !!"); - return 0; + snmp_log("de_allocate_pdu()"); + + struct agentx_header *h; + SNMP_CREATE(pkt, struct agentx_header, h); + SNMP_BLANK_HEADER(h, type); + SNMP_SESSION(h,p); + + struct agentx_varbind *vb = (struct agentx_varbind *) pkt; + STORE_16(vb->type, AGENTX_OBJECT_ID); + STORE(vb->oid, } -} -static int UNUSED -index_allocate_pdu(struct snmp_proto *p, struct oid *oids[], uint len, struct -agentx_alloc_context *ac) -{ - return de_allocate_pdu(p, oids, len, ac, AGENTX_INDEX_ALLOCATE_PDU); + else + snmp_log("de_allocate_pdu(): insufficient size"); } +*/ -static int UNUSED -index_deallocate_pdu(struct snmp_proto *p, struct oid *oids[], uint len, struct -agentx_alloc_context *ac) -{ - return de_allocate_pdu(p, oids, len, ac, AGENTX_INDEX_DEALLOCATE_PDU); -} -#endif - -/* Register-PDU / Unregister-PDU common code */ -static inline void +/* 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) { sock *sk = p->sock; - //buf = pkt = sk->tbuf; - //uint size = sk->tbsize; struct snmp_pdu_context c = { .buffer = sk->tpos, .size = sk->tbuf + sk->tbsize - sk->tpos, }; byte *buf = c.buffer; - /* conditional +4 for upper-bound */ + /* conditional +4 for upper-bound (optinal field) */ if (c.size < AGENTX_HEADER_SIZE + snmp_oid_size(oid) + ((len > 1) ? 4 : 0)) { snmp_log("un_register_pdu() insufficient size"); @@ -229,21 +264,22 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_pdu)); struct agentx_header *h = &ur->h; + // FIXME correctly set INSTANCE REGISTRATION bit SNMP_HEADER(h, type, is_instance ? AGENTX_FLAG_INSTANCE_REGISTRATION : 0); - /* use new packetID */ + /* use new transactionID, reset packetID */ p->packet_id++; SNMP_SESSION(h, p); /* do not override timeout */ STORE_U32(ur->timeout, 15); - /* We use default priority */ - STORE_U32(ur->priority, AGENTX_PRIORITY); // TODO configurable priority + /* default priority */ + STORE_U32(ur->priority, AGENTX_PRIORITY); STORE_U32(ur->range_subid, (len > 1) ? index : 0); snmp_put_oid(c.buffer, oid); ADVANCE(c.buffer, c.size, snmp_oid_size(oid)); - /* We place upper-bound if needed. */ + /* place upper-bound if needed */ if (len > 1) { STORE_PTR(c.buffer, len); @@ -262,7 +298,7 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 snmp_log("sk_send error"); } -/* Register-PDU */ +/* register pdu */ void snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 is_instance) { @@ -270,7 +306,7 @@ snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 is } -/* Unregister-PDU */ +/* unregister pdu */ void UNUSED snmp_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len) { @@ -379,7 +415,7 @@ addagentcaps_pdu(struct snmp_proto *p, struct oid *cap, char *descr, ADVANCE(buf, size, in_pkt); } - memcpy(buf, cap, snmp_oid_size(cap)); + // memcpy(buf, cap, snmp_oid_size(cap)); ADVANCE(buf, size, snmp_oid_size(cap)); in_pkt = snmp_put_nstr(buf, descr, descr_len) - buf; @@ -472,7 +508,8 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip) uint parsed_len = 0; struct agentx_header *h = (void *) pkt; - snmp_log("parse_pkt got type %s", snmp_pkt_type[h->type]); + snmp_log("parse_pkt got type %s (%d)", snmp_pkt_type[h->type], h->type); + snmp_log("parse_pkt rx size %u", size); snmp_dump_packet((void *)h, MIN(h->payload, 256)); switch (h->type) { @@ -481,10 +518,18 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip) parsed_len = parse_response(p, pkt, size); break; + /* + case AGENTX_GET_PDU: + refresh_ids(p, h); + return parse_get_pdu(p, pkt, size); + */ + case AGENTX_GET_PDU: case AGENTX_GET_NEXT_PDU: case AGENTX_GET_BULK_PDU: refresh_ids(p, h); + //parsed_len = parse_gets_pdu(p, &c); + //parsed_len = parse_gets_pdu(p, pkt, size, skip); parsed_len = parse_gets2_pdu(p, pkt, size, skip); break; @@ -504,7 +549,16 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip) //die("unknown packet type %u", h->type); } + /* We will process the same header again later * / + if (*skip || parsed_len < size) + { + / * We split our answer to multiple packet, we should differentiate them * / + h->packet_id++; + } + */ + snmp_log("parse_pkt returning parsed length"); + //snmp_dump_packet(p->sock->tbuf, 64); return parsed_len; } @@ -513,6 +567,8 @@ parse_response(struct snmp_proto *p, byte *res, uint size) { snmp_log("parse_response() g%u h%u", size, sizeof(struct agentx_header)); + //snmp_dump_packet(res, size); + if (size < sizeof(struct agentx_response)) return 0; @@ -539,7 +595,7 @@ parse_response(struct snmp_proto *p, byte *res, uint size) if (r->error == AGENTX_RES_NO_ERROR) do_response(p, res, size); else - /* Erronous packet should be dropped quietly. */ + /* erronous packet should be dropped quietly */ snmp_log("an error occured '%s'", snmp_errs[get_u16(&r->error) - SNMP_ERR_SHIFT]); return pkt_size + AGENTX_HEADER_SIZE; @@ -574,12 +630,16 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED) switch (p->state) { case SNMP_INIT: - /* We copy session info from recieved packet */ + case SNMP_LOCKED: + /* silent drop of recieved packet */ + break; + + case SNMP_OPEN: + /* copy session info from recieved packet */ p->session_id = LOAD_U32(h->session_id, byte_ord); refresh_ids(p, h); - /* - * The state needs to be changed before sending registering PDUs to + /* the state needs to be changed before sending registering PDUs to * use correct do_response action on them */ snmp_log("changing state to REGISTER"); @@ -596,6 +656,7 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED) if (snmp_registered_all(p)) { snmp_log("changing proto_snmp state to CONNECTED"); p->state = SNMP_CONN; + proto_notify_state(&p->p, PS_UP); } break; @@ -604,7 +665,7 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED) break; case SNMP_STOP: - /* do nothing here */ + snmp_shutdown(); break; default: @@ -615,10 +676,10 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED) u8 snmp_get_mib_class(const struct oid *oid) { + // TODO check code paths for oid->n_subid < 3 if (oid->prefix != 2 && oid->ids[0] != SNMP_MIB_2) return SNMP_CLASS_INVALID; - ASSUME(oid->n_subid > 1); switch (oid->ids[1]) { case SNMP_BGP4_MIB: @@ -649,8 +710,9 @@ snmp_get_next2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, if (c->size < sz) { - /* This is a bit tricky as we invalidate all in TX buffer pointers */ - snmp_manage_tbuf(p, c); + /* TODO create NULL varbind */ + c->error = AGENTX_RES_GEN_ERROR; + return; } vb = snmp_create_varbind(c->buffer, o_start); @@ -659,18 +721,17 @@ snmp_get_next2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, return; case SNMP_SEARCH_OK: - default: /* intentionaly left blank */ + default: break; } if (o_copy) { - /* Basicaly snmp_create_varbind(c->buffer, o_copy), - * but without any copying */ + /* basicaly snmp_create_varbind(c->buffer, o_copy), but without any copying */ vb = (void *) c->buffer; snmp_mib_fill2(p, o_copy, c); - /* Override the error value for GetNext-PDU when object is not found. */ + /* override the error for GetNext-PDU object not find */ switch (vb->type) { case AGENTX_NO_SUCH_OBJECT: @@ -702,45 +763,63 @@ 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) { if (state->index <= state->getbulk.non_repeaters) - return snmp_get_next2(p, o_start, o_end, c); - else { - struct oid *o_curr = NULL; - struct oid *o_predecessor = NULL; - enum snmp_search_res r; + return snmp_get_next2(p, o_start, o_end, c); + /* + * Here we don't need to do any overriding, not even in case no object was + * found, as the GetNext-PDU override is same as GetBulk-PDU override + * (to AGENTX_RES_END_OF_MIB_VIEW) + */ + } - uint i = 0; - do - { - o_predecessor = o_curr; - o_curr = search_mib(p, o_start, o_end, o_curr, c, &r); - i++; - } while (o_curr && i <= state->repetition); + struct oid *o_curr = NULL; + struct oid *o_predecessor = NULL; + enum snmp_search_res r; - if (!o_curr && i == 1) - { - o_predecessor = o_start; - goto abnormal; - } + uint i = 0; + do + { + o_predecessor = o_curr; + o_curr = search_mib(p, o_start, o_end, o_curr, c, &r); + i++; + } while (o_curr && i <= state->repetition); + + /* Object Identifier fall-backs */ + if (!o_curr) + o_curr = o_predecessor; - if (!o_curr) - goto abnormal; + if (!o_curr) + o_curr = o_start; - return snmp_mib_fill2(p, o_curr, c); + uint sz = snmp_varbind_hdr_size_from_oid(o_curr); -abnormal:; - uint sz = snmp_varbind_hdr_size_from_oid(o_predecessor); + if (c->size < sz) + { + c->error = AGENTX_RES_GEN_ERROR; + return; + } - if (c->size < sz) - { - snmp_log("snmp_get_bulk2() insufficient amount of memory in TX buffer, returning GET_ERROR"); - c->error = AGENTX_RES_GEN_ERROR; - return; - } + /* we need the varbind handle to be able to override it's type */ + struct agentx_varbind *vb = (void *) c->buffer; + vb->type = AGENTX_END_OF_MIB_VIEW; - struct agentx_varbind *vb = snmp_create_varbind(c->buffer, o_predecessor); - vb->type = AGENTX_END_OF_MIB_VIEW; - ADVANCE(c->buffer, c->size, snmp_varbind_size(vb, c->byte_ord)); + if (r == SNMP_SEARCH_OK) + /* the varbind will be recreated inside the snmp_mib_fill2() */ + snmp_mib_fill2(p, o_curr, c); + else + ADVANCE(c->buffer, c->size, snmp_varbind_header_size(vb)); + + /* override the error for GetBulk-PDU object not found */ + switch (vb->type) + { + case AGENTX_NO_SUCH_OBJECT: + case AGENTX_NO_SUCH_INSTANCE: + case AGENTX_END_OF_MIB_VIEW: + vb->type = AGENTX_END_OF_MIB_VIEW; + break; + + default: /* intentionally left blank */ + break; } } @@ -765,6 +844,7 @@ parse_close_pdu(struct snmp_proto UNUSED *p, byte UNUSED *req, uint UNUSED size) p->state = SNMP_ERR; + proto_notify(PS_DOWN, &p->p); */ return 0; } @@ -772,12 +852,43 @@ parse_close_pdu(struct snmp_proto UNUSED *p, byte UNUSED *req, uint UNUSED size) static inline uint update_packet_size(struct snmp_proto *p, byte *start, byte *end) { - /* Work even for partial packets */ + /* work even for partial messages */ struct agentx_header *h = (void *) p->sock->tpos; size_t s = snmp_pkt_len(start, end); STORE_U32(h->payload, s); return AGENTX_HEADER_SIZE + s; + +#if 0 + if (EMPTY_LIST(p->additional_buffers)) + { + return AGENTX_HEADER_SIZE + STORE_U32(h->payload, snmp_pkt_len(start, end)); + } + + uint size = p->to_send; /* to_send contain also the AGENTX_HEADER_SIZE */ + struct additional_buffer *b = TAIL(p->additional_buffers); + snmp_log("update_packet_size additional buf 0x%p pos 0x%p new pos 0x%p", b->buf, b->pos, end); + b->pos = end; + + snmp_log("update_packet_size to_send %u", p->to_send); + + /* TODO add packet size limiting + * we couldn't overflow the size because we limit the maximum packet size + */ + WALK_LIST(b, p->additional_buffers) + { + size += b->pos - b->buf; + snmp_log("update_packet_size add %u => %u", b->pos - b->buf, size); + } + + STORE_U32(h->payload, size - AGENTX_HEADER_SIZE); + + return size; +// if (p->additional_bufferson +// STORE_U32(h->payload, p->to_send + (end - start)); +// else {} +//// STORE_U32(h->payload, snmp_pkt_len(start, end)); +#endif } static inline void @@ -811,8 +922,8 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s .context = 0, }; - uint clen; /* Count of characters in context (without last '\0') */ - char *context; /* Newly allocated string of character */ + uint clen; /* count of characters in context (without last '\0') */ + char *context; /* newly allocated string of character */ /* alters pkt; assign context, clen */ SNMP_LOAD_CONTEXT(p, h, pkt, context, clen); @@ -833,7 +944,7 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s */ if (pkt_size < clen) { - /* For malformed packets consume full pkt_size */ + /* for malformed packets consume full pkt_size [or size] */ c.error = AGENTX_RES_PARSE_ERROR; goto send; } @@ -846,11 +957,33 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s c.context = ... */ - struct agentx_bulk_state bulk_state = { 0 }; - - if (c.size < sizeof(struct agentx_response)) + struct agentx_bulk_state bulk_state = { }; + if (h->type == AGENTX_GET_BULK_PDU) + { + if (size < sizeof(struct agentx_getbulk)) + goto wait; + + if (pkt_size < sizeof(struct agentx_getbulk)) + { + c.error = AGENTX_RES_PARSE_ERROR; + goto send; + } + + struct agentx_getbulk *bulk_info = (void *) pkt; + ADVANCE(pkt, pkt_size, sizeof(struct agentx_getbulk)); + + bulk_state = (struct agentx_bulk_state) { + .getbulk = { + .non_repeaters = LOAD_U32(bulk_info->non_repeaters, c.byte_ord), + .max_repetitions = LOAD_U32(bulk_info->max_repetitions, c.byte_ord), + }, + .index = 1, + .repetition = 1, + }; + } + + if (!p->partial_response && c.size < sizeof(struct agentx_response)) { - die("gets2: too small tx buffer"); snmp_manage_tbuf(p, &c); } @@ -859,7 +992,13 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s uint ind = 1; while (c.error == AGENTX_RES_NO_ERROR && size > 0 && pkt_size > 0) { - snmp_log("iter %u ``size'' %u", ind, c.buffer - ((byte *) response_header)); + snmp_log("iter %u size %u remaining %u/%u", ind, c.buffer - sk->tpos, size, pkt_size); +#if 0 + if (EMPTY_LIST(p->additional_buffers)) + snmp_log("iter %u size %u remaining %u/%u", ind, c.buffer - sk->tpos, size, pkt_size); + else + snmp_log("iter+ %u size %u remaining %u/%u", ind, c.buffer - ((struct additional_buffer *) TAIL(p->additional_buffers))->buf, size, pkt_size); +#endif if (size < snmp_oid_sizeof(0)) goto partial; @@ -869,21 +1008,20 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s uint sz; if ((sz = snmp_oid_size(o_start_b)) > pkt_size) { - /* For malformed packets consume full pkt_size */ + /* for malformed packets consume full pkt_size [or size] */ c.error = AGENTX_RES_PARSE_ERROR; /* Packet error, inconsistent values */ goto send; } /* - * If we already have written same relevant data to the tx-buffer then + * If we already have written same relevant data to the TX buffer, then * we send processed part, otherwise we don't have anything to send and * need to wait for more data to be recieved. */ if (sz > size && ind > 1) { snmp_log("sz %u > %u size && ind %u > 1", sz, size, ind); - /* Wait until the rest of the packet arrives, mark the proccess bytes */ - goto partial; + goto partial; /* send already processed part */ } else if (sz > size) { @@ -896,9 +1034,9 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s size -= sz; /* - * We load search range end OID. + * We load search range end OID * The exactly same process of sanity checking is preformed while loading - * the SearchRange's end OID. + * the SearchRange's end OID */ const struct oid *o_end_b = (void *) pkt; if ((sz = snmp_oid_size(o_end_b)) > pkt_size) @@ -935,6 +1073,7 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s goto send; } + /* TODO find mib_class, check if type is GET of GET_NEXT, act acordingly */ switch (h->type) { case AGENTX_GET_PDU: @@ -963,41 +1102,50 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s send: snmp_log("gets2: sending response ..."); - response_err_ind(response_header, c.error, ind); - - /* Number of bytes put into the TX buffer */ + struct agentx_response *res = (void *) sk->tbuf; + /* update the error, index pair on the beginning of the packet */ + response_err_ind(res, c.error, ind); uint s = update_packet_size(p, (byte *) response_header, c.buffer); - snmp_log("sending response to Get-PDU, GetNext-PDU or GetBulk-PDU request ..."); + + snmp_log("sending response to Get-PDU, GetNext-PDU or GetBulk-PDU request (size %u)...", s); + /* send the message in TX buffer */ int ret = sk_send(sk, s); + if (ret > 0) + snmp_log("sk_send OK!"); + else if (ret == 0) + snmp_log("sk_send sleep"); + else + snmp_log("sk_send error"); + // TODO think through the error state + + p->partial_response = NULL; + /* + int ret = sk_send(sk, c.buffer - sk->tpos); if (ret == 0) snmp_log("sk_send sleep (gets2"); else if (ret < 0) snmp_log("sk_send err %d (gets2)", ret); else snmp_log("sk_send was successful (gets2) !"); - - p->partial_response = NULL; + */ mb_free(context); mb_free(o_start); mb_free(o_end); - /* Number of bytes consumed from RX buffer */ + /* number of bytes parsed form rx-buffer */ return pkt - pkt_start; partial: snmp_log("partial packet"); /* The context octet is not added into response pdu */ - /* We need to tweak RX buffer packet size. */ + /* need to tweak RX buffer packet size */ snmp_log("old rx-buffer size %u", h->payload); (c.byte_ord) ? put_u32(&h->payload, pkt_size) : (h->payload = pkt_size); snmp_log("new rx-buffer size %u", h->payload); - *skip = AGENTX_HEADER_SIZE; p->partial_response = response_header; - - /* Number of bytes consumed from RX buffer */ return pkt - pkt_start; wait: @@ -1013,17 +1161,19 @@ snmp_start_subagent(struct snmp_proto *p) snmp_log("snmp_start_subagent() starting subagent"); snmp_log("DEBUG p->local_as %u", p->local_as); - /* Blank oid means unsupported */ - // TODO optional subagent identification + /* blank oid means unsupported */ struct oid *blank = snmp_oid_blank(p); open_pdu(p, blank); + + p->state = SNMP_OPEN; + mb_free(blank); } void snmp_stop_subagent(struct snmp_proto *p) { - snmp_log("snmp_stop_subagent() state %s", p->state); + snmp_log("snmp_stop_subagent() state %d", p->state); if (p->state == SNMP_STOP) close_pdu(p, AGENTX_CLOSE_SHUTDOWN); @@ -1043,6 +1193,7 @@ int snmp_rx(sock *sk, uint size) { snmp_log("snmp_rx() size %u", size); + //snmp_dump_packet(sk->tbuf, 64); struct snmp_proto *p = sk->data; byte *pkt_start = sk->rbuf; byte *end = pkt_start + size; @@ -1055,12 +1206,13 @@ snmp_rx(sock *sk, uint size) uint skip = 0; snmp_log("snmp_rx before loop"); - while (end >= pkt_start + AGENTX_HEADER_SIZE) + while (end >= pkt_start + AGENTX_HEADER_SIZE && skip == 0) { uint parsed_len = parse_pkt(p, pkt_start, size, &skip); snmp_log("snmp_rx loop end %p parsed >>> %u <<< curr %p", end, parsed_len, pkt_start + parsed_len); + snmp_log("snmp_rx loop2 rpos 0x%p", sk->rpos); if (parsed_len == 0) break; @@ -1092,8 +1244,67 @@ snmp_rx(sock *sk, uint size) void snmp_ping(struct snmp_proto *p) { - /* this code does not support non-default context */ + { +#define SNMP_OID_SIZE_FROM_LEN(x) (sizeof(struct oid) + (x) * sizeof(u32)) + /* trap OID bgpEstablishedNotification (.1.3.6.1.2.1.0.1) */ + struct oid *head = mb_alloc(p->p.pool, SNMP_OID_SIZE_FROM_LEN(3)); + head->n_subid = 3; + head->prefix = 2; + head->include = head->pad = 0; + + u32 trap_ids[] = { 1, 0, 1 }; + for (uint i = 0; i < head->n_subid; i++) + head->ids[i] = trap_ids[i]; + + /* paylaod oids */ + uint sz = 3 * SNMP_OID_SIZE_FROM_LEN(9) + 3 * 4 + 2 * 8 + 4 - 20; + void *data = mb_alloc(p->p.pool, sz); + struct agentx_varbind *addr_vb = data; + /* +4 for varbind header, +8 for octet string */ + struct agentx_varbind *error_vb = data + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8; + struct agentx_varbind *state_vb = (void *) error_vb + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8; +#undef SNMP_OID_SIZE_FROM_LEN + + addr_vb->pad = error_vb->pad = state_vb->pad = 0; + + struct oid *addr = &addr_vb->name; + struct oid *error = &error_vb->name; + struct oid *state = &state_vb->name; + + addr->n_subid = error->n_subid = state->n_subid = 9; + addr->prefix = error->prefix = state->prefix = 2; + addr->include = error->include = state->include = 0; + addr->pad = error->pad = state->pad = 0; + + u32 oid_ids[] = { + SNMP_MIB_2, SNMP_BGP4_MIB, SNMP_BGP_PEER_TABLE, SNMP_BGP_PEER_ENTRY, 0, + 10, 1, 2, 1 + }; + for (uint i = 0; i < addr->n_subid; i++) + addr->ids[i] = error->ids[i] = state->ids[i] = oid_ids[i]; + + addr->ids[4] = SNMP_BGP_REMOTE_ADDR; + error->ids[4] = SNMP_BGP_LAST_ERROR; + state->ids[4] = SNMP_BGP_STATE; + + ip4_addr ip4 = ip4_build(10,1,2,1); + snmp_varbind_ip4(addr_vb, 100, ip4); + + char error_str[] = { 0, 0 }; + snmp_varbind_nstr(error_vb, 100, error_str, 2); + + snmp_varbind_int(state_vb, 100, 6); + + u32 now = current_time() TO_S; + if (now % 4 == 0) + notify_pdu(p, head, data, sz, 1); + else if (now % 2 == 0) + notify_pdu(p, head, data, sz, 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 = { .buffer = sk->tpos, .size = sk->tbuf + sk->tbsize - sk->tpos, @@ -1109,9 +1320,10 @@ snmp_ping(struct snmp_proto *p) p->packet_id++; SNMP_SESSION(h, p); - /* We send only the header */ - snmp_log("sending ping packet ..."); - uint s = update_packet_size(p, sk->tpos, c.buffer); + snmp_log("sending ping packet ... tpos 0x%p", sk->tpos); + 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!"); @@ -1127,6 +1339,7 @@ snmp_agent_reconfigure(void) { } + */ static inline int @@ -1221,19 +1434,11 @@ search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_ } if (o_end == blank) - mb_free((void *) o_end); + mb_free((void *) blank); + return o_curr; } -/* -static byte * -find_ospf_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size) -{ - // TO DO X XX - return NULL; -} -*/ - /** * snmp_prefixize - return prefixed oid copy if possible * @proto: allocation pool holder @@ -1253,12 +1458,12 @@ snmp_prefixize(struct snmp_proto *proto, const struct oid *oid, int byte_ord) if (snmp_is_oid_empty(oid)) { - /* Allocate new zeroed oid */ + /* allocate new zeroed oid */ snmp_log("blank"); return snmp_oid_blank(proto); } - /* The oid is already in prefixed form */ + /* already in prefixed form */ else if (oid->prefix != 0) { struct oid *new = snmp_oid_duplicate(proto->p.pool, oid); snmp_log("already prefixed"); @@ -1266,13 +1471,13 @@ snmp_prefixize(struct snmp_proto *proto, const struct oid *oid, int byte_ord) } if (oid->n_subid < 5) - return NULL; + { snmp_log("too small"); return NULL; } for (int i = 0; i < 4; i++) if (LOAD_U32(oid->ids[i], byte_ord) != prefix[i]) { snmp_log("different prefix"); return NULL; } - /* Interval validity check */ + /* validity check here */ if (oid->ids[4] >= 256) { snmp_log("outside byte first id"); return NULL; } @@ -1282,7 +1487,8 @@ snmp_prefixize(struct snmp_proto *proto, const struct oid *oid, int byte_ord) memcpy(new, oid, sizeof(struct oid)); new->n_subid = oid->n_subid - 5; - /* We validated the fifth identifier, we can safely use it as prefix */ + /* validity check before allocation => ids[4] < 256 + and can be copied to one byte new->prefix */ new->prefix = oid->ids[4]; memcpy(&new->ids, &oid->ids[5], new->n_subid * sizeof(u32)); @@ -1295,10 +1501,18 @@ snmp_mib_fill2(struct snmp_proto *p, struct oid *oid, { ASSUME(oid != NULL); + snmp_log("critical part"); if (c->size < snmp_varbind_hdr_size_from_oid(oid)) { snmp_manage_tbuf(p, c); } + else + { + u32 *ptr = mb_alloc(p->p.pool, sizeof(u32) * 4); + *ptr = 0xbeef; + mb_free(ptr); + } + snmp_log("critical part done"); struct agentx_varbind *vb = snmp_create_varbind(c->buffer, oid); @@ -1330,21 +1544,88 @@ snmp_mib_fill2(struct snmp_proto *p, struct oid *oid, * are invalidated! */ void -snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu_context *c) +snmp_manage_tbuf(struct snmp_proto UNUSED *p, struct snmp_pdu_context *c) { snmp_log("snmp_manage_tbuf()"); sock *sk = p->sock; - - sk_set_tbsize(sk , sk->tbsize + 2048); + + sk_set_tbsize(sk, sk->tbsize + 2048); c->size += 2048; + //sk_set_tbsize(sk, sk->tbsize + SNMP_TX_BUFFER_SIZE); + //c->size += SNMP_TX_BUFFER_SIZE; + + return; + +#if 0 + if (!EMPTY_LIST(p->additional_buffers)) + { + struct additional_buffer *t = TAIL(p->additional_buffers); + t->pos = c->buffer; + } + else + p->to_send = c->buffer - p->sock->tpos; + + struct additional_buffer *b = mb_allocz(p->p.pool, sizeof(struct additional_buffer)); + b->buf = b->pos = mb_alloc(p->p.pool, SNMP_TX_BUFFER_SIZE); + add_tail(&p->additional_buffers, &b->n); + + c->buffer = b->buf; + c->size = SNMP_TX_BUFFER_SIZE; +#endif } +#if 0 +static int +send_remaining_buffers(sock *sk) +{ + struct snmp_proto *p = sk->data; + + while (!EMPTY_LIST(p->additional_buffers)) + { + struct additional_buffer *b = HEAD(p->additional_buffers); + p->to_send = b->pos - b->buf; + snmp_log("send_remaining_buffers sending next %u bytes", p->to_send); + + ASSUME(sk->tbuf == sk->tpos); + memcpy(sk->tbuf, b->buf, p->to_send); + sk->tpos = sk->tbuf + p->to_send; + + rem_node(&b->n); + snmp_log("state of additional b at 0x%p .buf = 0x%p .pos = 0x%p", b, b->buf, b->pos); + mb_free(b->buf); + snmp_log("b->buf fried, cause is b"); + mb_free(b); + + snmp_log("packet byte stream part next"); + snmp_dump_packet(sk->tpos, p->to_send); + + int ret; + if ((ret = sk_send(sk, p->to_send)) <= 0) + { + snmp_log("sending_remaining - error or sleep;returning"); + return ret; + } + } + + snmp_log("sending_remaining all done returning 1"); + return 1; +} +#endif + void snmp_tx(sock UNUSED *sk) { - snmp_log("snmp_tx() hook"); + snmp_log("snmp_tx"); + //struct snmp_proto *p = sk->data; return; + +#if 0 + if (!p->partial_response) + return; + + send_remaining_buffers(sk); +#endif } @@ -1353,22 +1634,24 @@ prepare_response(struct snmp_proto *p, struct snmp_pdu_context *c) { snmp_log("prepare_response()"); - if (p->partial_response) - return p->partial_response; + if (!p->partial_response) + { + struct agentx_response *r = (void *) c->buffer; + struct agentx_header *h = &r->h; - struct agentx_response *r = (void *) c->buffer; - struct agentx_header *h = &r->h; + SNMP_BLANK_HEADER(h, AGENTX_RESPONSE_PDU); + SNMP_SESSION(h, p); - SNMP_BLANK_HEADER(h, AGENTX_RESPONSE_PDU); - SNMP_SESSION(h, p); + /* protocol doesn't care about subagent upTime */ + STORE_U32(r->uptime, 0); + STORE_U16(r->error, AGENTX_RES_NO_ERROR); + STORE_U16(r->index, 0); - /* AgentX protocol does not care about subagent upTime */ - STORE_U32(r->uptime, 0); - STORE_U16(r->error, AGENTX_RES_NO_ERROR); - STORE_U16(r->index, 0); + ADVANCE(c->buffer, c->size, sizeof(struct agentx_response)); + return r; + } - ADVANCE(c->buffer, c->size, sizeof(struct agentx_response)); - return r; + return p->partial_response; }