diff --git a/proto/snmp/Makefile b/proto/snmp/Makefile index ca589059..b80cb135 100644 --- a/proto/snmp/Makefile +++ b/proto/snmp/Makefile @@ -1,6 +1,5 @@ src := snmp.c subagent.c obj := $(src-o-files) -LIBS += `net-snmp-config --agent-libs` $(all-daemon) $(cf-local) $(call proto-build,snmp_build) diff --git a/proto/snmp/bgp_mib.h b/proto/snmp/bgp_mib.h index 99229521..dd34fa18 100644 --- a/proto/snmp/bgp_mib.h +++ b/proto/snmp/bgp_mib.h @@ -2,30 +2,32 @@ #define _BIRD_SNMP_BGP_MIB_H_ /* peers attributes */ -#define SNMP_BGP_IDENTIFIER 1 -#define SNMP_BGP_STATE 2 -#define SNMP_BGP_ADMIN_STATUS 3 /* in read-only mode */ -#define SNMP_BGP_VERSION 4 -#define SNMP_BGP_LOCAL_ADDR 5 -#define SNMP_BGP_LOCAL_PORT 6 -#define SNMP_BGP_REMOTE_ADDR 7 -#define SNMP_BGP_REMOTE_PORT 8 -#define SNMP_BGP_REMOTE_AS 9 -#define SNMP_BGP_RX_UPDATES 10 /* in updates */ -#define SNMP_BGP_TX_UPDATES 11 /* out updates */ -#define SNMP_BGP_RX_MESSAGES 12 /* in total messages */ -#define SNMP_BGP_TX_MESSAGES 13 /* out total messages */ -#define SNMP_BGP_LAST_ERROR 14 /* UNSUPPORTED */ -#define SNMP_BGP_FSM_TRANSITIONS 15 /* FSM established transitions */ -#define SNMP_BGP_FSM_ESTABLISHED_TIME 16 /* UNSUPPORTED FSM established time */ -#define SNMP_BGP_RETRY_INTERVAL 17 -#define SNMP_BGP_HOLD_TIME 18 -#define SNMP_BGP_KEEPALIVE 19 -#define SNMP_BGP_HOLD_TIME_CONFIGURED 20 -#define SNMP_BGP_KEEPALIVE_CONFIGURED 21 -#define SNMP_BGP_ORIGINATION_INTERVAL 22 /* UNSUPPORTED */ -#define SNMP_BGP_MIN_ROUTE_ADVERTISEMENT 23 /* UNSUPPORTED */ -#define SNMP_BGP_MIN_UPDATE_ELAPSED_TIME 24 /* UNSUPPORTED */ +enum BGP4_MIB { + SNMP_BGP_IDENTIFIER = 1; + SNMP_BGP_STATE = 2; + SNMP_BGP_ADMIN_STATUS = 3; /* in read-only mode */ + SNMP_BGP_VERSION = 4; + SNMP_BGP_LOCAL_ADDR = 5; + SNMP_BGP_LOCAL_PORT = 6; + SNMP_BGP_REMOTE_ADDR = 7; + SNMP_BGP_REMOTE_PORT = 8; + SNMP_BGP_REMOTE_AS = 9; + SNMP_BGP_RX_UPDATES = 10; /* in updates */ + SNMP_BGP_TX_UPDATES = 11; /* out updates */ + SNMP_BGP_RX_MESSAGES = 12; /* in total messages */ + SNMP_BGP_TX_MESSAGES = 13; /* out total messages */ + SNMP_BGP_LAST_ERROR = 14; + SNMP_BGP_FSM_TRANSITIONS = 15; /* FSM established transitions */ + SNMP_BGP_FSM_ESTABLISHED_TIME = 16; /* UNSUPPORTED FSM established time */ + SNMP_BGP_RETRY_INTERVAL = 17; + SNMP_BGP_HOLD_TIME = 18; + SNMP_BGP_KEEPALIVE = 19; + SNMP_BGP_HOLD_TIME_CONFIGURED = 20; + SNMP_BGP_KEEPALIVE_CONFIGURED = 21; + SNMP_BGP_ORIGINATION_INTERVAL = 22; /* UNSUPPORTED 0 */ + SNMP_BGP_MIN_ROUTE_ADVERTISEMENT = 23; /* UNSUPPORTED 0*/ + SNMP_BGP_MIN_UPDATE_ELAPSED_TIME = 24; /* UNSUPPORTED */ +} PACKED; void snmp_init_bgp_table(void); void snmp_del_bgp_table(void); diff --git a/proto/snmp/config.Y b/proto/snmp/config.Y index 7593ef5f..d85dbf15 100644 --- a/proto/snmp/config.Y +++ b/proto/snmp/config.Y @@ -61,7 +61,8 @@ snmp_bgp_bond: BGP symbol struct proto_config *pc; WALK_LIST(pc, this_proto->global->protos) - if (!strcmp(pc->name, $2->name) && pc->protocol == &proto_bgp) + if (!strcmp(pc->name, $2->name) && pc->protocol == &proto_bgp + && !ipa_zero(((struct bgp_proto *) pc)->remote_ip)) this_bond->proto = pc; if (!this_bond->proto) cf_error("BGP protocol %s not found", $2->name); diff --git a/proto/snmp/snmp.c b/proto/snmp/snmp.c index 3f76a4c4..c00dd94f 100644 --- a/proto/snmp/snmp.c +++ b/proto/snmp/snmp.c @@ -35,6 +35,7 @@ snmp_init(struct proto_config *CF) p->remote_ip = cf->remote_ip; p->local_port = cf->local_port; p->remote_port = cf->remote_port; + p->state = SNMP_INIT; // p->timeout = cf->timeout; p->timeout = 15; @@ -59,7 +60,7 @@ snmp_start_locked(struct object_lock *lock) s->rbsize = SNMP_RX_BUFFER_SIZE; s->tbsize = SNMP_TX_BUFFER_SIZE; - // s->tos = IP_PREC_INTERNET_CONTROL + //s->tos = IP_PREC_INTERNET_CONTROL //s->rx_hook = snmp_connected; s->tx_hook = snmp_connected; s->err_hook = snmp_sock_err; @@ -76,7 +77,7 @@ snmp_start_locked(struct object_lock *lock) static void snmp_tx(sock *sk UNUSED) { - log(L_INFO "snmp_tx() recieved something, yay!"); + log(L_INFO "snmp_tx() something, yay!"); } @@ -96,7 +97,8 @@ snmp_connected(sock *sk) static void snmp_sock_err(sock *sk UNUSED, int err UNUSED) { - log(L_INFO "snmp_sock_err() "); + log(L_INFO "snmp_sock_err() %s - err no: %d", strerror(err), err); + die("socket error"); } static int @@ -104,9 +106,10 @@ snmp_start(struct proto *P) { log(L_INFO "snmp_start() - starting timer (almost)"); struct snmp_proto *p = (void *) P; + struct snmp_config *cf = P->cf; p->ping_timer = tm_new_init(p->p.pool, snmp_ping_timer, p, 0, 0); - tm_set(p->ping_timer, current_time() + (7 S_)); + tm_set(p->ping_timer, current_time() + (2 S_)); /* starting agentX communicaiton channel */ log(L_INFO "preparing lock"); @@ -122,7 +125,30 @@ snmp_start(struct proto *P) log(L_INFO "local ip: %I:%u, remote ip: %I:%u", p->local_ip, p->local_port, p->remote_ip, p->remote_port); - + + init_list(p->bgp_entries); + + /* create copy of bonds to bgp */ + HASH_INIT(p->peer_hash, p->p.pool, 10); + + struct snmp_bond *b; + WALK_LIST(b, cf->bgp_entries) + { + struct bgp_config *bc = b->proto; + if (bc && !ipa_zero(bc->remote_ip)) + { + struct snmp_bgp_peer_entry pe = { + .bond = b; + .peer_ip = bc->remote_ip; + .next = NULL; + }; + + HASH_INSERT(p->peer_hash, SNMP_HASH, pe) + + add_tail(&p->bgp_entries, b); + } + } + return PS_START; } @@ -138,13 +164,13 @@ snmp_reconfigure(struct proto *P, struct proto_config *CF) p->remote_port = cf->remote_port; p->timeout = 15; + /* TODO walk all bind protocols and find their (new) IP + to update HASH table */ log(L_INFO "snmp_reconfigure() lip: %I:%u rip: %I:%u", p->local_ip, p->local_port, p->remote_ip, p->remote_port); - return 0; + return PS_START; } - -static void -snmp_show_proto_info(struct proto *P) +static void snmp_show_proto_info(struct proto *P) { //struct snmp_proto *sp = (void *) P; struct snmp_config *c = (void *) P->cf; @@ -217,16 +243,17 @@ snmp_ping_timer(struct timer *tm) log(L_INFO "snmp_ping_timer() "); struct snmp_proto *p = tm->data; - // ping here - ping_pdu(p); + snmp_ping(p); + + //tm_set(tm, current_time() + (7 S_)); } -/* snmp_shutdown already occupied by net-snmp */ static int snmp_shutdown(struct proto *P) { struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P); snmp_stop_subagent(p); + return PS_DOWN; } struct protocol proto_snmp = { @@ -242,7 +269,6 @@ struct protocol proto_snmp = { .show_proto_info = snmp_show_proto_info, }; -/* strange name because of conflict with net-snmp lib snmp_lib() */ void snmp_build(void) { diff --git a/proto/snmp/snmp.h b/proto/snmp/snmp.h index 90236c5c..bb38002c 100644 --- a/proto/snmp/snmp.h +++ b/proto/snmp/snmp.h @@ -28,6 +28,20 @@ #define SNMP_RX_BUFFER_SIZE 2048 #define SNMP_TX_BUFFER_SIZE 2048 +#define SNMP_INIT 1 +#define SNMP_REGISTR 2 +#define SNMP_CONN 3 +#define SNMP_ERR 4 + +#define SNMP_OFF 0 + + +/* hash table macros */ +#define SNMP_HASH_KEY(n) n->peer_ip; +#define SNMP_HASH_NEXT(n) n->next; +#define SNMP_HASH_EQ(ip1, ip2) ipa_equal(ip1, ip2) +#define SNMP_HASH_FN(ip) ipa_hash(ip) + struct snmp_bond { node n; struct proto_config *proto; @@ -45,24 +59,40 @@ struct snmp_config { list bgp_entries; }; +struct snmp_bgp_peer_entry { + struct snmp_bond *bond; + ip_addr peer_ip; + struct snmp_bgp_peer_entry *next; +} + struct snmp_proto { struct proto p; struct object_lock *lock; + ip_addr local_ip; ip_addr remote_ip; u16 local_port; u16 remote_port; + sock *sock; u8 timeout; + u32 session_id; u32 transaction_id; u32 packet_id; + //struct iface *iface; // map goes here + HASH(struct snmp_bgp_peer_entry) bgp_hash; struct tbf rl_gen; + timer *ping_timer; + u8 state; + + list bgp_entries; }; +/* struct snmp_channel_config { struct channel_config c; struct bgp_config *bgp; @@ -72,7 +102,7 @@ struct snmp_channel_config { struct snmp_channel { struct channel c; }; - +*/ #endif diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index f7aa4c39..02638848 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -11,9 +11,25 @@ #include "lib/unaligned.h" #include "subagent.h" +/* ============================================================= + * Problems + * ------------------------------------------------------------ + * + * change of remote ip -> no notification, no update + * same ip, different ports + * distinct VRF (two interfaces with overlapping private addrs) + * + */ + static int parse_response(struct snmp_proto *p, byte *buf, uint size); static void header_update_len(byte *buf, u32 len); -static uint oid_size(struct oid* o); +static inline uint oid_size(struct oid *o); +static inline uint vb_size(struct agentx_varbind *vb); +static int snmp_stop_ack(sock *sk, uint size); +static void do_response(struct snmp_proto *p, byte *buf, uint size); +static int parse_get_pdu(struct snmp_proto *p, byte *buf, uint size); +static void response_fail(struct snmp_proto *p, u16 err_no, u16 index); +static byte *prepare_response(struct snmp_proto *p, byte *buf, uint size, u16 err_no, u16 index); static const char * const snmp_errs[] = { #define SNMP_ERR_SHIFT 256 @@ -32,112 +48,129 @@ static const char * const snmp_errs[] = { [AGENTX_RES_PROCESSING_ERR - SNMP_ERR_SHIFT] = "Processing error", }; -static int -put_str(byte *buf, const char *str, uint *size) +/* payload length in bytes */ +static inline size_t +pkt_len(byte *buf, byte *pkt) +{ + return (pkt - buf) - AGENTX_HEADER_SIZE; +} + +static inline size_t +str_size(const char *str) +{ + return 4 + BIRD_ALIGN(strlen(str), 4); +} + +static byte * +put_str(byte *buf, const char *str) { uint len = strlen(str); - uint pkt_len = BIRD_ALIGN(len, 4); + uint slen = BIRD_ALIGN(len, 4); if (len > MAX_STR) - return -1; + return NULL; + + STORE_PTR(buf, len); - put_u32(buf, len); - memcpy(buf + 4, str, len); - // make the value 32-bit aligned - for (uint i = 0; i < pkt_len - len; i++) + for (uint i = 0; i < slen - len; i++) buf[len + i] = 0x00; // PADDING - *size += (4 + pkt_len); - - return 0; + return buf + str_size(str); } -static void -put_blank(byte *buf, uint *size) +static byte * +put_blank(byte *buf) { - buf[0] = buf[1] = buf[2] = buf[3] = 0; - *size += 4; + STORE_PTR(buf, 0); + return buf + 4; } -static void -put_oid(byte *buf, struct oid *oid, uint *size) +static byte * +put_oid(byte *buf, struct oid *oid) { + log(L_INFO "testing oid"); + for (uint i = 0; i < oid->n_subid; i++) + log(L_INFO "oid id %d: %u", i, oid->ids[i]); + log(L_INFO "put_oid()"); put_u8(buf, oid->n_subid); - put_u8(buf + 1, oid->prefix); - put_u8(buf + 2, oid->include); - put_u8(buf + 3, 0); // PADDING + log(L_INFO "data %p: %02X", buf, *buf); + put_u8(++buf, oid->prefix); + log(L_INFO "data %p: %02X", buf, *buf); + put_u8(++buf, oid->include); + log(L_INFO "data %p: %02X", buf, *buf); + put_u8(++buf, 0); // PADDING + /* last increment */ + ++buf; + log(L_INFO "oid head end %p", buf); - put_u32s(buf + 4, oid->subid.ids, oid->subid.len); + /* copy OID data */ +#ifdef SNMP_NATIVE + for (uint i = 0; i < oid->n_subid; i++) + *(((u32 *) buf) + i) = oid->ids[i]; +#else + put_u32s(buf, oid->ids, oid->n_subid << 2); +#endif +/* + for (uint i = 0; i <= (oid->n_subid << 2) +4 ; i += 4) + log(L_INFO "OID % 3u: %02X %02X %02X %02X", i, + *(buf - 4 + i), + *(buf - 4 + i + 1), + *(buf - 4 + i + 2), + *(buf - 4 + i + 3) + ); +*/ - *size += (4 + oid->subid.len); + return buf + (oid->n_subid << 2); } + /* paste data at first byte in message * with 3B of padding */ -static void -paste_fbyte(byte *buf, u8 data, uint *size) +static byte * +paste_fbyte(byte *buf, u8 data) { - buf[0] = data; - buf[1] = buf[2] = buf[3] = 0x00; // PADDING - *size += 4; -} - -static u32 -store_in_order(u32 val, int order) -{ - /* AGENTX_BIG_ENDIAN */ - if (order) - { - } - else - { - } - return 0; + log(L_INFO "paste_fbyte()"); + put_u8(buf, data); + put_u24(++buf, 0); // PADDING + return buf + 3; } static void open_pdu(struct snmp_proto *p, struct oid *oid) { sock *sk = p->sock; - byte *buf, *pkt, *end; + byte *buf, *pkt; buf = pkt = sk->tbuf; uint size = sk->tbsize; // should be configurable const char *str = "bird"; - uint pkt_size = 0; - uint slen = BIRD_ALIGN(strlen(str), 4); + //uint pkt_size = 0; - /* +8 - header of oid (4) and octet string length (4) */ - if (size > AGENTX_HEADER_SIZE + oid->subid.len + slen + 8) + if (size > AGENTX_HEADER_SIZE + oid_size(oid) + str_size(str)) { - log(L_INFO "open_pdu() sufficient size nw order: %u", -AGENTX_NETWORK_BYTE_ORDER); - PASTE_HEADER(pkt, AGENTX_OPEN_PDU, AGENTX_NETWORK_BYTE_ORDER, size); + log(L_INFO "open_pdu()"); - // use random num instead - put_u32(&h->session_id, 1); - put_u32(&h->transaction_id, 1); - put_u32(&h->packet_id, 1); + struct agentx_header *h; + SNMP_CREATE(pkt, struct agentx_header, h) + SNMP_B_HEADER(h, AGENTX_OPEN_PDU) - paste_fbyte(pkt, p->timeout, &pkt_size); - ADVANCE(pkt, size, 4); - - put_oid(pkt, oid, &pkt_size); - ADVANCE(pkt, size, oid_size(oid)); + STORE(h->session_id, 1); + STORE(h->transaction_id, 1); + STORE(h->packet_id, 1); - /* paste description */ - put_str(pkt, str, &pkt_size); - ADVANCE(pkt, size, slen); + pkt = paste_fbyte(pkt, p->timeout); + pkt = put_oid(pkt, oid); + pkt = put_str(pkt, str); + + SNMP_UPDATE(h, pkt_len(buf, pkt)); + + int ret = sk_send(sk, pkt - buf); - header_update_len(buf, pkt_size); - - log(L_INFO "sk_send()-ing %u", AGENTX_HEADER_SIZE + pkt_size); - int ret = sk_send(sk, AGENTX_HEADER_SIZE + pkt_size); if (ret == 0) log(L_INFO "sleep"); else if (ret < 0) @@ -148,7 +181,108 @@ AGENTX_NETWORK_BYTE_ORDER); else log(L_INFO "open_pdu() insufficient size, %u <= %u ", - size, AGENTX_HEADER_SIZE + oid->subid.len + slen + 8); + size, AGENTX_HEADER_SIZE + oid_size(oid) + str_size(str)); +} + +/* 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 + ) + { + log(L_INFO "de_allocate_pdu()"); + + struct agentx_header *h; + SNMP_CREATE(pkt, struct agentx_header, h); + SNMP_B_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, + } + + else + log(L_INFO "de_allocate_pdu(): insufficient size"); +} +*/ + +/* register / unregister pdu */ +static void +un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 type) +{ + sock *sk = p->sock; + byte *buf, *pkt; + buf = pkt = sk->tbuf; + uint size = sk->tbsize; + + /* conditional +4 for upper-bound */ + if (size > AGENTX_HEADER_SIZE + oid_size(oid) + ((len > 1) ? 4 : 0)) + { + log(L_INFO "un_register_pdu()"); + struct agentx_un_register_pdu *ur; + SNMP_CREATE(pkt, struct agentx_un_register_pdu, ur); + struct agentx_header *h = &ur->h; + + // FIXME correctly set INSTANCE REGISTRATION bit + SNMP_HEADER(h, type, AGENTX_FLAG_INSTANCE_REGISTRATION); + SNMP_SESSION(h, p); + + /* do not override timeout */ + STORE(ur->timeout, 0); + /* default priority */ + STORE(ur->priority, AGENTX_PRIORITY); + STORE(ur->range_subid, (len > 1) ? index : 0); + + pkt = put_oid(pkt, oid); + log(L_INFO "pkt - buf : %lu sizeof %u", pkt -buf, AGENTX_HEADER_SIZE); + + /* place upper-bound if needed */ + if (len > 1) + { + STORE_PTR(pkt, len); + pkt += 4; + } + + log("size of pkt: %u", pkt_len(buf,pkt)); + SNMP_UPDATE(h, pkt_len(buf, pkt)); + + for (uint i = 0; i < pkt - buf; i++) + log(L_INFO "%p: %02X", buf+i, *(buf + i)); + + log(L_INFO "sending (un)register %d", type); + int ret = sk_send(sk, pkt - buf); + + if (ret == 0) + log(L_INFO "sleep"); + else if (ret < 0) + log(L_INFO "err %d", ret); + else + log(L_INFO "ok !!"); + } + + else + log(L_INFO "un_register_pdu() insufficient size"); +} + +/* register pdu */ +static void +snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len) +{ + un_register_pdu(p, oid, index, len, AGENTX_REGISTER_PDU); +} + + +/* unregister pdu */ +static void +snmp_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len) +{ + un_register_pdu(p, oid, index, len, AGENTX_UNREGISTER_PDU); } static void @@ -164,34 +298,36 @@ close_pdu(struct snmp_proto *p, u8 reason) /* +4B for reason */ if (size > AGENTX_HEADER_SIZE + 4) { - PASTE_HEADER(buf, AGENTX_CLOSE_PDU, AGENTX_NETWORK_BYTE_ORDER, size); + struct agentx_header *h; + SNMP_CREATE(pkt, struct agentx_header, h) + SNMP_B_HEADER(h, AGENTX_CLOSE_PDU) - log(L_INFO "session_id %u", p->session_id); - h->session_id = p->session_id; - p->transaction_id++; - p->transaction_id = get_u32(&p->transaction_id); - put_u32(&h->transaction_id, p->transaction_id); - put_u32(&h->packet_id, 1); + SNMP_SESSION(h, p) - ADVANCE(pkt, size, sizeof(struct agentx_header)); - - paste_fbyte(pkt, reason, &size); - ADVANCE(pkt, size, 4); + pkt = paste_fbyte(pkt, reason); - /* 4 - reason size */ - header_update_len(sk->tbuf, 4); + SNMP_UPDATE(h, pkt_len(buf, pkt)); - int ret = sk_send(sk, sizeof(struct agentx_header) + 4); + log(L_INFO "preparing to sk_send()"); + int ret = sk_send(sk, pkt - buf); if (ret == 0) log(L_INFO "sleep"); else if (ret < 0) log(L_INFO "err"); else - log(L_INFO, "ok !! "); + log(L_INFO, "ok !!"); } } +static inline void +refresh_ids(struct snmp_proto *p, struct agentx_header *h) +{ + int byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER; + p->transaction_id = LOAD(h->transaction_id, byte_ord); + p->packet_id = LOAD(h->packet_id, byte_ord); +} + static int parse_pkt(struct snmp_proto *p, byte *buf, uint size) { @@ -199,15 +335,19 @@ parse_pkt(struct snmp_proto *p, byte *buf, uint size) return 0; struct agentx_header *h = (void *) buf; + log(L_INFO "parse_pkt got type %u", h->type); switch (h->type) { case AGENTX_RESPONSE_PDU: return parse_response(p, buf, size); - break; + + case AGENTX_GET_PDU: + refresh_ids(p, h); + return parse_get_pdu(p, buf, size); /* should not happen */ default: - die("unknown packet type"); + die("unknown packet type %u", h->type); } } @@ -220,24 +360,165 @@ parse_response(struct snmp_proto *p, byte *buf, uint size) struct agentx_response *r = (void *) buf; struct agentx_header *h = &r->h; - log(L_INFO "endianity: %s, session %u", (h->flags & AGENTX_NETWORK_BYTE_ORDER) ? "big end": -"little end", h->session_id); - p->session_id = h->session_id; - p->transaction_id = h->transaction_id; - p->packet_id = h->packet_id; + log(L_INFO "endianity: %s, session %u, transaction: %u", (h->flags & AGENTX_NETWORK_BYTE_ORDER) ? "big end": +"little end", h->session_id, h->transaction_id); + log(L_INFO "sid: %3u\ttid: %3u\tpid: %3u\t", p->session_id, p->transaction_id, +p->packet_id); - log(L_INFO "size %u", get_u32(&h->payload)); - log(L_INFO "uptime: %u s", get_u32(&r->uptime)); - switch (r->err) - { - case AGENTX_RES_NO_ERROR: - break; - default: - log(L_INFO "an error occured: '%s'", snmp_errs[get_u16(&r->err) - + log(L_INFO "size %u", h->payload); + log(L_INFO "uptime: %u s", r->uptime); + + if (r->err == AGENTX_RES_NO_ERROR) + do_response(p, buf, size); + else + log(L_INFO "an error occured '%s'", snmp_errs[get_u16(&r->err) - SNMP_ERR_SHIFT]); + + return 1; +} + +static void +do_response(struct snmp_proto *p, byte *buf, uint size) +{ + struct agentx_response *r = (void *) buf; + struct agentx_header *h = &r->h; + + /* TODO make it asynchronous for better speed */ + switch (p->state) + { + case SNMP_INIT: + if (h->flags & AGENTX_NETWORK_BYTE_ORDER) + { + p->session_id = get_u32(&h->session_id); + p->transaction_id = get_u32(&h->transaction_id); + p->packet_id = get_u32(&h->packet_id); + } + else + { + memcpy(&p->session_id, &h->session_id, 12); + } + + p->transaction_id++; + + log(L_INFO "sending register-pdu"); + u32 arr_with_prefix[] = {1, 15, 3, 1, 1}; + struct oid *o2 = mb_allocz(p->p.pool, 10 * 4); + put_u8(&o2->n_subid, 9); + put_u8(&o2->prefix, 2); + + memcpy(o2->ids, arr_with_prefix, 5 * 4); + u32 remote_addr[] = {10, 0, 0, 0}; + memcpy(o2->ids + 5, remote_addr, 4 * 4); + + // register first line in BGP4-MIB bgpPeerTable + // TODO register all bind bgp connections + snmp_register(p, o2, 9, 24); + + // register whole BGP4 mib-tree section + u32 arr_bgp[] = {1, 15, 1}; + struct oid *o3 = mb_allocz(p->p.pool, 4 * 4); + put_u8(&o3->n_subid, 3); + put_u8(&o3->prefix, 2); + + memcpy(o3->ids, arr_bgp, 3 * 4); + + snmp_register(p, o3, 0, 1); + + p->state = SNMP_REGISTR; + //proto_notify_state(&p->p, PS_UP); break; + + case SNMP_REGISTR: + break; + + case SNMP_CONN: + break; + + default: + die("unkonwn SNMP state"); } - proto_notify_state(&p->p, PS_UP); +} + +static int +parse_get_pdu(struct snmp_proto *p, byte *buf, uint size) +{ + log(L_INFO "parse_get_pdu()"); + + sock *sk = p->sock; + byte *res_pkt, *res = sk->tbuf; + uint rsize = sk->tbsize; + + if (size < AGENTX_HEADER_SIZE) + return 0; + + log(L_INFO "Get-PDU enough room %p", buf); + struct agentx_header *h = (void *) buf; + int byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER; + ADVANCE(buf, size, AGENTX_HEADER_SIZE); + log(L_INFO "advancing %p cause %u", buf, AGENTX_HEADER_SIZE); + byte *pkt = buf; + uint pkt_size = LOAD(h->payload, byte_ord); + log(L_INFO "packet size is %u", pkt_size); + + uint clen; + char *context = NULL; + SNMP_LOAD_CONTEXT(p, h, pkt, context, clen) + log(L_INFO "after context load %p, pkt == buf %d", pkt, pkt == buf); + + /* parsing one search range */ + struct oid *o_start, *o_end; + o_start = (struct oid *) pkt; + pkt += oid_size(o_start); + o_end = (struct oid *) pkt; // for Get-PDU always null + pkt += oid_size(o_end); + + log(L_INFO "sizes o_start %lu o_end %lu", oid_size(o_start), + oid_size(o_end)); + + log(L_INFO " creating response header rpkt %p %u", res_pkt, res_pkt - res); + log(L_INFO "o_subid: %u o_prefix %u o_include %u ---", + o_start->n_subid, o_start->prefix, o_start->include); + // TODO read a oid + // TODO allow multiple values + + res_pkt = prepare_response(p, res, rsize, AGENTX_RES_NO_ERROR, 0); + log(L_INFO "response header created: %p (%u)", res_pkt, res_pkt - res); + + res_pkt = request(res_pkt, o_start); + struct agentx_varbind *vb_start; + vb_start = (void *) res_pkt; + log(L_INFO " SNMP_CREATEish rpkt %p %u", res_pkt, res_pkt - res); + + memcpy(&vb_start->name, o_start, oid_size(o_start)); + STORE_16(vb_start->type, AGENTX_INTEGER); + STORE_16(vb_start->pad, 0); // padding zeroing + res_pkt += vb_size(vb_start); + + log(L_INFO " vb_size() rpkt %p %u", res_pkt, res_pkt - res); + + STORE_PTR(res_pkt, 0x1234ABCD); + + log(L_INFO " STORE_PTR int-value rpkt %p %u", res_pkt, res_pkt - res); + res_pkt += 4; + log(L_INFO " shift rpkt %p %u", res_pkt, res_pkt - res); + + log(L_INFO "after integer write"); + + struct agentx_header *rh = (void *) res; + SNMP_UPDATE(rh, pkt_len(res, res_pkt)); + log(L_INFO "res->payload %u (loaded) %u, trying to send: %u", + rh->payload, LOAD(rh->payload, rh->flags & AGENTX_NETWORK_BYTE_ORDER), + res_pkt - res); + + int ret = sk_send(sk, res_pkt - res); + log(L_INFO "message sent"); + + if (res == 0) + log(L_INFO "sleep"); + else if (ret < 0) + log(L_INFO "err no: %d", ret); + else + log(L_INFO "OK !!"); return 1; } @@ -262,11 +543,13 @@ snmp_start_subagent(struct snmp_proto *p) struct oid *o = mb_allocz(p->p.pool, sizeof(struct oid)); open_pdu(p, o); mb_free(o); + } void snmp_stop_subagent(struct snmp_proto *p) { + log(L_INFO "snmp_stop_subagent()"); sock *sk = p->sock; close_pdu(p, AGENTX_CLOSE_SHUTDOWN); @@ -274,10 +557,18 @@ snmp_stop_subagent(struct snmp_proto *p) sk->rx_hook = snmp_stop_ack; } -static uint +static inline uint oid_size(struct oid *o) { - return 4 + o->subid.len; + /* faster multipication by 4 */ + return 4 + (o->n_subid << 2); +} + +static inline uint +vb_size(struct agentx_varbind *vb) +{ + /* +4B for type and pad */ + return oid_size(&vb->name) + 4; } int @@ -286,126 +577,73 @@ snmp_rx(sock *sk, uint size) log(L_INFO "snmp_rx()"); struct snmp_proto *p = sk->data; byte *pkt = sk->rbuf; - byte *end = pkt + size; - parse_pkt(p, pkt, size); + // 1 means all done; 0 means to be continued + return parse_pkt(p, pkt, size); /* - while (end >= ptk + AGENTX_HEADER_SIZE) + while (end >= pkt + AGENTX_HEADER_SIZE) { parse_header(p); parse_pkt(p, ); } */ - return 0; - // 1 means all done } -void -ping_pdu(struct snmp_proto *p) +/* ping pdu */ +void +snmp_ping(struct snmp_proto *p) { /* this does not support non-default context */ sock *sk = p->sock; - byte *buf = sk->tbuf; + byte *pkt = sk->tbuf; uint size = sk->tbsize; - PASTE_HEADER(buf, AGENTX_PING_PDU, AGENTX_NETWORK_BYTE_ORDER, size); - - put_u32(&h->session_id, p->session_id); - p->transaction_id++; - put_u32(&h->transaction_id, p->transaction_id); - put_u32(&h->packet_id, 1); - put_u32(&h->payload, 0); - - sk_send(sk, AGENTX_HEADER_SIZE); -} - -/* - * cont is optional context - * upp_b is upper_bond - */ -int -snmp_register_oid(sock *sk, struct oid *subtree, u8 range, const char *cont, u32 upp_b) -{ - struct snmp_proto *p = sk->data; - byte *buf = sk->tbuf; - uint size = sk->tbsize; - log(L_INFO "snmp_register_oid() "); - - u8 flags = AGENTX_NETWORK_BYTE_ORDER | ((cont) ? AGENTX_NON_DEFAULT_CONTEXT : -0); - PASTE_HEADER(buf, AGENTX_REGISTER_PDU, flags, size); - - if (cont) - put_str(buf, cont, &size); - - put_u8(buf, p->timeout); - put_u8(buf + 1, AGENTX_PRIORITY); - put_u8(buf + 2, range); - put_u8(buf + 3, 0); // PADDING - ADVANCE(buf, size, 4); - - put_oid(buf, subtree, &size); - ADVANCE(buf, size, oid_size(subtree)); - - if (upp_b) + if (size > AGENTX_HEADER_SIZE) { - put_u32(buf, upp_b); - ADVANCE(buf, size, 4); + log(L_INFO "ping_pdu()"); + struct agentx_header *h; + log("before dead %p", pkt ); + SNMP_CREATE(pkt, struct agentx_header, h); + SNMP_B_HEADER(h, AGENTX_PING_PDU); + SNMP_SESSION(h, p); + + /* sending only header => pkt - buf */ + int ret = sk_send(sk, AGENTX_HEADER_SIZE); + if (ret == 0) + log(L_INFO "sleep"); + else if (ret < 0) + log(L_INFO "err %d", ret); + else + log("ok ! !"); } - header_update_len(sk->tbuf, buf - sk->tbuf + AGENTX_HEADER_SIZE); - - sk_send(sk, buf - sk->tbuf); + else + log(L_INFO "ping_pdu() insufficient size"); } -/* - * cont is optional context nullable - * upp_b is upper_bond - */ -int -snmp_unregister_oid(sock *sk, struct oid *subtree, const char *cont, u32 upp_b) -{ - byte *buf = sk->tbuf; - uint size = sk->tbsize; - log(L_INFO "snmp_unregister_oid()"); - u8 flags = AGENTX_NETWORK_BYTE_ORDER | ((cont) ? AGENTX_NON_DEFAULT_CONTEXT : -0); - PASTE_HEADER(buf, AGENTX_UNREGISTER_PDU, flags, size); - - if (cont) - { - put_str(buf, cont, &size); - ADVANCE(buf, size, strlen(cont) + 4); - } - - put_oid(buf, subtree, &size); - ADVANCE(buf, size, oid_size(subtree)); - - if (upp_b) - { - put_u32(buf, upp_b); - ADVANCE(buf, size, 4); - } - - sk_send(sk, buf - sk->tbuf); -} - -static void +static int snmp_stop_ack(sock *sk, uint size) { struct snmp_proto *p = sk->data; byte *buf = sk->rbuf; - + if (size < AGENTX_HEADER_SIZE) - return 0; + return 0; if (parse_response(p, buf, size)) { p->p.disabled = 1; proto_notify_state(&p->p, PS_DOWN); + + sk->tx_hook = NULL; + sk->rx_hook = NULL; } + + /* all done */ + return 0; } + /* void snmp_agent_reconfigure(void) @@ -414,4 +652,262 @@ snmp_agent_reconfigure(void) } */ +static byte * +find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *buf, uint size, uint contid) +{ + struct bgp_conn *b_conn = bp->conn; + struct bgp_conn *b_in = bp->incomming_conn; + struct bgp_conn *b_out = bp->outgoing_conn; + + uint b_state; + + if (b_conn) + b_state = b_conn->state; + else if (MAX(b_in->state, b_out->state) == BS_CLOSE && + MIN(b_in->state, b_out->state) != BS_CLOSE) + b_state = MIN(b_in->state, b_out->state); + /* BS_CLOSE is unsupported by BGP4-MIB */ + else if (MIN(b_in->state, b_out->state) == BS_CLOSE) + b_state = BS_IDLE; + else + b_state = MAX(b_in->state, b_out->state); + + struct agentx_varbind *vb = (void *) buf; + + + switch (o->ids[4]) + { + case SNMP_BGP_IDENTIFIER: + if (b_state == BS_ESTABLISHED) + STORE_PTR(pkt, ip_to_u32(b_conn->remote_ip)); + BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt); + else if (b_state == BS_OPENCONFIRM) + STORE_PTR(pkt, ip4_to_u32( (b_state == b_in->state) ? b_in->state : b_out->state)); + BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt); + else + STORE_PTR(pkt, ip4_to_u32(IPA_NONE)); + BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt); + + case SNMP_BGP_STATE: + STORE_PTR(pkt, b_state); + BGP_DATA(vb, AGENTX_INTEGER, pkt); + + case SNMP_BGP_ADMIN_STATUS: + STORE_PTR(pkt, (bp->disabled) ? AGENTX_ADMIN_STOP : AGENTX_ADMIN_START); + BGP_DATA(vb, AGENTX_INTEGER, pkt); + + case SNMP_BGP_VERSION: + STORE(pkt, BGP4_VERSIONS); + STORE + case SNMP_BGP_LOCAL_ADDR: + case SNMP_BGP_LOCAL_PORT: + case SNMP_BGP_REMOTE_ADDR: + case SNMP_BGP_REMOTE_PORT: + case SNMP_BGP_REMOTE_AS: + case SNMP_BGP_RX_UPDATES: + case SNMP_BGP_TX_UPDATES: + case SNMP_BGP_RX_MESSAGES: + case SNMP_BGP_TX_MESSAGES: + + case SNMP_BGP_FSM_TRANSITIONS: + + case SNMP_BGP_RETRY_INTERVAL: + case SNMP_BGP_HOLD_TIME: + case SNMP_BGP_KEEPALIVE: + case SNMP_BGP_HOLD_TIME_CONFIGURED: + case SNMP_BGP_KEEPALIVE_CONFIGURED: + + /* UNSUPPORTED */ + case SNMP_BGP_LAST_ERROR: + + case SNMP_BGP_FSM_ESTABLISHED_TIME: + + case SNMP_BGP_ORIGINATION_INTERVAL: + case SNMP_BGP_MIN_ROUTE_ADVERTISEMENT: + case SNMP_BGP_MIN_UPDATE_ELAPSED_TIME: + defualt: + vb->type = AGENTX_NO_SUCH_OBJECT; + /* pkt += 0; no data */ + break; + } +} + +/* contid - context identification number */ +static byte * +find_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid) +{ + struct agentx_varbind *vb = (void *) buf; + + if (o->n_subid < 3) + { + vb->type = AGENTX_NO_SUCH_OBJECT; + return buff + vb_size(vb); + } + + byte *pkt = buf + vb_size(vb); + switch (o->ids[2]) + { + case BGP4_MIB_VERSION: + vb->type = AGENTX_OCTET_STRING; + STORE(pkt, BGP4_VERSIONS); + pkt += 4; + break; + + case BGP4_MIB_LOCAL_AS: + vb->type = AGENTX_INTEGER; + // XXX local as to use + STORE(pkt, p->local_as); + pkt += 4; + break; + + case BGP4_PEER_TABLE: + /* end part of .1.3.6.1.2.1.15.3.1.x.a.b.c.d */ + if (o->n_subid < 9 || o->ids[3] != 1 + || o->ids[4] == 0 || o->ids[4] > 24) + { + vb->type = AGENTX_NO_SUCH_OBJECT; + return buff + vb_size(vb); + } + + // TODO enumerate range requests + ip_addr addr = ipa_build4(o->ids[5], o->ids[6], o->ids[7], o->ids[8]); + struct snmp_bgp_peer_entry *pe = + HASH_FIND(p->bgp_entries, SNMP_HASH, addr); + + struct bgp_proto *bp = NULL; + if (pe && pe->bond->proto->proto && + ipa_equal(pe->bond->proto->proto->remote_ip, addr)) + { + bp = pe->bond->proto->proto; + } + else + { + struct snmp_bond *b; + WALK_LIST(b, p->bgp_entries) + if (b->proto->proto && + ipa_equal(b->proto->proto->remote_ip, addr)) + bp = b->proto->proto; + } + + if (!bp) + { + vb->type = AGENTX_NO_SUCH_OBJECT; + /* pkt += 0; no data */ + return pkt; + } + + return find_bgp_one(bp, o, buf, size, contid); + break; + + default: + vb->type = AGENTX_NO_SUCH_OBJECT; + /* pkt += 0; no data */ + break; + } + + return pkt; +} + +static byte * +find_ospf_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size) +{ + // TODO XXX + return NULL; +} + +static inline byte * +find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size) +{ + struct agetnx_varbind *vb = (void *) buf; + + memcpy(&vb->name, o, oid_size(o)); + + /* SNMPv2 mgmt mib-2 */ + if (o->n_subid < 2 || (o->prefix != 2 && o->ides[0] != 1)) + { + vb->type = AGENTX_NO_SUCH_OBJECT; + return buf + vb_size(vb); + } + + switch (o->ids[1]) + { + case SNMP_BGP4_MIB: + return find_bgp_record(p, o, buf, size); + + case SNMP_OSPFv3_MIB: + return find_ospf_record(p, o, buf, size); + + /* the old OSPF */ + case SNMP_OSPF_MIB: + log("too old OSPF oid request"); + break; + + default: + log(L_INFO "unsupported oid"); + break; + } + + vb->type = AGENTX_NO_SUCH_OBJECT; + return buf + vb_size(vb); +} + +/* tests if there is present canonical "internet" prefix .1.3.6.1 + and if so it shortens the oid to the ``prefix'' form */ +static int +prefixize(struct oid *o, int byte_ord) +{ + const u32 prefix[] = {1, 3, 6, 1}; + + /* NETWORK_BYTE_ORDER */ + if (byte_ord) + /* prefix len == 4 */ + for (uint i = 0; i < 4; i++) + if (get_u32(&o->ids[i]) != prefix[i]) return 0; + + else + /* prefix len == 4 */ + for (uint i = 0; i < 4; i++) + if (o->ids[i] != prefix[i]) return 0; + + o->n_subid -= 5; + o->prefix = o->ids[4]; + /* n_subid contains number of elements, not bytes */ + memmove(&o->ids, &o->ids[5], o->n_subid << 2); + return 1; +} + +static inline byte * +find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, int byte_ord) +{ + if (!o->prefix && prefixize(o, byte_ord)) + find_prefixed(p, o, buf, size); + else if (o->prefix) + find_prefixed(p, o, buf, size); + else + return NULL; +} + +static byte * +prepare_response(struct snmp_proto *p, byte *buf, uint size, u16 err_no, u16 index) +{ + log(L_INFO "prepare_response()"); + + if (size < sizeof(struct agentx_response)) + return NULL; + + struct agentx_response *r = (void *) buf; + struct agentx_header *h = &r->h; + + SNMP_B_HEADER(h, AGENTX_RESPONSE_PDU) + SNMP_SESSION(h, p) + + /* protocol doesn't care about subagent upTime */ + STORE(r->uptime, 0); + STORE_16(r->err, err_no); + STORE_16(r->index, index); + + buf += sizeof(struct agentx_response); + return buf; +} + #undef SNMP_ERR_SHIFT diff --git a/proto/snmp/subagent.h b/proto/snmp/subagent.h index 71320519..c34dfa4b 100644 --- a/proto/snmp/subagent.h +++ b/proto/snmp/subagent.h @@ -6,36 +6,111 @@ void snmp_start_subagent(struct snmp_proto *p); void snmp_stop_subagent(struct snmp_proto *p); +void snmp_ping(struct snmp_proto *p); -#define AGENTX_INTEGER 2 -#define AGENTX_OCTET_STRING 4 -#define AGENTX_NULL 5 -#define AGENTX_OBJECT_ID 6 -#define AGENTX_IP_ADDRESS 64 -#define AGENTX_COUNTER_32 65 -#define AGENTX_GAUGE_32 66 -#define AGENTX_TIME_TICKS 67 -#define AGENTX_OPAQUE 68 -#define AGENTX_COUNTER_64 70 -#define AGENTX_NO_SUCH_OBJECT 128 -#define AGENTX_NO_SUCH_INSTANCE 129 -#define AGENTX_END_OF_MIB_VIEW 130 +#define AGENTX_VERSION 1 + +#define SNMP_OSPF_MIB 14 /* part of oid .1.3.6.1.2.1.14 */ +#define SNMP_BGP4_MIB 15 /* part of oid .1.3.6.1.2.1.15 */ +#define SNMP_OSPFv3_MIB 192 /* part of oid .1.3.6.1.2.1.192 */ + +enum agentx_type { + AGENTX_INTEGER = 2; + AGENTX_OCTET_STRING = 4; + AGENTX_NULL = 5; + AGENTX_OBJECT_ID = 6; + AGENTX_IP_ADDRESS = 64; + AGENTX_COUNTER_32 = 65; + AGENTX_GAUGE_32 = 66; + AGENTX_TIME_TICKS = 67; + AGENTX_OPAQUE = 68; + AGENTX_COUNTER_64 = 70; + AGENTX_NO_SUCH_OBJECT = 128; + AGENTX_NO_SUCH_INSTANCE = 129; + AGENTX_END_OF_MIB_VIEW = 130; +} PACKED; + +#define AGENTX_ADMIN_STOP 1 +#define AGENTX_ADMIN_START 2 #define AGENTX_PRIORITY 127 #define MAX_STR 0xFFFFFFFF -#define PASTE_HEADER_(buf, v, t, f, s) \ - memset(buf, 0, sizeof(struct agentx_header)); \ - struct agentx_header *h = (void *) buf; \ - log(L_INFO "value : %d", (void *) h == buf? 1:0); \ - h->version = v; \ - h->type = t; \ - h->flags = f; \ - h->pad = 0; \ - ADVANCE(buf, s, sizeof(struct agentx_header)); \ +#define SNMP_NATIVE -#define PASTE_HEADER(buf, t, f, s) PASTE_HEADER_(buf, AGENTX_VERSION, t, f, s) -#define U32_CPY(w, u) memcpy((w), (u), 4); ADVANCE((w), 4, 4); +#ifdef SNMP_NATIVE +#define STORE(v,c) (v) = (u32) (c) +#define STORE_16(v,c) (v) = (u16) (c) +#define STORE_PTR(v,c) *((u32 *) (v)) = (u32) (c) +#define SNMP_UPDATE(h,l) \ + STORE((h)->payload, l) + +#else +#define STORE(v, c) put_u32(&v, c) +#define STORE_16(v,c) put_u32(&v, c) +#define STORE_PTR(v,c) put_u32(v, c) +#define SNMP_UPDATE(h,l) \ + STORE(h->payload, l) +#endif + +/* storing byte (u8) is always the same */ +#define SNMP_HEADER_(h, v, t, f) \ + put_u8(&h->version, v); \ + put_u8(&h->type, t); \ + put_u8(&h->flags, f); \ + put_u8(&h->pad, 0); + +#ifdef SNMP_NATIVE +#define SNMP_HEADER(h,t,f) SNMP_HEADER_(h, AGENTX_VERSION, t, f) +#else +#define SNMP_HEADER(h,t,f) \ + SNMP_HEADER_(h, AGENTX_VERSION, t, f | SNMP_NETWORK_BYTE_ORDER) +#endif + +#define SNMP_B_HEADER(h, t) SNMP_HEADER(h, t, AGENTX_FLAG_BLANK) + +#define SNMP_SESSION(h, p) \ + STORE(h->session_id, p->session_id); \ + STORE(h->transaction_id, p->transaction_id); \ + p->transaction_id++; \ + STORE(h->packet_id, p->packet_id); + +#define SNMP_CREATE(b, t, n) \ + n = (void *) (b); \ + memset(n, 0, sizeof(t)); \ + (b) += sizeof(t); + +#define LOAD(v, bo) ((bo) ? get_u32(&v) : (u32) (v)) +#define LOAD_16(v, bo) ((bo) ? get_u16(&v) : (u16) (v)) +#define LOAD_PTR(v, bo) ((bo) ? get_u32(v) : (u32) *(v)) + +#define LOAD_STR(p, b, s, l, bo) \ + l = LOAD(*((u32 *) b), bo); \ + log(L_INFO "LOAD_STR(), %p %u", p->p.pool, l + 1); \ + s = mb_allocz(p->p.pool, l + 1); \ + memcpy(s, b, l); \ + b += str_size(s); + +#define SNMP_LOAD_CONTEXT(p, h, b, s, l) \ + if (h->flags & AGENTX_NON_DEFAULT_CONTEXT) \ + { log(L_INFO "encountered non-default context"); \ + LOAD_STR(p, b, s, l, h->flags & AGENTX_NETWORK_BYTE_ORDER); } + +#define SNMP_COPY_OID(b, o) \ + memcpy(b, o, oid_size(o)); \ + b += oid_size(o); + +#define SNMP_COPY_VB(b, s, e) \ + memcpy(b, s, 4); \ + b += 4; \ + SNMP_COPY_OID(b, &s->name) \ + SNMP_COPY_OID(b, e) + +#define BGP_DATA_(v, d, p, o) \ + (v)->type = d; \ + p += o; + +#define BGP_DATA(v, d, p) BGP_DATA(v, d, p, 4) struct agentx_header { u8 version; @@ -50,17 +125,12 @@ struct agentx_header { #define AGENTX_HEADER_SIZE sizeof(struct agentx_header) -struct subid{ - u32 len; - u32 ids[]; -}; - struct oid { u8 n_subid; u8 prefix; u8 include; u8 pad; - struct subid subid; + u32 ids[]; }; struct agentx_varbind { @@ -70,6 +140,7 @@ struct agentx_varbind { struct oid name; }; +/* this does not work */ struct agentx_search_range { struct oid start; struct oid end; @@ -82,7 +153,18 @@ struct agentx_response { u16 index; }; -#define AGENTX_VERSION 1 +struct agentx_close_pdu { + struct agentx_header h; + u8 reason; +}; + +struct agentx_un_register_pdu { + struct agentx_header h; + u8 timeout; + u8 priority; + u8 range_subid; + u8 padd; +}; enum agentx_pdu { AGENTX_OPEN_PDU = 1, @@ -108,6 +190,7 @@ enum agentx_pdu { #define AGENTX_FLAGS_MASK 0x1F enum agentx_flags { + AGENTX_FLAG_BLANK = 0x00, AGENTX_FLAG_INSTANCE_REGISTRATION = 0x01, AGENTX_FLAG_NEW_INDEX = 0x02, AGENTX_FLAG_ANY_INDEX = 0x04,