#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
-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)
#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
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));
*/
#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;
+
+ 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);
+}
- /* init ospf MIB table */
- //snmp_inti_ospf_table();
+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");
{
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;
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);
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 );
}
}
-
-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 = {
.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);
}
*/
#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;
};
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 {
struct channel c;
};
+
+
#endif
*
* 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 <net-snmp/net-snmp-config.h>
+#include "lib/unaligned.h"
+#include "subagent.h"
-#ifdef HAVE_SIGNAL
-#include <signal.h>
-#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 <sys/stat.h>
-#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 <fcntl.h>
-#endif
+static int
+put_str(byte *buf, const char *str, uint *size)
+{
+ uint len = strlen(str);
+ uint pkt_len = BIRD_ALIGN(len, 4);
-#include <net-snmp/net-snmp-includes.h>
-#include <net-snmp/agent/net-snmp-agent-includes.h>
+ if (len > MAX_STR)
+ return -1;
-extern int netsnmp_running;
+ put_u32(buf, len);
+
+ memcpy(buf + 4, str, len);
-int
-snmp_start_subagent(void (*hook)(void))
+ // make the value 32-bit aligned
+ for (uint i = 0; i < pkt_len - len; i++)
+ buf[len + i] = 0x00; // PADDING
+
+ *size += (4 + pkt_len);
+
+ 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)
{
- /* subagent mode */
- netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_AGENT_ROLE, 1);
+ 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);
- /* forking netsnmp mechanism * /
- if (netsnmp_daemonize(1, snmp_stderrolog_status()) != 0)
- return 0; // start FAILED
- */
+ /* +4B for reason */
+ if (size > AGENTX_HEADER_SIZE + 4)
+ {
+ PASTE_HEADER(buf, AGENTX_CLOSE_PDU, AGENTX_NETWORK_BYTE_ORDER, size);
- /* for Win32 only */
- SOCK_STARTUP;
+ 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);
- /* init library */
- init_agent("bird");
+ ADVANCE(pkt, size, sizeof(struct agentx_header));
+
+ paste_fbyte(pkt, reason, &size);
+ ADVANCE(pkt, size, 4);
- if (hook)
- hook();
+ /* 4 - reason size */
+ header_update_len(sk->tbuf, 4);
- /* used for loading config 'bird-snmp.conf' */
- init_snmp("bird-snmp");
+ 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));
- return 1; // SUCCESS
}
void
-snmp_agent_reconfigure(void)
+snmp_start_subagent(struct snmp_proto *p)
{
- free_config();
- read_configs();
+ 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_shutdown_subagent(void (*hook)(void))
+snmp_stop_subagent(struct snmp_proto *p)
{
- /* at shutdown time */
- snmp_shutdown("bird");
+ sock *sk = p->sock;
+
+ close_pdu(p, AGENTX_CLOSE_SHUTDOWN);
+
+ sk->rx_hook = snmp_stop_ack;
+}
- /* shutdown hook */
- if (hook)
- hook();
+static uint
+oid_size(struct oid *o)
+{
+ return 4 + o->subid.len;
+}
- /* shutdown the agent library */
- shutdown_agent();
+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;
- /* for Win32 only */
- SOCK_CLEANUP;
+ parse_pkt(p, pkt, size);
+ /*
+ while (end >= ptk + AGENTX_HEADER_SIZE)
+ {
+ parse_header(p);
+ parse_pkt(p, );
+ }
+ */
+ return 0;
+ // 1 means all done
}
-void
-snmp_stop_subagent(void (*hook)(void))
+void
+ping_pdu(struct snmp_proto *p)
{
- /* at shutdown time */
- snmp_shutdown("bird");
+ /* 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);
- /* deinitialize MIB code */
- if (hook)
- hook();
+ 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);
- /* shutdown the agent library */
- shutdown_agent();
+ 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)
+{
+
+}
+*/
+
+#undef SNMP_ERR_SHIFT
#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