]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Testing Notify-PDU
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Mon, 4 Sep 2023 07:25:51 +0000 (09:25 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Mon, 4 Sep 2023 07:25:51 +0000 (09:25 +0200)
proto/snmp/bgp_mib.c
proto/snmp/snmp.c
proto/snmp/snmp.h
proto/snmp/subagent.c

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