diff --git a/lib/lists.h b/lib/lists.h index 86ff59c9..5bfe19f3 100644 --- a/lib/lists.h +++ b/lib/lists.h @@ -9,6 +9,8 @@ #ifndef _BIRD_LISTS_H_ #define _BIRD_LISTS_H_ +#include "lib/birdlib.h" + /* * I admit the list structure is very tricky and also somewhat awkward, * but it's both efficient and easy to manipulate once one understands the diff --git a/proto/snmp/Makefile b/proto/snmp/Makefile index f121af25..ca589059 100644 --- a/proto/snmp/Makefile +++ b/proto/snmp/Makefile @@ -1,8 +1,8 @@ -src := snmp.c bgp_mib.c subagent.c +src := snmp.c subagent.c obj := $(src-o-files) LIBS += `net-snmp-config --agent-libs` $(all-daemon) $(cf-local) -$(call proto-build,snmp_build_) +$(call proto-build,snmp_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/snmp/bgp_mib.c b/proto/snmp/bgp_mib.c index dae6a945..6f80acdc 100644 --- a/proto/snmp/bgp_mib.c +++ b/proto/snmp/bgp_mib.c @@ -24,15 +24,16 @@ #undef PACKAGE_TARNAME #undef PACKAGE_VERSION -#include "proto/snmp/bgp_mib.h" -#include "lib/birdlib.h" +#include "bgp_mib.h" +#include "snmp.h" static int bgpPeerTable_handler( netsnmp_mib_handler *handler, // contains void * for internal use netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, - netsnmp_request_info *requests) { + netsnmp_request_info *requests) +{ /* perform anything here that you need to do. The requests have already been processed by the master table_dataset handler, but diff --git a/proto/snmp/config.Y b/proto/snmp/config.Y index f50f314b..7593ef5f 100644 --- a/proto/snmp/config.Y +++ b/proto/snmp/config.Y @@ -28,15 +28,32 @@ snmp_proto: snmp_proto_start '{' | snmp_proto proto_item ';' | snmp_proto snmp_bgp_bond ';' - | snmp_proto ';' + | snmp_proto LOCAL PORT expr ';' { SNMP_CFG->local_port = $4; if (($4<1) || +($4>65535)) cf_error("Invalid port number"); } + | snmp_proto REMOTE PORT expr ';' { SNMP_CFG->remote_port = $4; if (($4<1) || +($4>65545)) cf_error("Invalid port number"); } + | snmp_proto LOCAL ipa ';' { SNMP_CFG->local_ip = $3; } + | snmp_proto REMOTE ipa ';' { SNMP_CFG->remote_ip = $3; if(!ipa_nonzero($3)) +cf_error("Invalid remote ip address"); } ; snmp_proto_start: proto_start SNMP { this_proto = proto_config_new(&proto_snmp, $1); init_list(&SNMP_CFG->bgp_entries); + + SNMP_CFG->local_ip = IPA_NONE; + SNMP_CFG->remote_ip = ipa_build4(127,0,0,1); + SNMP_CFG->local_port = 0; + SNMP_CFG->remote_port = 705; + + SNMP_CFG->timeout = 15; } +proto_name ; + + + snmp_bgp_bond: BGP symbol { struct snmp_bond *this_bond = cfg_alloc(sizeof(struct snmp_bond)); diff --git a/proto/snmp/snmp.c b/proto/snmp/snmp.c index 2bf37d58..3f76a4c4 100644 --- a/proto/snmp/snmp.c +++ b/proto/snmp/snmp.c @@ -11,53 +11,142 @@ */ #include "nest/bird.h" -#include "nest/protocol.h" #include "nest/cli.h" +#include "nest/locks.h" +#include "lib/socket.h" -#include "proto/snmp/snmp.h" -#include "proto/snmp/subagent.h" -#include "proto/snmp/bgp_mib.h" +#include "snmp.h" +#include "subagent.h" + +static void snmp_connected(sock *sk); +static void snmp_sock_err(sock *sk, int err); +static void snmp_ping_timer(struct timer *tm); static struct proto * snmp_init(struct proto_config *CF) { struct proto *P = proto_new(CF); - struct snmp_proto *p = (void *) P; + struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P); + struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, CF); p->rl_gen = (struct tbf) TBF_DEFAULT_LOG_LIMITS; + p->local_ip = cf->local_ip; + p->remote_ip = cf->remote_ip; + p->local_port = cf->local_port; + p->remote_port = cf->remote_port; + + // p->timeout = cf->timeout; + p->timeout = 15; + + log(L_INFO "snmp_reconfigure() lip: %I:%u rip: %I:%u", + cf->local_ip, cf->local_port, cf->remote_ip, cf->remote_port); + return P; } -void start_multihook(void) +static void +snmp_start_locked(struct object_lock *lock) { - /* init bgp MIB table */ - snmp_init_bgp_table(); + log(L_INFO "snmp_start_locked() - preparing socket "); + struct snmp_proto *p = lock->data; - /* init ospf MIB table */ - //snmp_inti_ospf_table(); + sock *s = sk_new(p->p.pool); + s->type = SK_TCP_ACTIVE; + s->saddr = p->local_ip; + s->daddr = p->remote_ip; + s->dport = p->remote_port; + s->rbsize = SNMP_RX_BUFFER_SIZE; + s->tbsize = SNMP_TX_BUFFER_SIZE; + + // s->tos = IP_PREC_INTERNET_CONTROL + //s->rx_hook = snmp_connected; + s->tx_hook = snmp_connected; + s->err_hook = snmp_sock_err; + + p->sock = s; + s->data = p; + + if (sk_open(s) < 0) + log(L_ERR "Cannot open listening socket"); + + log(L_INFO "socket ready!, trying to connect"); +} + +static void +snmp_tx(sock *sk UNUSED) +{ + log(L_INFO "snmp_tx() recieved something, yay!"); +} + + +static void +snmp_connected(sock *sk) +{ + struct snmp_proto *p = sk->data; + log(L_INFO "snmp_connected() connection created"); + byte *buf UNUSED = sk->rbuf; + + sk->rx_hook = snmp_rx; + sk->tx_hook = snmp_tx; + + snmp_start_subagent(p); +} + +static void +snmp_sock_err(sock *sk UNUSED, int err UNUSED) +{ + log(L_INFO "snmp_sock_err() "); } static int snmp_start(struct proto *P) { - /* init MIB tables */ - if (snmp_start_subagent(start_multihook)) - return PS_UP; - else - return PS_DOWN; + log(L_INFO "snmp_start() - starting timer (almost)"); + struct snmp_proto *p = (void *) P; + + p->ping_timer = tm_new_init(p->p.pool, snmp_ping_timer, p, 0, 0); + tm_set(p->ping_timer, current_time() + (7 S_)); + + /* starting agentX communicaiton channel */ + log(L_INFO "preparing lock"); + struct object_lock *lock; + lock = p->lock = olock_new(P->pool); + + lock->type = OBJLOCK_TCP; + lock->hook = snmp_start_locked; + lock->data = p; + + olock_acquire(lock); + log(L_INFO "lock acquired"); + + log(L_INFO "local ip: %I:%u, remote ip: %I:%u", + p->local_ip, p->local_port, p->remote_ip, p->remote_port); + + return PS_START; } static int snmp_reconfigure(struct proto *P, struct proto_config *CF) { + struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P); + struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, CF); + + p->local_ip = cf->local_ip; + p->remote_ip = cf->remote_ip; + p->local_port = cf->local_port; + p->remote_port = cf->remote_port; + p->timeout = 15; + + 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; } static void snmp_show_proto_info(struct proto *P) { - struct snmp_proto *sp = (void *) P; + //struct snmp_proto *sp = (void *) P; struct snmp_config *c = (void *) P->cf; cli_msg(-1006, " BGP peers"); @@ -66,7 +155,6 @@ snmp_show_proto_info(struct proto *P) { struct proto_config *cf = P->cf; struct bgp_config *bcf = (struct bgp_config *) cf; - struct proto_config *pcf = (void *) bond->proto; struct proto *p = cf->proto; struct bgp_proto *bp = (struct bgp_proto *) cf->proto; struct bgp_conn *conn = bp->conn; @@ -83,10 +171,12 @@ snmp_show_proto_info(struct proto *P) cli_msg(-1006, " remote ip: %u", bcf->remote_ip); cli_msg(-1006, " local port: %u", bcf->local_port); cli_msg(-1006, " remote port: %u", bcf->remote_port); + /* if (conn) { cli_msg(-1006, " state: %u", conn->state); cli_msg(-1006, " remote as: %u", conn->remote_caps->as4_number); } + */ cli_msg(-1006, " in updates: %u", bp->stats.rx_updates); cli_msg(-1006, " out updates: %u", bp->stats.tx_updates); cli_msg(-1006, " in total: %u", bp->stats.rx_messages); @@ -98,10 +188,12 @@ bp->stats.fsm_established_transitions); cli_msg(-1006, " fsm total time: --"); cli_msg(-1006, " retry interval: %u", bcf->connect_retry_time); + /* if (conn) { cli_msg(-1006, " hold time: %u", conn->hold_time); cli_msg(-1006, " keep alive: %u", conn->keepalive_time ); } + */ cli_msg(-1006, " hold configurated: %u", bcf->hold_time ); cli_msg(-1006, " keep alive config: %u", bcf->keepalive_time ); @@ -119,19 +211,22 @@ bp->stats.fsm_established_transitions); } } - -void -shutdown_multihook(void) +static void +snmp_ping_timer(struct timer *tm) { - snmp_del_bgp_table(); - //snmp_del_ospf_table(); + log(L_INFO "snmp_ping_timer() "); + struct snmp_proto *p = tm->data; + + // ping here + ping_pdu(p); } /* snmp_shutdown already occupied by net-snmp */ -void -snmp_shutdown_(struct proto *P) +static int +snmp_shutdown(struct proto *P) { - snmp_stop_subagent(shutdown_multihook); + struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P); + snmp_stop_subagent(p); } struct protocol proto_snmp = { @@ -143,13 +238,13 @@ struct protocol proto_snmp = { .init = snmp_init, .start = snmp_start, .reconfigure = snmp_reconfigure, - .shutdown = snmp_shutdown_, + .shutdown = snmp_shutdown, .show_proto_info = snmp_show_proto_info, }; -/* strange name because conflict with net-snmp lib snmp_lib() */ +/* strange name because of conflict with net-snmp lib snmp_lib() */ void -snmp_build_(void) +snmp_build(void) { proto_build(&proto_snmp); } diff --git a/proto/snmp/snmp.h b/proto/snmp/snmp.h index 57709f5b..90236c5c 100644 --- a/proto/snmp/snmp.h +++ b/proto/snmp/snmp.h @@ -8,15 +8,26 @@ */ #ifndef _BIRD_SNMP_H_ -#define _BIRD_SNPM_H_ +#define _BIRD_SNMP_H_ +#include "lib/ip.h" +#include "lib/socket.h" +#include "lib/timer.h" +#include "nest/bird.h" +#include "nest/protocol.h" #include "proto/bgp/bgp.h" + #define SNMP_UNDEFINED 0 #define SNMP_BGP 1 #define SNMP_OSPF 2 #define SNMP_INVALID 255 +#define SNMP_PORT 705 + +#define SNMP_RX_BUFFER_SIZE 2048 +#define SNMP_TX_BUFFER_SIZE 2048 + struct snmp_bond { node n; struct proto_config *proto; @@ -24,13 +35,32 @@ struct snmp_bond { }; struct snmp_config { - struct channel_config c; + struct proto_config cf; + ip_addr local_ip; + ip_addr remote_ip; + u16 local_port; + u16 remote_port; + u8 timeout; + //struct iface *iface; list bgp_entries; }; struct snmp_proto { - struct channel c; + 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 struct tbf rl_gen; + timer *ping_timer; }; struct snmp_channel_config { @@ -43,4 +73,6 @@ struct snmp_channel { struct channel c; }; + + #endif diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index 5bc81d34..f7aa4c39 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -6,89 +6,412 @@ * * Can be freely distributed and used under the terms of the GNU GPL. * - * Parts of this file were auto-generated from net-snmp-config */ -#include +#include "lib/unaligned.h" +#include "subagent.h" -#ifdef HAVE_SIGNAL -#include -#endif +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); -#ifdef HAV_SYS_STAT_H -#include -#endif +static const char * const snmp_errs[] = { + #define SNMP_ERR_SHIFT 256 + [AGENTX_RES_OPEN_FAILED - SNMP_ERR_SHIFT] = "Open failed", + [AGENTX_RES_NOT_OPEN - SNMP_ERR_SHIFT] = "Not open", + [AGENTX_RES_INDEX_WRONG_TYPE - SNMP_ERR_SHIFT] = "Index wrong type", + [AGENTX_RES_INDEX_ALREADY_ALLOC - SNMP_ERR_SHIFT] = "Index already allocated", + [AGENTX_RES_INDEX_NONE_AVAIL - SNMP_ERR_SHIFT] = "Index none availlable", + [AGENTX_RES_NOT_ALLOCATED - SNMP_ERR_SHIFT] = "Not allocated", + [AGENTX_RES_UNSUPPORTED_CONTEXT - SNMP_ERR_SHIFT] = "Unsupported contex", + [AGENTX_RES_DUPLICATE_REGISTR - SNMP_ERR_SHIFT] = "Duplicate registration", + [AGENTX_RES_UNKNOWN_REGISTR - SNMP_ERR_SHIFT] = "Unknown registration", + [AGENTX_RES_UNKNOWN_AGENT_CAPS - SNMP_ERR_SHIFT] = "Unknown agent caps", + [AGENTX_RES_PARSE_ERROR - SNMP_ERR_SHIFT] = "Parse error", + [AGENTX_RES_REQUEST_DENIED - SNMP_ERR_SHIFT] = "Request denied", + [AGENTX_RES_PROCESSING_ERR - SNMP_ERR_SHIFT] = "Processing error", +}; -#ifdef HAVE_FCNTL_H -#include -#endif - -#include -#include - -extern int netsnmp_running; - -int -snmp_start_subagent(void (*hook)(void)) +static int +put_str(byte *buf, const char *str, uint *size) { - /* subagent mode */ - netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, - NETSNMP_DS_AGENT_ROLE, 1); + uint len = strlen(str); + uint pkt_len = BIRD_ALIGN(len, 4); - /* forking netsnmp mechanism * / - if (netsnmp_daemonize(1, snmp_stderrolog_status()) != 0) - return 0; // start FAILED - */ + if (len > MAX_STR) + return -1; - /* for Win32 only */ - SOCK_STARTUP; + put_u32(buf, len); + + memcpy(buf + 4, str, len); - /* init library */ - init_agent("bird"); + // make the value 32-bit aligned + for (uint i = 0; i < pkt_len - len; i++) + buf[len + i] = 0x00; // PADDING - if (hook) - hook(); + *size += (4 + pkt_len); - /* used for loading config 'bird-snmp.conf' */ - init_snmp("bird-snmp"); - - return 1; // SUCCESS + return 0; } +static void +put_blank(byte *buf, uint *size) +{ + buf[0] = buf[1] = buf[2] = buf[3] = 0; + *size += 4; +} + +static void +put_oid(byte *buf, struct oid *oid, uint *size) +{ + put_u8(buf, oid->n_subid); + put_u8(buf + 1, oid->prefix); + put_u8(buf + 2, oid->include); + put_u8(buf + 3, 0); // PADDING + + put_u32s(buf + 4, oid->subid.ids, oid->subid.len); + + *size += (4 + oid->subid.len); +} + +/* paste data at first byte in message + * with 3B of padding + */ +static void +paste_fbyte(byte *buf, u8 data, uint *size) +{ + 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; +} + +static void +open_pdu(struct snmp_proto *p, struct oid *oid) +{ + sock *sk = p->sock; + byte *buf, *pkt, *end; + 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); + + /* +8 - header of oid (4) and octet string length (4) */ + if (size > AGENTX_HEADER_SIZE + oid->subid.len + slen + 8) + { + 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); + + // use random num instead + put_u32(&h->session_id, 1); + put_u32(&h->transaction_id, 1); + put_u32(&h->packet_id, 1); + + paste_fbyte(pkt, p->timeout, &pkt_size); + ADVANCE(pkt, size, 4); + + put_oid(pkt, oid, &pkt_size); + ADVANCE(pkt, size, oid_size(oid)); + + /* paste description */ + put_str(pkt, str, &pkt_size); + ADVANCE(pkt, size, slen); + + 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) + log(L_INFO "err %d", ret); + else + log(L_INFO "ok !!! "); + } + + else + log(L_INFO "open_pdu() insufficient size, %u <= %u ", + size, AGENTX_HEADER_SIZE + oid->subid.len + slen + 8); +} + +static void +close_pdu(struct snmp_proto *p, u8 reason) +{ + sock *sk = p->sock; + byte *buf, *pkt; + buf = pkt = sk->tbuf; + uint size = sk->tbsize; + log(L_INFO "close_pdu() size: %u %c %u", size, (size > AGENTX_HEADER_SIZE + 4) +? '>':'<', AGENTX_HEADER_SIZE); + + /* +4B for reason */ + if (size > AGENTX_HEADER_SIZE + 4) + { + PASTE_HEADER(buf, AGENTX_CLOSE_PDU, AGENTX_NETWORK_BYTE_ORDER, size); + + 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); + + ADVANCE(pkt, size, sizeof(struct agentx_header)); + + paste_fbyte(pkt, reason, &size); + ADVANCE(pkt, size, 4); + + /* 4 - reason size */ + header_update_len(sk->tbuf, 4); + + int ret = sk_send(sk, sizeof(struct agentx_header) + 4); + + if (ret == 0) + log(L_INFO "sleep"); + else if (ret < 0) + log(L_INFO "err"); + else + log(L_INFO, "ok !! "); + } +} + +static int +parse_pkt(struct snmp_proto *p, byte *buf, uint size) +{ + if (size < AGENTX_HEADER_SIZE) + return 0; + + struct agentx_header *h = (void *) buf; + switch (h->type) + { + case AGENTX_RESPONSE_PDU: + return parse_response(p, buf, size); + break; + + /* should not happen */ + default: + die("unknown packet type"); + } +} + +static int +parse_response(struct snmp_proto *p, byte *buf, uint size) +{ + if (size < sizeof(struct agentx_response)) + return 0; + + 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 "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) - +SNMP_ERR_SHIFT]); + break; + } + proto_notify_state(&p->p, PS_UP); + + return 1; +} + +static void +header_update_len(byte *buf, u32 len) +{ + struct agentx_header *h = (void *) buf; + put_u32(&h->payload, len); + log(L_INFO "header_update_len() %d 0x%02X 0x%02X 0x%02X 0x%02X", len, *((unsigned char +*) &h->payload), *(((unsigned char *) &h->payload) + 1), *(((unsigned char *) +&h->payload) + 2), *(((unsigned char *) &h->payload) + 3)); + +} + +void +snmp_start_subagent(struct snmp_proto *p) +{ + log(L_INFO "snmp_start_subagent() starting subagent"); + + /* blank oid means unsupported */ + 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) +{ + sock *sk = p->sock; + + close_pdu(p, AGENTX_CLOSE_SHUTDOWN); + + sk->rx_hook = snmp_stop_ack; +} + +static uint +oid_size(struct oid *o) +{ + return 4 + o->subid.len; +} + +int +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); + /* + while (end >= ptk + AGENTX_HEADER_SIZE) + { + parse_header(p); + parse_pkt(p, ); + } + */ + return 0; + // 1 means all done +} + +void +ping_pdu(struct snmp_proto *p) +{ + /* this does not support non-default context */ + sock *sk = p->sock; + byte *buf = 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) + { + put_u32(buf, upp_b); + ADVANCE(buf, size, 4); + } + + header_update_len(sk->tbuf, buf - sk->tbuf + AGENTX_HEADER_SIZE); + + sk_send(sk, buf - sk->tbuf); +} + +/* + * 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 +snmp_stop_ack(sock *sk, uint size) +{ + struct snmp_proto *p = sk->data; + byte *buf = sk->rbuf; + + if (size < AGENTX_HEADER_SIZE) + return 0; + + if (parse_response(p, buf, size)) + { + p->p.disabled = 1; + proto_notify_state(&p->p, PS_DOWN); + } +} +/* void snmp_agent_reconfigure(void) { - free_config(); - read_configs(); + } +*/ -void -snmp_shutdown_subagent(void (*hook)(void)) -{ - /* at shutdown time */ - snmp_shutdown("bird"); - - /* shutdown hook */ - if (hook) - hook(); - - /* shutdown the agent library */ - shutdown_agent(); - - /* for Win32 only */ - SOCK_CLEANUP; -} - -void -snmp_stop_subagent(void (*hook)(void)) -{ - /* at shutdown time */ - snmp_shutdown("bird"); - - /* deinitialize MIB code */ - if (hook) - hook(); - - /* shutdown the agent library */ - shutdown_agent(); -} +#undef SNMP_ERR_SHIFT diff --git a/proto/snmp/subagent.h b/proto/snmp/subagent.h index 9cd92357..71320519 100644 --- a/proto/snmp/subagent.h +++ b/proto/snmp/subagent.h @@ -1,8 +1,148 @@ #ifndef _BIRD_SNMP_SUBAGENT_H_ #define _BIRD_SNMP_SUBAGENT_H_ -int snmp_start_subagent(void (*hook)(void)); -void snmp_agent_reconfigure(void); -void snmp_stop_subagent(void (*hook)(void)); +#include "nest/bird.h" +#include "snmp.h" +void snmp_start_subagent(struct snmp_proto *p); +void snmp_stop_subagent(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_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 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); + +struct agentx_header { + u8 version; + u8 type; + u8 flags; + u8 pad; + u32 session_id; + u32 transaction_id; + u32 packet_id; + u32 payload; /* length of the packet without 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; +}; + +struct agentx_varbind { + u16 type; + u16 pad; + /* oid part */ + struct oid name; +}; + +struct agentx_search_range { + struct oid start; + struct oid end; +}; + +struct agentx_response { + struct agentx_header h; + u32 uptime; + u16 err; + u16 index; +}; + +#define AGENTX_VERSION 1 + +enum agentx_pdu { + AGENTX_OPEN_PDU = 1, + AGENTX_CLOSE_PDU = 2, + AGENTX_REGISTER_PDU = 3, + AGENTX_UNREGISTER_PDU = 4, + AGENTX_GET_PDU = 5, + AGENTX_GET_NEXT_PDU = 6, + AGENTX_GET_BULK_PDU = 7, + AGENTX_TEST_SET_PDU = 8, + AGENTX_COMMIT_SET_PDU = 9, + AGENTX_UNDO_SET_PDU = 10, + AGENTX_CLEANUP_SET_PDU = 11, + AGENTX_NOTIFY_PDU = 12, + AGENTX_PING_PDU = 13, + AGENTX_INDEX_ALLOCATE_PDU = 14, + AGENTX_INDEX_DEALLOCATE_PDU = 15, + AGENTX_ADD_AGENT_CAPS_PDU = 16, + AGENTX_REMOVE_AGENT_CAPS_PDU = 17, + AGENTX_RESPONSE_PDU = 18, +} PACKED; + +#define AGENTX_FLAGS_MASK 0x1F + +enum agentx_flags { + AGENTX_FLAG_INSTANCE_REGISTRATION = 0x01, + AGENTX_FLAG_NEW_INDEX = 0x02, + AGENTX_FLAG_ANY_INDEX = 0x04, + AGENTX_NON_DEFAULT_CONTEXT = 0x08, + AGENTX_NETWORK_BYTE_ORDER = 0x10, +} PACKED; + +/* CLOSE_PDU close reasons */ +enum agentx_close_reasons { + AGENTX_CLOSE_OTHER = 1, + AGENTX_CLOSE_PARSE_ERROR = 2, + AGENTX_CLOSE_PROTOCOL_ERROR = 3, + AGENTX_CLOSE_TIMEOUTS = 4, + AGENTX_CLOSE_SHUTDOWN = 5, + AGENTX_CLOSE_BY_MANAGER = 6, +} PACKED; + + +/* RESPONSE_PDU - result error */ +enum agentx_response_err { + AGENTX_RES_NO_ERROR = 0, + AGENTX_RES_OPEN_FAILED = 256, + AGENTX_RES_NOT_OPEN = 257, + AGENTX_RES_INDEX_WRONG_TYPE = 258, + AGENTX_RES_INDEX_ALREADY_ALLOC = 259, + AGENTX_RES_INDEX_NONE_AVAIL = 260, + AGENTX_RES_NOT_ALLOCATED = 261, + AGENTX_RES_UNSUPPORTED_CONTEXT = 262, + AGENTX_RES_DUPLICATE_REGISTR = 263, + AGENTX_RES_UNKNOWN_REGISTR = 264, + AGENTX_RES_UNKNOWN_AGENT_CAPS = 265, + AGENTX_RES_PARSE_ERROR = 266, + AGENTX_RES_REQUEST_DENIED = 267, + AGENTX_RES_PROCESSING_ERR = 268, +} PACKED; + +int snmp_rx(sock *sk, uint size); #endif