]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
TMP: work on Get-PDU and GetNext-PDU
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 20 Sep 2022 12:28:57 +0000 (14:28 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 20 Sep 2022 12:28:57 +0000 (14:28 +0200)
proto/snmp/bgp_mib.c
proto/snmp/bgp_mib.h
proto/snmp/config.Y
proto/snmp/snmp.c
proto/snmp/snmp.h
proto/snmp/subagent.c
proto/snmp/subagent.h

index 6f80acdc056ccf1dd81f620c4c228b396206d991..f3d2de5b361c6e953ee5cfc3aaf9c9cbacdf15e0 100644 (file)
  *      using mib2c.create-dataset.conf
  */
 
-
+/*
 #include <net-snmp/net-snmp-config.h>
 #include <net-snmp/net-snmp-includes.h>
 #include <net-snmp/varbind_api.h>
 #include <net-snmp/agent/net-snmp-agent-includes.h>
+*/
 
 // fix conflicts
 #undef PACKAGE_BUGREPORT
 #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)
-{
-
-  /* perform anything here that you need to do.  The requests have
-     already been processed by the master table_dataset handler, but
-     this gives you chance to act on the request in some other way
-     if need be. */
-
-  log(L_INFO " bgpPeerTable_handler()");
-  // walk list of netsnmp_data_list
-  for (netsnmp_data_list *l = reqinfo->agent_data;
-       l; l->next)
-  {
-    log(L_INFO " name: %s,  poniter %p", l->name, l->data);
-  }
-
-  char buff[64];
-  // walk list of netsnmp_variable_list VB
-  for (netsnmp_variable_list *var = requests->requestvb;
-       var; var->next_variable)
-  {
-    snprint_value(buff, 64, var->name, var->name_length, var);
-    log(L_INFO "variable %s", buff);
-    memset((void *) buff, 0, 64);
-  }
-
-  return SNMP_ERR_NOERROR;
-}
-
 void
-snmp_init_bgp_table(void)
-{
-  const oid bgpPeerTable_oid[] = {1,3,6,1,2,1,15,3};
-  netsnmp_table_data_set *table_set;
-
-  /* create the table structure itself */
-  table_set = netsnmp_create_table_data_set("bgpPeerTable");
-
-  log(L_INFO "adding indexes to SNMP table bgpPeerTable");
-
-  netsnmp_table_set_add_indexes(
-    table_set,
-    ASN_IPADDRESS,  /* index: bgpPeerRemoteAddr */
-    0
-  );
-
-  log(L_INFO "adding column types to SNMP table bgpPeerTable");
-  netsnmp_table_set_multi_add_default_row(
-    table_set,
-    SNMP_BGP_IDENTIFIER, ASN_IPADDRESS, 0, NULL, 0,
-    SNMP_BGP_STATE, ASN_INTEGER, 0, NULL, 0,
-    /* change to ASN_INTEGER, 1, NULL, 0, below to allow write */
-    SNMP_BGP_ADMIN_STATUS, ASN_INTEGER, 0, NULL, 0,
-    SNMP_BGP_VERSION, ASN_INTEGER, 0, NULL, 0,
-    SNMP_BGP_LOCAL_ADDR, ASN_IPADDRESS, 0, NULL, 0,
-    SNMP_BGP_LOCAL_PORT, ASN_INTEGER, 0, NULL, 0,
-    SNMP_BGP_REMOTE_ADDR, ASN_IPADDRESS, 0, NULL, 0,
-    SNMP_BGP_REMOTE_PORT, ASN_INTEGER, 0, NULL, 0,
-    SNMP_BGP_REMOTE_AS, ASN_INTEGER, 0, NULL, 0,
-    SNMP_BGP_RX_UPDATES, ASN_COUNTER, 0, NULL, 0,
-    SNMP_BGP_TX_UPDATES, ASN_COUNTER, 0, NULL, 0,
-    SNMP_BGP_RX_MESSAGES, ASN_COUNTER, 0, NULL, 0,
-    SNMP_BGP_TX_MESSAGES, ASN_COUNTER, 0, NULL, 0,
-    SNMP_BGP_LAST_ERROR, ASN_OCTET_STR, 0, NULL, 0,
-    SNMP_BGP_FSM_TRANSITIONS, ASN_COUNTER, 0, NULL, 0,
-    SNMP_BGP_FSM_ESTABLISHED_TIME, ASN_GAUGE, 0, NULL, 0,
-    SNMP_BGP_RETRY_INTERVAL, ASN_INTEGER, 1, NULL, 0,
-    SNMP_BGP_HOLD_TIME, ASN_INTEGER, 0, NULL, 0,
-    SNMP_BGP_KEEPALIVE, ASN_INTEGER, 0, NULL, 0,
-    SNMP_BGP_HOLD_TIME_CONFIGURED, ASN_INTEGER, 1, NULL, 0,
-    SNMP_BGP_KEEPALIVE_CONFIGURED, ASN_INTEGER, 1, NULL, 0,
-    SNMP_BGP_ORIGINATION_INTERVAL, ASN_INTEGER, 1, NULL, 0,
-    SNMP_BGP_MIN_ROUTE_ADVERTISEMENT, ASN_INTEGER, 1, NULL, 0,
-    SNMP_BGP_MIN_UPDATE_ELAPSED_TIME, ASN_GAUGE, 0, NULL, 0,
-    0
-  );
+snmp_bgp_register()
+{}
 
-  /* registering the table with the master agent */
-  /* note: if you don't need a subhandler to deal with any aspects
-     of the request, change bgpPeerTable_handler to "NULL" */
-  netsnmp_register_table_data_set(
-    netsnmp_create_handler_registration(
-      "bgpPeerTable", bgpPeerTable_handler,
-      bgpPeerTable_oid,
-      OID_LENGTH(bgpPeerTable_oid),
-      HANDLER_CAN_RONLY
-      // HANDLER_CAN_RWRITE
-    ),
-    table_set, NULL
-  );
+static inline int
+is_bgp_peer_entry(struct oid *o)
+{
+  if (o->ids[2] == BGP4_PEER_ENTRY &&
+      o->ids[3] > 0 &&
+      /* do not include bgpPeerInUpdatesElapsedTime
+         and bgpPeerFsmEstablishedTime */
+      o->ids[3] < SNMP_BGP_IN_UPDATE_ELAPSED_TIME &&
+      o->ids[3] != SNMP_BGP_FSM_ESTABLISHED_TIME)
+    return 1;
+  else
+    return 0;
 }
 
-void
-snmp_del_bgp_table(void)
+int
+snmp_bgp_is_supported(struct oid *o)
 {
-  // XXX really needed ?
-  const oid bgpPeerTable_oid[] = {1,3,6,1,2,1,15,3};
-
-  remove_tree_entry(bgpPeerTable_oid, OID_LENGTH(bgpPeerTable_oid));
+  if (o->prefix == 2 && o->ids[0] == 1)
+  {
+    if (o->ids[1] == BGP4_MIB_VERSION ||
+        o->ids == BGP4_MIB_LOCAL_AS)
+      return 1;
+    else if (o->ids[1] == BGP4_PEER_TABLE)
+      return is_bgp_peer_entry(o)
+    else
+      return 0;
+  }
+  else
+    return 0;
 }
+
index dd34fa18676f6490f5b6c637650b118552536190..6c538b63936c3ac42ae3eb8fbf153e77a42be327 100644 (file)
@@ -3,33 +3,41 @@
 
 /* peers attributes */
 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 */
+  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_IN_UPDATE_ELAPSED_TIME   = 24,   /* UNSUPPORTED */
 } PACKED;
 
-void snmp_init_bgp_table(void);
-void snmp_del_bgp_table(void);
+//void snmp_init_bgp_table(void);
+//void snmp_del_bgp_table(void);
+
+void snmp_bgp_register(void);
+int snmp_bgp_is_supported(struct oid *o);
+
+#define BGP4_MIB_VERSION  1
+#define BGP4_MIB_LOCAL_AS 2
+#define BGP4_PEER_TABLE          3
+#define BGP4_PEER_ENTRY            1
 
 #endif
index d85dbf15c6ab5d419313107cc4d128d094c8198f..33f653427cd77d096221afa4f3853bc236261d6f 100644 (file)
@@ -14,11 +14,10 @@ CF_HDR
 CF_DEFINES
 
 #define SNMP_CFG ((struct snmp_config *) this_proto)
-#define SNMP_CC ((struct snmp_channel_config *) this_channel)
 
 CF_DECLS
 
-CF_KEYWORDS(SNMP, TABLE, PROTOCOL, BPG)
+CF_KEYWORDS(SNMP, PROTOCOL, BPG, LOCAL, AS, REMOTE, PORT)
 
 CF_GRAMMAR
 
@@ -33,19 +32,23 @@ snmp_proto:
  | 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))
+ | snmp_proto REMOTE ipa ';' { SNMP_CFG->remote_ip = $3; if(ipa_zero($3))
 cf_error("Invalid remote ip address"); }
+ | snmp_proto LOCAL AS expr ';' { if ($4<1 || $4>65535) cf_error("invalid local as");
+  SNMP_CFG->local_as = $4; }
  ;
 
 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->local_as = 0;
 
   SNMP_CFG->timeout = 15;
 }
@@ -53,7 +56,6 @@ snmp_proto_start: proto_start SNMP
 proto_name ;
 
 
-
 snmp_bgp_bond: BGP symbol
 {
   struct snmp_bond *this_bond = cfg_alloc(sizeof(struct snmp_bond));
index c00dd94febe21b8e4c450376017ed6d3f4689f73..587921a84a859ee8840a2bff5ff4429d2b3cd248 100644 (file)
@@ -14,6 +14,7 @@
 #include "nest/cli.h"
 #include "nest/locks.h"
 #include "lib/socket.h"
+#include "lib/lists.h"
 
 #include "snmp.h"
 #include "subagent.h"
@@ -21,6 +22,7 @@
 static void snmp_connected(sock *sk);
 static void snmp_sock_err(sock *sk, int err);
 static void snmp_ping_timer(struct timer *tm);
+static void snmp_retry_timer(struct timer *tm);
 
 static struct proto *
 snmp_init(struct proto_config *CF)
@@ -98,7 +100,14 @@ static void
 snmp_sock_err(sock *sk UNUSED, int err UNUSED)
 {
   log(L_INFO "snmp_sock_err() %s - err no: %d",  strerror(err), err);
-  die("socket error");
+
+  struct snmp_proto *p = sk->data;
+
+  p->state = SNMP_ERR;
+  if (p->p.proto_state == PS_UP)
+    proto_notify_state(&p->p, PS_START);
+
+  tm_set(p->retry_timer, current_time() + 5 S);
 }
 
 static int
@@ -106,15 +115,17 @@ 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;
+  struct snmp_config *cf = (struct snmp_config *) P->cf;
 
   p->ping_timer = tm_new_init(p->p.pool, snmp_ping_timer, p, 0, 0);
-  tm_set(p->ping_timer, current_time() + (2 S_));
+  tm_set(p->ping_timer, current_time() + 2 S);
+
+  p->retry_timer = tm_new_init(p->p.pool, snmp_retry_timer, p, 0, 0);
 
   /* starting agentX communicaiton channel */
   log(L_INFO "preparing lock");
   struct object_lock *lock;
-  lock = p->lock = olock_new(P->pool); 
+  lock = p->lock = olock_new(p->p.pool);
 
   lock->type = OBJLOCK_TCP;
   lock->hook = snmp_start_locked;
@@ -126,26 +137,29 @@ 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);
+  init_list(&p->bgp_entries);
 
   /* create copy of bonds to bgp */
-  HASH_INIT(p->peer_hash, p->p.pool, 10);
+  HASH_INIT(p->bgp_hash, p->p.pool, 10);
 
-  struct snmp_bond *b;
+  struct snmp_bond *b, *b2;
   WALK_LIST(b, cf->bgp_entries)
   {
-    struct bgp_config *bc = b->proto;
+    struct bgp_config *bc = (struct bgp_config *) b->proto;
     if (bc && !ipa_zero(bc->remote_ip))
     {
-      struct snmp_bgp_peer_entry pe = {
-       .bond = b;
-       .peer_ip = bc->remote_ip;
-       .next = NULL;
-      }; 
+      struct snmp_bgp_peer *peer =
+       mb_allocz(p->p.pool, sizeof(struct snmp_bgp_peer));
+      peer->bond = b;
+      peer->peer_ip = bc->remote_ip;
 
-      HASH_INSERT(p->peer_hash, SNMP_HASH, pe)
+      HASH_INSERT(p->bgp_hash, SNMP_HASH, peer);
        
-      add_tail(&p->bgp_entries, b);
+      b2 = mb_allocz(p->p.pool, sizeof(struct snmp_bond));
+      b2->proto = b->proto;
+      b2->type = b->type;
+      add_tail(&p->bgp_entries, NODE b2);
+      mb_free(peer);
     }
   }
    
@@ -162,6 +176,7 @@ snmp_reconfigure(struct proto *P, struct proto_config *CF)
   p->remote_ip = cf->remote_ip;
   p->local_port = cf->local_port;
   p->remote_port = cf->remote_port;
+  p->local_as = cf->local_as;
   p->timeout = 15;
 
   /* TODO walk all bind protocols and find their (new) IP
@@ -192,7 +207,7 @@ static void snmp_show_proto_info(struct proto *P)
     cli_msg(-1006, "    admin status: %s", (p->disabled) ? "start" :
              "stop");
     // version ?
-    cli_msg(-1006, "    version: ??, likely 4");
+    cli_msg(-1006, "    version: 4");
     cli_msg(-1006, "    local ip: %u", bcf->local_ip);
     cli_msg(-1006, "    remote ip: %u", bcf->remote_ip);
     cli_msg(-1006, "    local port: %u", bcf->local_port);
@@ -237,21 +252,59 @@ bp->stats.fsm_established_transitions);
   }
 }
 
+static void
+snmp_postconfig(struct proto_config *CF)
+{
+  if (((struct snmp_config *) CF)->local_as == 0)
+    cf_error("local as not specified");
+}
+
 static void
 snmp_ping_timer(struct timer *tm)
 {
   log(L_INFO "snmp_ping_timer() ");
   struct snmp_proto *p = tm->data;  
 
-  snmp_ping(p);
+  if (p->state == SNMP_CONN)
+  {
+    snmp_ping(p);
+  }
 
   //tm_set(tm, current_time() + (7 S_));
 }
 
+static void
+snmp_retry_timer(struct timer *tm)
+{
+  log(L_INFO "snmp_retry_timer()");
+
+  struct snmp_proto *p = tm->data;
+
+  /* starting agentX communicaiton channel */
+  log(L_INFO "preparing lock");
+  struct object_lock *lock;
+  lock = p->lock = olock_new(p->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);
+}
+
 static int
 snmp_shutdown(struct proto *P)
 {
   struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
+  p->state = SNMP_INIT;
+
+  tm_stop(p->ping_timer);
+  tm_stop(p->retry_timer);
+
   snmp_stop_subagent(p);
   return PS_DOWN;
 }
@@ -262,6 +315,7 @@ struct protocol proto_snmp = {
   .channel_mask =      NB_ANY,
   .proto_size =                sizeof(struct snmp_proto),
   .config_size =       sizeof(struct snmp_config),
+  .postconfig =                snmp_postconfig,
   .init =              snmp_init,
   .start =             snmp_start,
   .reconfigure =       snmp_reconfigure,
index bb38002cdadd03d12a1111da4b51ff32eef17496..baf643c30831ee710dd19a4c78a655c5e6b340b4 100644 (file)
@@ -37,8 +37,8 @@
 
 
 /* hash table macros */
-#define SNMP_HASH_KEY(n)  n->peer_ip;
-#define SNMP_HASH_NEXT(n) n->next;
+#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)
 
@@ -54,16 +54,17 @@ struct snmp_config {
   ip_addr remote_ip;
   u16 local_port;
   u16 remote_port;
+  u32 local_as;
   u8 timeout;
   //struct iface *iface;
   list bgp_entries;
 };
 
-struct snmp_bgp_peer_entry {
+struct snmp_bgp_peer {
   struct snmp_bond *bond;
   ip_addr peer_ip;
-  struct snmp_bgp_peer_entry *next;
-}
+  struct snmp_bgp_peer *next;
+};
 
 struct snmp_proto {
   struct proto p;
@@ -73,6 +74,7 @@ struct snmp_proto {
   ip_addr remote_ip;
   u16 local_port;
   u16 remote_port;
+  u32 local_as;
 
   sock *sock;
   u8 timeout;
@@ -83,10 +85,11 @@ struct snmp_proto {
 
   //struct iface *iface;
   // map goes here
-  HASH(struct snmp_bgp_peer_entry) bgp_hash;
+  HASH(struct snmp_bgp_peer) bgp_hash;
   struct tbf rl_gen;
 
   timer *ping_timer;
+  timer *retry_timer;
   u8 state;
 
   list bgp_entries;
index 02638848bd7224a7d9a98476c28f91982de8943c..ca84e3f8362e3272c605f81465ac8820ba1fe8dd 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "lib/unaligned.h"
 #include "subagent.h"
+#include "bgp_mib.h"
 
 /* =============================================================
  *  Problems
@@ -18,6 +19,7 @@
  *    change of remote ip -> no notification, no update 
  *    same ip, different ports
  *    distinct VRF (two interfaces with overlapping private addrs)
+ *    posible link-local addresses in LOCAL_IP
  *
  */
 
@@ -28,8 +30,13 @@ 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 int parse_gets_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);
+static void response_err_ind(byte *buf, uint err, uint ind);
+static struct oid *bgp_search(struct oid *o_start, struct oid *o_end, struct oid *o_curr);
+static struct oid *prefixize(struct snmp_proto *p, struct oid *o, int byte_ord);
+static inline byte *find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid, int byte_ord);
 
 static const char * const snmp_errs[] = {
   #define SNMP_ERR_SHIFT 256
@@ -341,9 +348,16 @@ parse_pkt(struct snmp_proto *p, byte *buf, uint size)
     case AGENTX_RESPONSE_PDU:
       return parse_response(p, buf, size);
 
+    /*
     case AGENTX_GET_PDU:
       refresh_ids(p, h);
       return parse_get_pdu(p, buf, size);
+    */
+
+    case AGENTX_GET_PDU:
+    case AGENTX_GET_NEXT_PDU:
+      refresh_ids(p, h);
+      return parse_gets_pdu(p, buf, size);
 
     /* should not happen */
     default:
@@ -378,7 +392,7 @@ SNMP_ERR_SHIFT]);
 }
 
 static void
-do_response(struct snmp_proto *p, byte *buf, uint size)
+do_response(struct snmp_proto *p, byte *buf, uint size UNUSED)
 {
   struct agentx_response *r = (void *) buf;
   struct agentx_header *h = &r->h;
@@ -401,34 +415,47 @@ do_response(struct snmp_proto *p, byte *buf, uint size)
       p->transaction_id++;
 
       log(L_INFO "sending register-pdu");
+
+      // register whole BGP4-MIB
+      u32 arr_bgp[] = {1, 15, 1};
+      struct oid *o = mb_allocz(p->p.pool, 4 * 4);
+      put_u8(&o->n_subid, 2);
+      put_u8(&o->prefix, 2);
+
+      memcpy(o->ids, arr_bgp, 2 * 4);
+
+      snmp_register(p, o, 0, 1);
+
+      put_u8(&o->n_subid, 3);
+      STORE(o->ids[2], arr_bgp[2]);
+      snmp_register(p, o, 0, 1);
+
+
+      STORE(o->ids[2], 2);
+      snmp_register(p, o, 0, 1);
+
+      mb_free(o);
+
       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);
 
+      put_u8(&o2->n_subid, 9);
       memcpy(o2->ids, arr_with_prefix, 5 * 4);
       u32 remote_addr[] = {10, 0, 0, 0};
       memcpy(o2->ids + 5, remote_addr, 4 * 4);
+      STORE(o2->prefix, 2);
 
       // 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);
+      mb_free(o2);
 
       p->state = SNMP_REGISTR;
       //proto_notify_state(&p->p, PS_UP);
       break;
 
     case SNMP_REGISTR:
+      p->state = SNMP_CONN;
       break;
 
     case SNMP_CONN:
@@ -452,68 +479,80 @@ parse_get_pdu(struct snmp_proto *p, byte *buf, uint 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);
+
+  int byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER;
+
   byte *pkt = buf;
   uint pkt_size = LOAD(h->payload, byte_ord);
-  log(L_INFO "packet size is %u", pkt_size);
+  log(L_INFO "RX packet size is %u", pkt_size);
 
-  uint clen;
+  uint clen;         /* context len */
   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);
+  res_pkt = prepare_response(p, res, rsize);
   log(L_INFO "response header created: %p (%u)", res_pkt, res_pkt - res);
+  /* parsing one search range */
+  uint ind = 1;
+  int err = 0;
+               /* parsed  */
+  while (!err && pkt - buf < pkt_size)
+  {
+    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);
 
-  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);
+    log(L_INFO "sizes o_start %lu o_end %lu", oid_size(o_start),
+       oid_size(o_end));
 
-  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 "o_subid: %u o_prefix %u o_include %u ---",
+       o_start->n_subid, o_start->prefix, o_start->include);
 
-  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");
+    /* currently unsupported non-default context */
+    res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
+
+    /*
+    struct agentx_varbind *vb_start;
+    vb_start = (void *) res_pkt;
+
+    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);
+    */
+    ind++;
+  }
 
   struct agentx_header *rh = (void *) res;
   SNMP_UPDATE(rh, pkt_len(res, res_pkt));
+
+  if (err)
+    response_err_ind(res, err, ind);
+
   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); 
+    res_pkt - res + 4);
    
   int ret = sk_send(sk, res_pkt - res);
   log(L_INFO "message sent");
 
-  if (res == 0)
+  if (ret == 0)
     log(L_INFO "sleep");
   else if (ret < 0)
     log(L_INFO "err no: %d", ret);
@@ -523,6 +562,126 @@ parse_get_pdu(struct snmp_proto *p, byte *buf, uint size)
   return 1;
 }
 
+
+/* req is request */
+static int
+parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
+{
+  log(L_INFO "parse_gets_pdu");
+
+  sock *sk = p->sock;
+  byte *res_pkt, *res = sk->tbuf;
+  uint rsize = sk->tbsize;
+
+  if (size < AGENTX_HEADER_SIZE)
+    return 0;
+
+  struct agentx_header *h = (void *) req;
+  ADVANCE(req, size, AGENTX_HEADER_SIZE);
+  log(L_INFO "advancing %p cause header", req);
+
+  byte *pkt = req;
+
+  int byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER;
+  uint pkt_size = LOAD(h->payload, byte_ord);
+
+  uint clen;
+  char *context;
+  SNMP_LOAD_CONTEXT(p, h, req, context, clen);
+
+  res_pkt = prepare_response(p, res, rsize);
+  uint ind = 1;
+  int err = 0;
+  while (!err && pkt - req < pkt_size)
+  {
+    struct oid *o_start, *o_end;
+    o_start = (struct oid *) pkt;
+    pkt += oid_size(o_start);
+    o_end = (struct oid *) pkt;
+    pkt += oid_size(o_end);
+
+    // TODO normalize OID to prefix form
+
+    /* advertised size of oid is greater then size of message */
+    if (oid_size(o_start) > size || oid_size(o_end) > size)
+    {
+      err = -1;  /* parse error too big n_subid */
+      continue;
+    }
+
+    switch (h->type)
+    {
+      case AGENTX_GET_PDU:
+       res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
+       break;
+
+      case AGENTX_GET_NEXT_PDU:
+       o_start = bgp_search(o_start, o_end, NULL);
+       if (o_start)
+         res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
+       else
+       {
+         err = -2;
+         continue;
+       }
+       break;
+
+      case AGENTX_GET_BULK_PDU:
+      {
+       struct oid  *o_curr = NULL;
+       /* TODO add res packet size limiting logic */
+       while ((o_curr = bgp_search(o_start, o_end, o_curr)) != NULL)
+       {
+         res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
+       }
+
+       /* no item found */
+       if (res_pkt == res + sizeof(struct agentx_response))
+       {
+         err = -2;
+         continue;
+       }
+
+       break;
+      }
+    }
+
+    ind++;
+  }
+
+  switch (err)
+  {
+    case 0:
+      response_err_ind(req, AGENTX_RES_NO_ERROR, 0);
+      err = 1;
+      break;
+    case -1:
+      response_err_ind(req, AGENTX_RES_PARSE_ERROR, ind);
+      break;
+
+    /* no item found - could it happen? */
+    case -2:
+      response_err_ind(req, AGENTX_RES_GEN_ERROR, ind);
+      break;
+  }
+
+  struct agentx_header *rh = (void *) res;
+  SNMP_UPDATE(rh, pkt_len(res, res_pkt));
+
+  int ret = sk_send(sk, res_pkt - res);
+  log(L_INFO "message sent");
+
+  if (ret == 0)
+    log(L_INFO "sleep");
+  else if (ret < 0)
+    log(L_INFO "err no: %d", ret);
+  else
+    log("OK ! !!");
+
+  return err;
+}
+
+
 static void
 header_update_len(byte *buf, u32 len)
 {
@@ -552,9 +711,12 @@ snmp_stop_subagent(struct snmp_proto *p)
   log(L_INFO "snmp_stop_subagent()");
   sock *sk = p->sock;
 
-  close_pdu(p, AGENTX_CLOSE_SHUTDOWN);
+  if (p->state == SNMP_CONN)
+  {
+    close_pdu(p, AGENTX_CLOSE_SHUTDOWN);
 
-  sk->rx_hook = snmp_stop_ack;
+    sk->rx_hook = snmp_stop_ack;
+  }
 }
 
 static inline uint
@@ -652,12 +814,53 @@ snmp_agent_reconfigure(void)
 }
 */
 
+static int
+compare(struct oid *left, struct oid *right)
+{
+  if (left->prefix < right->prefix)
+    return -1;
+
+  else if (left->prefix > right->prefix)
+    return 1;
+
+  for (int i = 0; i < MIN(left->n_subid, right->n_subid); i++)
+  {
+    if (left->ids[i] < right->ids[i])
+      return -1;
+    else if (left->ids[i] > right->ids[i])
+      return 1;
+  }
+  return 0;
+}
+
+static inline int
+is_bgp4_mib_prefix(struct oid *o)
+{
+  if (o->prefix == 2 && o->ids[0] == 15)
+    return 1; 
+  else
+    return 0;
+}
+
+static struct oid *
+bgp_search(struct oid *o_start, struct oid *e_end, struct oid *o_curr)
+{
+  if (o_start->include);
+    // if valid o_start
+
+  // search o_start.0 (resp. o_start.1)
+  return o_start;
+}
+
 static byte *
-find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *buf,  uint size, uint contid)
+find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt,  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;
+  struct bgp_conn *b_in = &bp->incoming_conn;
+  struct bgp_conn *b_out = &bp->outgoing_conn;
+
+  struct bgp_stats *b_stats = &bp->stats;
+  const struct bgp_config *b_conf = bp->cf;
 
   uint b_state;
 
@@ -672,122 +875,216 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *buf,  uint size, uint co
   else
     b_state = MAX(b_in->state, b_out->state);
   
-  struct agentx_varbind *vb = (void *) buf;
-  
+  struct agentx_varbind *vb = (void *) pkt;
+  pkt += vb_size(vb);
   
   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));
+      if (b_state == BS_OPENCONFIRM || b_state == BS_ESTABLISHED)
+      {
+       STORE_PTR(pkt, ipa_to_u32(bp->remote_ip));
        BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+      }
       else
-       STORE_PTR(pkt, ip4_to_u32(IPA_NONE));
+      {
+       STORE_PTR(pkt, ipa_to_u32(IPA_NONE));
        BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+      }
+      break;
       
     case SNMP_BGP_STATE: 
       STORE_PTR(pkt, b_state);
       BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
 
     case SNMP_BGP_ADMIN_STATUS:
-      STORE_PTR(pkt, (bp->disabled) ? AGENTX_ADMIN_STOP : AGENTX_ADMIN_START);
+      if (((struct proto *) bp)->disabled)
+       STORE_PTR(pkt, AGENTX_ADMIN_STOP);
+      else
+       STORE_PTR(pkt, AGENTX_ADMIN_START);
       BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
 
     case SNMP_BGP_VERSION:
-      STORE(pkt, BGP4_VERSIONS);
-      STORE
+      if (b_state == BS_OPENCONFIRM || b_state == BS_ESTABLISHED)
+       STORE_PTR(pkt, 4);
+      else
+       STORE_PTR(pkt, 0);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
     case SNMP_BGP_LOCAL_ADDR:
+      // TODO XXX bp->link_addr & zero local_ip
+      STORE_PTR(pkt, ipa_to_u32(bp->local_ip));
+      BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+      break;
+
     case SNMP_BGP_LOCAL_PORT:
+      STORE_PTR(pkt, b_conf->local_port);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
     case SNMP_BGP_REMOTE_ADDR:
+      STORE_PTR(pkt, ipa_to_u32(bp->remote_ip));
+      BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+      break;
+
     case SNMP_BGP_REMOTE_PORT:
+      STORE_PTR(pkt, b_conf->remote_port);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
     case SNMP_BGP_REMOTE_AS:
+      STORE_PTR(pkt, bp->remote_as);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
+    /* IN UPDATES */
     case SNMP_BGP_RX_UPDATES:
+      STORE_PTR(pkt, b_stats->rx_updates);
+      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      break;
+
+    /* OUT UPDATES */
     case SNMP_BGP_TX_UPDATES:
+      STORE_PTR(pkt, b_stats->tx_updates);
+      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      break;
+
+    /* IN MESSAGES */
     case SNMP_BGP_RX_MESSAGES:
+      STORE_PTR(pkt, b_stats->rx_messages);
+      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      break;
+
+    /* OUT MESSAGES */
     case SNMP_BGP_TX_MESSAGES:
+      STORE_PTR(pkt, b_stats->tx_messages);
+      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      break;
+
+    case SNMP_BGP_LAST_ERROR:
+      STORE_PTR(pkt, 2);
+      pkt += 4;
+      /* force network order */
+      put_u32(pkt,
+       (bp->last_error_code << 8 | bp->last_error_code << 48) & 0xFFFF0000);
+      /* real size is 8 but we already shifted the pkt by 4 */
+      BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
+      break;
 
     case SNMP_BGP_FSM_TRANSITIONS:
+      STORE_PTR(pkt, b_stats->fsm_established_transitions);
+      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      break;
 
     case SNMP_BGP_RETRY_INTERVAL:
+      STORE_PTR(pkt, b_conf->connect_retry_time);
+      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      break;
+
     case SNMP_BGP_HOLD_TIME:
+      if (b_conn && b_conf->hold_time)
+       STORE_PTR(pkt, b_conn->hold_time);
+      else
+       STORE_PTR(pkt, 0);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
     case SNMP_BGP_KEEPALIVE:
+      if (b_conn && b_conf->keepalive_time)
+       STORE_PTR(pkt, b_conn->keepalive_time);
+      else
+       STORE_PTR(pkt, 0);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
     case SNMP_BGP_HOLD_TIME_CONFIGURED:
+      STORE_PTR(pkt, b_conf->hold_time);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
     case SNMP_BGP_KEEPALIVE_CONFIGURED:
+      STORE_PTR(pkt, b_conf->keepalive_time);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
 
     /* UNSUPPORTED */
-    case SNMP_BGP_LAST_ERROR:
-
-    case SNMP_BGP_FSM_ESTABLISHED_TIME:
-
+    /* TODO XXX forbiden value 0 */
     case SNMP_BGP_ORIGINATION_INTERVAL:
     case SNMP_BGP_MIN_ROUTE_ADVERTISEMENT:
-    case SNMP_BGP_MIN_UPDATE_ELAPSED_TIME:
-    defualt:
+      STORE_PTR(pkt, 0);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
+    case SNMP_BGP_FSM_ESTABLISHED_TIME:
+    case SNMP_BGP_IN_UPDATE_ELAPSED_TIME:
       vb->type = AGENTX_NO_SUCH_OBJECT;
       /* pkt += 0;  no data */
       break;
+
+    /* no default */
   }
+
+  return pkt;
 }
 
 /* contid - context identification number */
 static byte *
-find_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
+snmp_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; 
+      STORE_PTR(pkt, 1);   // string len
+      pkt += 4;
+      STORE_PTR(pkt, BGP4_VERSIONS);
+      /* real size is 8 but we already shifted the pkt by 4 */
+      BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
       break;
       
     case BGP4_MIB_LOCAL_AS:
-      vb->type = AGENTX_INTEGER;
       // XXX local as to use
-      STORE(pkt, p->local_as);
-      pkt += 4;
+      STORE_PTR(pkt, p->local_as);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
       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] != 
+      if (o->n_subid < 9 || o->ids[3] != BGP4_PEER_ENTRY
          || o->ids[4] == 0 || o->ids[4] > 24)
       {
        vb->type = AGENTX_NO_SUCH_OBJECT;
-       return buff + vb_size(vb);
+       return buf + 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 snmp_bgp_peer *pe =
+        HASH_FIND(p->bgp_hash, SNMP_HASH, addr);
 
       struct bgp_proto *bp = NULL;
       if (pe && pe->bond->proto->proto && 
-         ipa_equal(pe->bond->proto->proto->remote_ip, addr))
+         ipa_equal(addr,
+           ((struct bgp_proto *) pe->bond->proto->proto)->remote_ip))
       {
-       bp = pe->bond->proto->proto;    
+       bp = (void *) pe->bond->proto->proto;
       }
+
+      /* IF WE CONSIDER CHANGES OF REMOTE IP
       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; 
+             ipa_equal(((struct bgp_proto *) b->proto->proto)->remote_ip, addr))
+           bp = (struct bgp_proto *) b->proto->proto;
       }
+      */
 
       if (!bp)
       {
@@ -815,15 +1112,23 @@ find_ospf_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size)
   return NULL;
 }
 
+static byte *
+unsupported_oid(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
+{
+  struct agentx_varbind *vb = (void *) buf;
+  vb->type = AGENTX_NO_SUCH_OBJECT;
+  return buf + vb_size(vb);
+}
+
 static inline byte *
-find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size)
+find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
 {
-  struct agetnx_varbind *vb = (void *) buf;
+  struct agentx_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))
+                       /* SNMPv2   mgmt                     mib-2 */
+  if (o->n_subid < 2 || (o->prefix != 2 && o->ids[0] != 1))
   {
     vb->type = AGENTX_NO_SUCH_OBJECT;
     return buf + vb_size(vb);
@@ -832,29 +1137,26 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size)
   switch (o->ids[1])
   {
     case SNMP_BGP4_MIB:
-      return find_bgp_record(p, o, buf, size);
+      if (snmp_bgp_is_supported(o))
+       return snmp_bgp_record(p, o, buf, size, contid);
+      else
+       return unsupported_oid(p, o, buf, size, contid);
 
     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;
+      return unsupported_oid(p, o, buf, size, contid);
+      //return find_ospf_record(p, o, buf, size);
 
     default:
+      return unsupported_oid(p, o, buf, size, contid);
       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)
+prefixize_in_place(struct oid *o, int byte_ord)
 {
   const u32 prefix[] = {1, 3, 6, 1};
 
@@ -876,25 +1178,51 @@ prefixize(struct oid *o, int byte_ord)
   return 1;
 }
 
+static struct oid *
+prefixize(struct snmp_proto *p, struct oid *o, int byte_ord)
+{
+  const u32 prefix[] = {1, 3, 6, 1};
+
+  if (o->n_subid < 5)
+    return NULL;
+
+  for (int i = 0; i < 4; i++)
+    if (LOAD(o->ids[i], byte_ord) != prefix[i])
+      return NULL;
+
+  struct oid *new = mb_alloc(p->p.pool, sizeof(struct oid) + MAX((o->n_subid - 5) * 4, 0));
+
+  memcpy(new, o, sizeof(struct oid));
+  new->n_subid = o->n_subid - 5;
+
+  if (o->ids[4] < 256)
+    new->prefix = o->ids[4];
+  else return NULL;
+
+  memcpy(&new->ids, &o->ids[5], new->n_subid * 4);
+  return new;
+}
+
 static inline byte *
-find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, int byte_ord)
+find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid, int byte_ord)
 {
-  if (!o->prefix && prefixize(o, byte_ord))
-    find_prefixed(p, o, buf, size);
+  struct oid *new;
+  if (!o->prefix && (new = prefixize(p, o, byte_ord)) != NULL)
+    find_prefixed(p, new, buf, size, contid);
   else if (o->prefix)
-    find_prefixed(p, o, buf, size);
+    find_prefixed(p, o, buf, size, contid);
   else
+    // TODO handle unprefixable oids
     return NULL;
 }
 
 static byte *
-prepare_response(struct snmp_proto *p, byte *buf, uint size, u16 err_no, u16 index)
+prepare_response(struct snmp_proto *p, byte *buf, uint size)
 {
   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;
 
@@ -903,11 +1231,21 @@ prepare_response(struct snmp_proto *p, byte *buf, uint size, u16 err_no, u16 ind
 
   /* protocol doesn't care about subagent upTime */
   STORE(r->uptime, 0);
-  STORE_16(r->err, err_no);
-  STORE_16(r->index, index);
+  STORE_16(r->err, AGENTX_RES_NO_ERROR);
+  STORE_16(r->index, 0);
 
   buf += sizeof(struct agentx_response);
   return buf;
 }
 
+static void
+response_err_ind(byte *buf, uint err, uint ind)
+{
+  log(L_INFO "reponse_err_ind()");
+  struct agentx_response *res = (void *) buf;
+
+  res->err = err;
+  res->index = ind;
+}
+
 #undef SNMP_ERR_SHIFT
index c34dfa4be655e0027b805450a4000938d0863c6a..16da447bace9ffd72bb3efb8aeb5a6fe593edfbe 100644 (file)
@@ -14,20 +14,22 @@ void snmp_ping(struct snmp_proto *p);
 #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 */
 
+#define BGP4_VERSIONS 0x10
+
 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;
+  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
@@ -110,7 +112,7 @@ enum agentx_type {
   (v)->type = d;                 \
   p += o;
 
-#define BGP_DATA(v, d, p) BGP_DATA(v, d, p, 4)
+#define BGP_DATA(v, d, p) BGP_DATA_(v, d, p, 4)
 
 struct agentx_header {
   u8 version;
@@ -211,20 +213,33 @@ enum agentx_close_reasons {
 
 /* 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,
+  AGENTX_RES_NO_ERROR              =   0,
+  /* TEST_SET_PDU response errors */
+  AGENTX_RES_GEN_ERROR             =   5,
+  AGENTX_RES_NO_ACCESS             =   6,
+  AGENTX_RES_WRONG_TYPE                    =   7,
+  AGENTX_RES_WRONG_LENGTH          =   8,
+  AGENTX_RES_WRONG_ENCODING        =   9,
+  AGENTX_RES_WRONG_VALUE           =  10,
+  AGENTX_RES_NO_CREATION           =  11,
+  AGENTX_RES_INCONSISTENT_VALUE            =  12,
+  AGENTX_RES_RESOURCE_UNAVAILABLE   =  13,
+  AGENTX_RES_NOT_WRITEABLE         =  17,
+  AGENTX_RES_INCONSISTENT_NAME     =  18,
+  /* end of TEST_SET_PDU resonse errs */
+  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);