]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
SNMP: Major leap forward
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 23 Jan 2024 23:23:31 +0000 (00:23 +0100)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 23 Jan 2024 23:23:31 +0000 (00:23 +0100)
Solved segmentation faults.

proto/snmp/bgp_mib.c
proto/snmp/bgp_mib.h
proto/snmp/snmp.c
proto/snmp/snmp.h
proto/snmp/snmp_utils.c
proto/snmp/snmp_utils.h
proto/snmp/splitter.py [new file with mode: 0755]
proto/snmp/subagent.c
proto/snmp/subagent.h

index c55af2901a4254246056f3df3d282a136babab8f..d97a0de4c16a7cff8f172af21a71d158298f766a 100644 (file)
 #include "subagent.h"
 #include "bgp_mib.h"
 
-STATIC_ASSERT(BGP_MIB_IDLE == BS_IDLE + 1);
-STATIC_ASSERT(BGP_MIB_CONNECT == BS_CONNECT + 1);
-STATIC_ASSERT(BGP_MIB_ACTIVE == BS_ACTIVE + 1);
-STATIC_ASSERT(BGP_MIB_OPENSENT == BS_OPENSENT + 1);
-STATIC_ASSERT(BGP_MIB_OPENCONFIRM == BS_OPENCONFIRM + 1);
-STATIC_ASSERT(BGP_MIB_ESTABLISHED == BS_ESTABLISHED + 1);
-
 /* hash table macros */
 #define SNMP_HASH_KEY(n)  n->peer_ip
 #define SNMP_HASH_NEXT(n) n->next
@@ -58,30 +51,30 @@ static u8
 bgp_get_candidate(u32 field)
 {
   const u8 translation_table[] = {
-    [SNMP_BGP_PEER_IDENTIFIER]         = BGP_INTERNAL_PEER_IDENTIFIER,
-    [SNMP_BGP_STATE]                   = BGP_INTERNAL_STATE,
-    [SNMP_BGP_ADMIN_STATUS]            = BGP_INTERNAL_ADMIN_STATUS,
-    [SNMP_BGP_NEGOTIATED_VERSION]      = BGP_INTERNAL_NEGOTIATED_VERSION,
-    [SNMP_BGP_LOCAL_ADDR]              = BGP_INTERNAL_LOCAL_ADDR,
-    [SNMP_BGP_LOCAL_PORT]              = BGP_INTERNAL_LOCAL_PORT,
-    [SNMP_BGP_REMOTE_ADDR]             = BGP_INTERNAL_REMOTE_ADDR,
-    [SNMP_BGP_REMOTE_PORT]             = BGP_INTERNAL_REMOTE_PORT,
-    [SNMP_BGP_REMOTE_AS]               = BGP_INTERNAL_REMOTE_AS,
-    [SNMP_BGP_RX_UPDATES]              = BGP_INTERNAL_RX_UPDATES,
-    [SNMP_BGP_TX_UPDATES]              = BGP_INTERNAL_TX_UPDATES,
-    [SNMP_BGP_RX_MESSAGES]             = BGP_INTERNAL_RX_MESSAGES,
-    [SNMP_BGP_TX_MESSAGES]             = BGP_INTERNAL_TX_MESSAGES,
-    [SNMP_BGP_LAST_ERROR]              = BGP_INTERNAL_LAST_ERROR,
-    [SNMP_BGP_FSM_TRANSITIONS]         = BGP_INTERNAL_FSM_TRANSITIONS,
-    [SNMP_BGP_FSM_ESTABLISHED_TIME]    = BGP_INTERNAL_FSM_ESTABLISHED_TIME,
-    [SNMP_BGP_RETRY_INTERVAL]          = BGP_INTERNAL_RETRY_INTERVAL,
-    [SNMP_BGP_HOLD_TIME]               = BGP_INTERNAL_HOLD_TIME,
-    [SNMP_BGP_KEEPALIVE]               = BGP_INTERNAL_KEEPALIVE,
-    [SNMP_BGP_HOLD_TIME_CONFIGURED]    = BGP_INTERNAL_HOLD_TIME_CONFIGURED,
-    [SNMP_BGP_KEEPALIVE_CONFIGURED]     = BGP_INTERNAL_KEEPALIVE_CONFIGURED,
-    [SNMP_BGP_ORIGINATION_INTERVAL]     = BGP_INTERNAL_ORIGINATION_INTERVAL,
-    [SNMP_BGP_MIN_ROUTE_ADVERTISEMENT]  = BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT,
-    [SNMP_BGP_IN_UPDATE_ELAPSED_TIME]   = BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME,
+    [BGP4_MIB_PEER_IDENTIFIER]         = BGP4_MIB_S_PEER_IDENTIFIER,
+    [BGP4_MIB_STATE]                   = BGP4_MIB_S_STATE,
+    [BGP4_MIB_ADMIN_STATUS]            = BGP4_MIB_S_ADMIN_STATUS,
+    [BGP4_MIB_NEGOTIATED_VERSION]      = BGP4_MIB_S_NEGOTIATED_VERSION,
+    [BGP4_MIB_LOCAL_ADDR]              = BGP4_MIB_S_LOCAL_ADDR,
+    [BGP4_MIB_LOCAL_PORT]              = BGP4_MIB_S_LOCAL_PORT,
+    [BGP4_MIB_REMOTE_ADDR]             = BGP4_MIB_S_REMOTE_ADDR,
+    [BGP4_MIB_REMOTE_PORT]             = BGP4_MIB_S_REMOTE_PORT,
+    [BGP4_MIB_REMOTE_AS]               = BGP4_MIB_S_REMOTE_AS,
+    [BGP4_MIB_RX_UPDATES]              = BGP4_MIB_S_RX_UPDATES,
+    [BGP4_MIB_TX_UPDATES]              = BGP4_MIB_S_TX_UPDATES,
+    [BGP4_MIB_RX_MESSAGES]             = BGP4_MIB_S_RX_MESSAGES,
+    [BGP4_MIB_TX_MESSAGES]             = BGP4_MIB_S_TX_MESSAGES,
+    [BGP4_MIB_LAST_ERROR]              = BGP4_MIB_S_LAST_ERROR,
+    [BGP4_MIB_FSM_TRANSITIONS]         = BGP4_MIB_S_FSM_TRANSITIONS,
+    [BGP4_MIB_FSM_ESTABLISHED_TIME]    = BGP4_MIB_S_FSM_ESTABLISHED_TIME,
+    [BGP4_MIB_RETRY_INTERVAL]          = BGP4_MIB_S_RETRY_INTERVAL,
+    [BGP4_MIB_HOLD_TIME]               = BGP4_MIB_S_HOLD_TIME,
+    [BGP4_MIB_KEEPALIVE]               = BGP4_MIB_S_KEEPALIVE,
+    [BGP4_MIB_HOLD_TIME_CONFIGURED]    = BGP4_MIB_S_HOLD_TIME_CONFIGURED,
+    [BGP4_MIB_KEEPALIVE_CONFIGURED]     = BGP4_MIB_S_KEEPALIVE_CONFIGURED,
+    [BGP4_MIB_ORIGINATION_INTERVAL]     = BGP4_MIB_S_ORIGINATION_INTERVAL,
+    [BGP4_MIB_MIN_ROUTE_ADVERTISEMENT]  = BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT,
+    [BGP4_MIB_IN_UPDATE_ELAPSED_TIME]   = BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME,
   };
 
   /*
@@ -90,10 +83,10 @@ bgp_get_candidate(u32 field)
    */
   if (field > 0 && field <= ARRAY_SIZE(translation_table)- 1)
     return translation_table[field];
-  if (field == 0)
-    return BGP_INTERNAL_PEER_ENTRY;
+  else if (field == 0)
+    return BGP4_MIB_S_PEER_ENTRY;
   else
-    return BGP_INTERNAL_PEER_TABLE_END;
+    return BGP4_MIB_S_PEER_TABLE_END;
 }
 
 /**
@@ -114,9 +107,9 @@ snmp_bgp_state(const struct oid *oid)
    */
 
   if (snmp_is_oid_empty(oid))
-    return BGP_INTERNAL_END;
+    return BGP4_MIB_S_END;
 
-  u8 state = BGP_INTERNAL_NO_VALUE;
+  u8 state = BGP4_MIB_S_NO_VALUE;
 
   u8 candidate;
   switch (oid->n_subid)
@@ -124,7 +117,7 @@ snmp_bgp_state(const struct oid *oid)
     default:
       if (oid->n_subid < 2)
       {
-       state = BGP_INTERNAL_INVALID;
+       state = BGP4_MIB_S_INVALID;
        break;
       }
 
@@ -145,11 +138,11 @@ snmp_bgp_state(const struct oid *oid)
       /* fall through */
 
     case 4:
-      if (oid->ids[3] == SNMP_BGP_PEER_ENTRY)
-       state = (state == BGP_INTERNAL_NO_VALUE) ?
-         BGP_INTERNAL_PEER_ENTRY : state;
+      if (oid->ids[3] == BGP4_MIB_PEER_ENTRY)
+       state = (state == BGP4_MIB_S_NO_VALUE) ?
+         BGP4_MIB_S_PEER_ENTRY : state;
       else
-       state = BGP_INTERNAL_NO_VALUE;
+       state = BGP4_MIB_S_NO_VALUE;
 
       /* fall through */
 
@@ -158,39 +151,39 @@ snmp_bgp_state(const struct oid *oid)
       switch (oid->ids[2])
       {
 
-       case SNMP_BGP_VERSION:
-         state = BGP_INTERNAL_VERSION;
+       case BGP4_MIB_VERSION:
+         state = BGP4_MIB_S_VERSION;
          break;
-       case SNMP_BGP_LOCAL_AS:
-         state = BGP_INTERNAL_LOCAL_AS;
+       case BGP4_MIB_LOCAL_AS:
+         state = BGP4_MIB_S_LOCAL_AS;
          break;
-       case SNMP_BGP_PEER_TABLE:
+       case BGP4_MIB_PEER_TABLE:
          /* We use candidate to avoid overriding more specific state */
-         candidate = BGP_INTERNAL_PEER_TABLE;
+         candidate = BGP4_MIB_S_PEER_TABLE;
          break;
-       case SNMP_BGP_IDENTIFIER:
-         state = BGP_INTERNAL_IDENTIFIER;
+       case BGP4_MIB_IDENTIFIER:
+         state = BGP4_MIB_S_IDENTIFIER;
          break;
 
        default:  /* test fails */
          /* We force state invalidation */
-         if (oid->ids[2] < SNMP_BGP_VERSION)
+         if (oid->ids[2] < BGP4_MIB_VERSION)
          {
-           state = BGP_INTERNAL_NO_VALUE;
-           candidate = BGP_INTERNAL_NO_VALUE;
+           state = BGP4_MIB_S_NO_VALUE;
+           candidate = BGP4_MIB_S_NO_VALUE;
          }
-         else /* oid->ids[2] > SNMP_BGP_PEER_TABLE */
-           state = BGP_INTERNAL_END;
+         else /* oid->ids[2] > BGP4_MIB_PEER_TABLE */
+           state = BGP4_MIB_S_END;
       }
-      state = (state == BGP_INTERNAL_NO_VALUE) ?
+      state = (state == BGP4_MIB_S_NO_VALUE) ?
        candidate : state;
 
       /* fall through */
 
     case 2: /* We found bare BGP4-MIB::bgp ObjectId */
-      if (state == BGP_INTERNAL_NO_VALUE ||
-         state == BGP_INTERNAL_INVALID)
-       state = BGP_INTERNAL_BGP;
+      if (state == BGP4_MIB_S_NO_VALUE ||
+         state == BGP4_MIB_S_INVALID)
+       state = BGP4_MIB_S_BGP;
   }
 
   return state;
@@ -216,73 +209,103 @@ snmp_bgp_reg_failed(struct snmp_proto *p, struct agentx_response UNUSED *r, stru
 /*
  * snmp_bgp_notify_common - common functionaly for BGP4-MIB notifications
  * @p: SNMP protocol instance
- * @type
- *
+ * @type: type of notification send - either established or backward transition
+ * @ip4: IPv4 remote addr
+ * @last_error: 2 bytes of BGP last error
+ * @state_val: BGP peer state as defined in MIB
  */
 static void
 snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_error[], uint state_val)
 {
-#define SNMP_OID_SIZE_FROM_LEN(x) (sizeof(struct oid) + (x) * sizeof(u32))
-
-  /* OIDs, VB type headers, octet string, ip4 address, integer */
-  uint sz = 3 * SNMP_OID_SIZE_FROM_LEN(9) + 3 * 4 + 8 + 8 + 4;
-
-  /* trap OID bgpEstablishedNotification (.1.3.6.1.2.1.0.1) */
-  struct oid *head = mb_alloc(p->pool, SNMP_OID_SIZE_FROM_LEN(3)) + sz;
-  head->n_subid = 3;
-  head->prefix = 2;
-  head->include = head->pad = 0;
+  uint sz = (uint) (snmp_varbind_size_from_len(9, AGENTX_IP_ADDRESS, 0)
+      + snmp_varbind_size_from_len(9, AGENTX_OCTET_STRING, 2)
+      + snmp_varbind_size_from_len(9, AGENTX_INTEGER, 0));
 
   u32 trap_ids[] = { 1, 0, type };
-  for (uint i = 0; i < head->n_subid; i++)
-    head->ids[i] = trap_ids[i];
-
-
-  void *data = (void *) head + sz;
+  STATIC_ASSERT(ARRAY_SIZE(trap_ids) == 3);
+  /* additional size for trap identification, here either 
+   *  bgpEstablishedNotification or bgpBackwardTransNotification (see below) */
+  void *data = tmp_alloc(snmp_oid_size_from_len(ARRAY_SIZE(trap_ids)) + sz); 
+  struct oid *head = data; 
+
+  { /* trap id BGP4-MIB::bgpEstablishedNotification (.1.3.6.1.2.15.0.1)
+     * or BGP4-MIB::bgpBackwardTransNotification (.1.3.6.1.2.15.0.2) */
+    head->n_subid = ARRAY_SIZE(trap_ids);
+    head->prefix = SNMP_MGMT;
+    head->include = head->reserved = 0;
+
+    for (uint i = 0; i < head->n_subid; i++)
+      head->ids[i] = trap_ids[i];
+  }
 
+  data += sz;
   struct agentx_varbind *addr_vb = data;
-  // TODO remove magic constants; use measuring functions instead
-  /* +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;
-
-  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;
+  struct agentx_varbind *error_vb = \
+    data + snmp_varbind_size_from_len(9, AGENTX_IP_ADDRESS, 0);
+  struct agentx_varbind *state_vb = \
+    (void *) error_vb + snmp_varbind_size_from_len(9, AGENTX_OCTET_STRING, 2);
 
   u32 oid_ids[] = {
-    SNMP_MIB_2, SNMP_BGP4_MIB, SNMP_BGP_PEER_TABLE, SNMP_BGP_PEER_ENTRY
+    SNMP_MIB_2, BGP4_MIB, BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY
   };
 
-  for (uint i = 0; i < sizeof(oid_ids) / sizeof(oid_ids[0]); 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;
-
-  for (uint i = 0; i < 4; i++)
-    addr->ids[5 + i] = error->ids[5 + i] = state->ids[5 + i] \
-      = (ip4_to_u32(ip4) >> (8 * (3-i))) & 0xFF;
-
-  snmp_varbind_ip4(addr_vb, 100, ip4);
-
-  snmp_varbind_nstr(error_vb, 100, last_error, 2);
-
-  snmp_varbind_int(state_vb, 100, state_val);
+  /*
+   * The n_subid is 9 in all cases because all are rows entries of
+   * BGP4-MIB::bgpPeerTable
+   *  BGP4-MIB::bgpPeerRemoteAddr = .1.3.6.1.[2].1.15.3.1.7.a.b.c.d
+   * where .1.3.6.1 is internet prefix, .[2] is SNMP_MGMT,
+   * .1.15.3.1.7.a.b.c.d has 9 elements (a.b.c.d are IP addr bytes)
+   *  Here subidentifier 7 is entry type bgpPeerRemoteAddr.
+   */
+  #define PEER_TABLE_ENTRY 9
+  #define ENTRY_TYPE 4
+
+  { /* BGP4-MIB::bgpPeerRemoteAddr */
+    struct oid *addr = &addr_vb->name;
+    *addr = (struct oid) {
+      .n_subid = PEER_TABLE_ENTRY, .prefix = SNMP_MGMT, .include = 0,
+      .reserved = 0,
+    };
+    for (uint i = 0; i < ARRAY_SIZE(oid_ids); i++)
+      addr->ids[i] = oid_ids[i];
+    addr->ids[ENTRY_TYPE] = BGP4_MIB_REMOTE_ADDR;
+    ip4_to_oid(addr, ip4);
+  }
+  /* We have enough space inside the TX-buffer prepared */
+  #define UNLIMITED 100
+  snmp_varbind_ip4(addr_vb, UNLIMITED, ip4);
+
+  { /* BGP4-MIB::bgpPeerLastError */
+    struct oid *error = &error_vb->name;
+    *error = (struct oid) {
+      .n_subid = PEER_TABLE_ENTRY, .prefix = SNMP_MGMT, .include = 0,
+      .reserved = 0,
+    };
+    for (uint i = 0; i < ARRAY_SIZE(oid_ids); i++)
+      error->ids[i] = oid_ids[i];
+    error->ids[ENTRY_TYPE] = BGP4_MIB_LAST_ERROR;
+    ip4_to_oid(error, ip4);
+  }
+  snmp_varbind_nstr(error_vb, UNLIMITED, last_error, 2);
+
+  { /* BGP4-MIB::bgpPeerState */
+    struct oid *state = &state_vb->name;
+    *state = (struct oid) {
+      .n_subid = PEER_TABLE_ENTRY, .prefix = SNMP_MGMT, .include = 0,
+      .reserved = 0,
+    };
+    for (uint i = 0; i < ARRAY_SIZE(oid_ids); i++)
+      state->ids[i] = oid_ids[i];
+    state->ids[ENTRY_TYPE] = BGP4_MIB_STATE;
+    ip4_to_oid(state, ip4);
+  }
+  snmp_varbind_int(state_vb, UNLIMITED, state_val);
 
+  /* We do not send the systemUpTime.0 */
   snmp_notify_pdu(p, head, data, sz, 0);
-  mb_free(head);
-  mb_free(data);
 
-#undef SNMP_OID_SIZE_FROM_LEN
+  #undef OID_N_SUBID
+  #undef UNLIMITED
 }
 
 /*
@@ -303,17 +326,17 @@ snmp_bgp_fsm_state(const struct bgp_proto *bgp_proto)
 
   if (MAX(bgp_in->state, bgp_out->state) == BS_CLOSE &&
       MIN(bgp_in->state, bgp_out->state) != BS_CLOSE)
-    return MIN(bgp_in->state, bgp_out->state);
+    return MIN(bgp_in->state, bgp_out->state) + 1;
   if (MIN(bgp_in->state, bgp_out->state) == BS_CLOSE)
     return BS_IDLE;
-
-  return MAX(bgp_in->state, bgp_out->state);
+  return MAX(bgp_in->state, bgp_out->state) + 1;
 }
 
 static void
 snmp_bgp_notify_wrapper(struct snmp_proto *p, struct bgp_proto *bgp, uint type)
 {
-  // possibly dangerous
+  /* possibly incorrect cast */
   ip4_addr ip4 = ipa_to_ip4(bgp->remote_ip);
   char last_error[2];
   snmp_bgp_last_error(bgp, last_error);
@@ -324,30 +347,27 @@ snmp_bgp_notify_wrapper(struct snmp_proto *p, struct bgp_proto *bgp, uint type)
 void
 snmp_bgp_notify_established(struct snmp_proto *p, struct bgp_proto *bgp)
 {
-  /* .1.3.6.1.2.15.0.>1<  i.e. BGP4-MIB::bgpEstablishedNotification */
-  snmp_bgp_notify_wrapper(p, bgp, 1);
+  snmp_bgp_notify_wrapper(p, bgp, BGP4_MIB_ESTABLISHED_NOTIFICATION);
 }
 
 void
 snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp)
 {
-  /* .1.3.6.1.2.15.0.>2<  i.e. BGP4-MIB::bgpBackwardTransNotification */
-  snmp_bgp_notify_wrapper(p, bgp, 2);
+  snmp_bgp_notify_wrapper(p, bgp, BGP4_MIB_BACKWARD_TRANS_NOTIFICATION);
 }
 
 void
 snmp_bgp_register(struct snmp_proto *p)
 {
-  //u32 bgp_mib_prefix[] = {1, 15, 1};
   u32 bgp_mib_prefix[] = { 1, 15 };
 
   {
     /* Register the whole BGP4-MIB::bgp root tree node */
     struct snmp_registration *reg;
-    reg = snmp_registration_create(p, SNMP_BGP4_MIB);
+    reg = snmp_registration_create(p, BGP4_MIB);
 
-    struct oid *oid = mb_alloc(p->pool,
-      snmp_oid_sizeof(ARRAY_SIZE(bgp_mib_prefix)));
+    struct oid *oid = mb_allocz(p->pool,
+      snmp_oid_size_from_len(ARRAY_SIZE(bgp_mib_prefix)));
     STORE_U8(oid->n_subid, ARRAY_SIZE(bgp_mib_prefix));
     STORE_U8(oid->prefix, SNMP_MGMT);
 
@@ -434,7 +454,7 @@ print_bgp_record(const struct bgp_proto *bgp_proto)
   DBG("  incoming_conn state: %u", bgp_proto->incoming_conn.state + 1);
 }
 
-static void
+static void UNUSED
 print_bgp_record_all(struct snmp_proto *p)
 {
   DBG("dumping watched bgp status");
@@ -448,29 +468,43 @@ print_bgp_record_all(struct snmp_proto *p)
 
 
 
+/*
+ * is_dynamic - is state dependent on runtime BGP peer state
+ * @state: tested bgp4_mib state
+ *
+ * Used to distinguish states that depend on runtime BGP peer states.
+ *
+ * Return nonzero for states with value that may change at runtime.
+ */
 static inline int
 is_dynamic(u8 state)
 {
-  return (state >= BGP_INTERNAL_PEER_IDENTIFIER &&
-         state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME);
+  return (state >= BGP4_MIB_S_PEER_IDENTIFIER &&
+         state <= BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME);
 }
 
+/*
+ * is_static - logical inverse of is_dynamic() for states with value
+ * @state: tested bgp4_mib state
+ *
+ * Return nonzero for states with value that do not change at runtime.
+ */
 static inline int
 is_static(u8 state)
 {
-  return (state == BGP_INTERNAL_VERSION ||
-         state == BGP_INTERNAL_LOCAL_AS ||
-         state == BGP_INTERNAL_IDENTIFIER);
+  return (state == BGP4_MIB_S_VERSION ||
+         state == BGP4_MIB_S_LOCAL_AS ||
+         state == BGP4_MIB_S_IDENTIFIER);
 }
 
 static inline int
 snmp_bgp_has_value(u8 state)
 {
-  if (state <= BGP_INTERNAL_BGP ||
-      state == BGP_INTERNAL_PEER_TABLE ||
-      state == BGP_INTERNAL_PEER_ENTRY ||
-      state == BGP_INTERNAL_PEER_TABLE_END ||
-      state >= BGP_INTERNAL_END)
+  if (state <= BGP4_MIB_S_BGP ||
+      state == BGP4_MIB_S_PEER_TABLE ||
+      state == BGP4_MIB_S_PEER_ENTRY ||
+      state == BGP4_MIB_S_PEER_TABLE_END ||
+      state >= BGP4_MIB_S_END)
     return 0;
   else
     return 1;
@@ -486,12 +520,12 @@ snmp_bgp_has_value(u8 state)
 u8
 snmp_bgp_get_valid(u8 state)
 {
-  if (state == BGP_INTERNAL_INVALID ||
-      state == BGP_INTERNAL_BGP ||
-      state == BGP_INTERNAL_PEER_TABLE ||
-      state == BGP_INTERNAL_PEER_ENTRY ||
-      state == BGP_INTERNAL_PEER_TABLE_END ||
-      state >= BGP_INTERNAL_END)
+  if (state == BGP4_MIB_S_INVALID ||
+      state == BGP4_MIB_S_BGP ||
+      state == BGP4_MIB_S_PEER_TABLE ||
+      state == BGP4_MIB_S_PEER_ENTRY ||
+      state == BGP4_MIB_S_PEER_TABLE_END ||
+      state >= BGP4_MIB_S_END)
     return 0;
   else
     return state;
@@ -509,58 +543,37 @@ snmp_bgp_next_state(u8 state)
 {
   switch (state)
   {
-    case BGP_INTERNAL_LOCAL_AS:
-    case BGP_INTERNAL_PEER_TABLE:
-    case BGP_INTERNAL_PEER_ENTRY:
-      return BGP_INTERNAL_PEER_IDENTIFIER;
+    case BGP4_MIB_S_LOCAL_AS:
+    case BGP4_MIB_S_PEER_TABLE:
+    case BGP4_MIB_S_PEER_ENTRY:
+      return BGP4_MIB_S_PEER_IDENTIFIER;
 
-    case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
-    case BGP_INTERNAL_PEER_TABLE_END:
-      return BGP_INTERNAL_IDENTIFIER;
+    case BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME:
+    case BGP4_MIB_S_PEER_TABLE_END:
+      return BGP4_MIB_S_IDENTIFIER;
 
-    case BGP_INTERNAL_IDENTIFIER:
-    case BGP_INTERNAL_END:
-      return BGP_INTERNAL_END;
+    case BGP4_MIB_S_IDENTIFIER:
+    case BGP4_MIB_S_END:
+      return BGP4_MIB_S_END;
 
     default:
       return state + 1;
   }
 }
 
-int
-snmp_bgp_is_supported(struct oid *o)
-{
-  if (o->prefix == 2 && o->n_subid > 0 && o->ids[0] == 1)
-  {
-    if (o->n_subid == 2 && (o->ids[1] == SNMP_BGP4_MIB ||
-        o->ids[1] == SNMP_BGP_LOCAL_AS))
-      return 1;
-    else if (o->n_subid > 2 && o->ids[1] == SNMP_BGP_PEER_TABLE &&
-            o->ids[2] == SNMP_BGP_PEER_ENTRY)
-    {
-      if (o->n_subid == 3)
-       return 1;
-      if (o->n_subid == 8 && o->ids[3] > 0)
-       return 1;
-    }
-    return 0;
-  }
-  return 0;
-}
-
 static int
 oid_state_compare(const struct oid *oid, u8 state)
 {
   ASSUME(oid != NULL);
-  if (state >= BGP_INTERNAL_PEER_IDENTIFIER &&
-      state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME)
+  if (state >= BGP4_MIB_S_PEER_IDENTIFIER &&
+      state <= BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME)
     return (oid->n_subid > 9) - (oid->n_subid < 9);
-  if ((state >= BGP_INTERNAL_VERSION && state <= BGP_INTERNAL_PEER_TABLE) ||
-      (state == BGP_INTERNAL_IDENTIFIER))
+  if ((state >= BGP4_MIB_S_VERSION && state <= BGP4_MIB_S_PEER_TABLE) ||
+      (state == BGP4_MIB_S_IDENTIFIER))
     return (oid->n_subid > 3) - (oid->n_subid < 3);
-  if (state == BGP_INTERNAL_PEER_ENTRY)
+  if (state == BGP4_MIB_S_PEER_ENTRY)
     return (oid->n_subid > 4) - (oid->n_subid < 4);
-  if (state == BGP_INTERNAL_BGP)
+  if (state == BGP4_MIB_S_BGP)
     return (oid->n_subid > 2) - (oid->n_subid < 2);
 
   return -1;
@@ -569,58 +582,58 @@ oid_state_compare(const struct oid *oid, u8 state)
 static struct oid *
 update_bgp_oid(struct oid *oid, u8 state)
 {
-  if (state == BGP_INTERNAL_END || state == BGP_INTERNAL_INVALID ||
-      state == BGP_INTERNAL_NO_VALUE)
+  if (state == BGP4_MIB_S_END || state == BGP4_MIB_S_INVALID ||
+      state == BGP4_MIB_S_NO_VALUE)
     return oid;
 
   /* No need to reallocate anything if the OID has same lin. state */
   if (snmp_bgp_state(oid) == state)
   {
-    if (state >= BGP_INTERNAL_PEER_IDENTIFIER &&
-       state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME &&
+    if (state >= BGP4_MIB_S_PEER_IDENTIFIER &&
+       state <= BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME &&
        oid->n_subid == 9)
       return oid;
-    if (state >= BGP_INTERNAL_VERSION &&
-       state <= BGP_INTERNAL_PEER_TABLE && oid->n_subid == 3)
+    if (state >= BGP4_MIB_S_VERSION &&
+       state <= BGP4_MIB_S_PEER_TABLE && oid->n_subid == 3)
       return oid;
-    if (state == BGP_INTERNAL_PEER_ENTRY && oid->n_subid == 4)
+    if (state == BGP4_MIB_S_PEER_ENTRY && oid->n_subid == 4)
       return oid;
-    if (state == BGP_INTERNAL_BGP && oid->n_subid == 2)
+    if (state == BGP4_MIB_S_BGP && oid->n_subid == 2)
       return oid;
   }
 
   switch (state)
   {
-    case BGP_INTERNAL_BGP:
+    case BGP4_MIB_S_BGP:
       /* This could potentially destroy same old data */
       if (oid->n_subid != 2)
-       oid = mb_realloc(oid, snmp_oid_sizeof(2));
+       oid = mb_realloc(oid, snmp_oid_size_from_len(2));
 
       oid->n_subid = 2;
       oid->ids[0] = SNMP_MIB_2;
-      oid->ids[1] = SNMP_BGP4_MIB;
+      oid->ids[1] = BGP4_MIB;
       break;
 
-    case BGP_INTERNAL_VERSION:
+    case BGP4_MIB_S_VERSION:
       if (oid->n_subid != 3)
-       oid = mb_realloc(oid, snmp_oid_sizeof(3));
+       oid = mb_realloc(oid, snmp_oid_size_from_len(3));
 
       oid->n_subid = 3;
-      oid->ids[2] = SNMP_BGP_VERSION;
+      oid->ids[2] = BGP4_MIB_VERSION;
       break;
 
-    case BGP_INTERNAL_LOCAL_AS:
+    case BGP4_MIB_S_LOCAL_AS:
       if (oid->n_subid != 3)
-       oid = mb_realloc(oid, snmp_oid_sizeof(3));
+       oid = mb_realloc(oid, snmp_oid_size_from_len(3));
 
       oid->n_subid = 3;
-      oid->ids[2] = SNMP_BGP_LOCAL_AS;
+      oid->ids[2] = BGP4_MIB_LOCAL_AS;
       break;
 
-    case BGP_INTERNAL_PEER_IDENTIFIER:
+    case BGP4_MIB_S_PEER_IDENTIFIER:
       if (oid->n_subid != 9)
       {
-       oid = mb_realloc(oid, snmp_oid_sizeof(9));
+       oid = mb_realloc(oid, snmp_oid_size_from_len(9));
 
        if (oid->n_subid < 6)
          oid->ids[5] = 0;
@@ -632,10 +645,10 @@ update_bgp_oid(struct oid *oid, u8 state)
          oid->ids[8] = 0;
       }
 
-      oid->ids[2] = SNMP_BGP_PEER_TABLE;
-      oid->ids[3] = SNMP_BGP_PEER_ENTRY;
+      oid->ids[2] = BGP4_MIB_PEER_TABLE;
+      oid->ids[3] = BGP4_MIB_PEER_ENTRY;
 
-      oid->ids[4] = SNMP_BGP_PEER_IDENTIFIER;
+      oid->ids[4] = BGP4_MIB_PEER_IDENTIFIER;
       oid->n_subid = 9;
       break;
 
@@ -643,7 +656,7 @@ update_bgp_oid(struct oid *oid, u8 state)
     case num:                                                              \
       if (oid->n_subid != 9)                                               \
       {                                                                            \
-       oid = mb_realloc(oid, snmp_oid_sizeof(9));                          \
+       oid = mb_realloc(oid, snmp_oid_size_from_len(9));                   \
                                                                            \
        if (oid->n_subid < 6)                                               \
          oid->ids[5] = 0;                                                  \
@@ -658,55 +671,55 @@ update_bgp_oid(struct oid *oid, u8 state)
       oid->ids[4] = update;                                                \
       break;
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_STATE, SNMP_BGP_STATE)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_STATE, BGP4_MIB_STATE)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_ADMIN_STATUS, SNMP_BGP_ADMIN_STATUS)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_ADMIN_STATUS, BGP4_MIB_ADMIN_STATUS)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_NEGOTIATED_VERSION, SNMP_BGP_NEGOTIATED_VERSION)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_NEGOTIATED_VERSION, BGP4_MIB_NEGOTIATED_VERSION)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_LOCAL_ADDR, SNMP_BGP_LOCAL_ADDR)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_LOCAL_ADDR, BGP4_MIB_LOCAL_ADDR)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_LOCAL_PORT, SNMP_BGP_LOCAL_PORT)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_LOCAL_PORT, BGP4_MIB_LOCAL_PORT)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_ADDR, SNMP_BGP_REMOTE_ADDR)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_REMOTE_ADDR, BGP4_MIB_REMOTE_ADDR)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_PORT, SNMP_BGP_REMOTE_PORT)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_REMOTE_PORT, BGP4_MIB_REMOTE_PORT)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_AS, SNMP_BGP_REMOTE_AS)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_REMOTE_AS, BGP4_MIB_REMOTE_AS)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_RX_UPDATES, SNMP_BGP_RX_UPDATES)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_RX_UPDATES, BGP4_MIB_RX_UPDATES)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_TX_UPDATES, SNMP_BGP_TX_UPDATES)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_TX_UPDATES, BGP4_MIB_TX_UPDATES)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_RX_MESSAGES, SNMP_BGP_RX_MESSAGES)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_RX_MESSAGES, BGP4_MIB_RX_MESSAGES)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_TX_MESSAGES, SNMP_BGP_TX_MESSAGES)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_TX_MESSAGES, BGP4_MIB_TX_MESSAGES)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_LAST_ERROR, SNMP_BGP_LAST_ERROR)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_LAST_ERROR, BGP4_MIB_LAST_ERROR)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_FSM_TRANSITIONS, SNMP_BGP_FSM_TRANSITIONS)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_FSM_TRANSITIONS, BGP4_MIB_FSM_TRANSITIONS)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_FSM_ESTABLISHED_TIME, SNMP_BGP_FSM_ESTABLISHED_TIME)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_FSM_ESTABLISHED_TIME, BGP4_MIB_FSM_ESTABLISHED_TIME)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_RETRY_INTERVAL, SNMP_BGP_RETRY_INTERVAL)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_RETRY_INTERVAL, BGP4_MIB_RETRY_INTERVAL)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_HOLD_TIME, SNMP_BGP_HOLD_TIME)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_HOLD_TIME, BGP4_MIB_HOLD_TIME)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_KEEPALIVE, SNMP_BGP_KEEPALIVE)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_KEEPALIVE, BGP4_MIB_KEEPALIVE)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_HOLD_TIME_CONFIGURED, SNMP_BGP_HOLD_TIME_CONFIGURED)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_HOLD_TIME_CONFIGURED, BGP4_MIB_HOLD_TIME_CONFIGURED)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_KEEPALIVE_CONFIGURED, SNMP_BGP_KEEPALIVE_CONFIGURED)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_KEEPALIVE_CONFIGURED, BGP4_MIB_KEEPALIVE_CONFIGURED)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_ORIGINATION_INTERVAL, SNMP_BGP_ORIGINATION_INTERVAL)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_ORIGINATION_INTERVAL, BGP4_MIB_ORIGINATION_INTERVAL)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT, SNMP_BGP_MIN_ROUTE_ADVERTISEMENT)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT, BGP4_MIB_MIN_ROUTE_ADVERTISEMENT)
 
-    SNMP_UPDATE_CASE(BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME, SNMP_BGP_IN_UPDATE_ELAPSED_TIME)
+    SNMP_UPDATE_CASE(BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME, BGP4_MIB_IN_UPDATE_ELAPSED_TIME)
 
-    case BGP_INTERNAL_IDENTIFIER:
+    case BGP4_MIB_S_IDENTIFIER:
       if (oid->n_subid != 3)
-       oid = mb_realloc(oid, snmp_oid_sizeof(3));
+       oid = mb_realloc(oid, snmp_oid_size_from_len(3));
 
       oid->n_subid = 3;
       oid->ids[2] = 4;
@@ -715,81 +728,12 @@ update_bgp_oid(struct oid *oid, u8 state)
     default:
       /* intentionally left blank */
       break;
-      //die("update unavailable");
   }
 
   return oid;
 #undef SNMP_UPDATE_CASE
 }
 
-static struct oid *
-bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, const struct oid *o_end, u8 start_state)
-{
-  ASSUME(o_start != NULL);
-  ASSUME(o_end != NULL);
-
-  ip4_addr ip4 = ip4_from_oid(o_start);
-  ip4_addr dest;
-
-  if (o_start->n_subid < 9)
-    o_start->include = 1;
-
-  int check_dest = snmp_is_oid_empty(o_end);
-  if (check_dest)
-  {
-    u8 end_state = snmp_bgp_state(o_end);
-    dest = (start_state == end_state && o_end->n_subid > 5) ?
-      ip4_from_oid(o_end) :
-      ip4_from_u32(UINT32_MAX);
-  }
-
-  net_addr net;
-  net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH);
-
-  struct f_trie_walk_state ws;
-
-  trie_walk_init(&ws, p->bgp_trie, NULL, 0);
-
-  if (!trie_walk_next(&ws, &net))
-    return NULL;
-
-  /*
-   * If the o_end is empty, then there are no conditions on the ip4 address.
-   */
-  int cmp = ip4_compare(net4_prefix(&net), dest);
-  if (cmp < 0 || (cmp == 0 && snmp_is_oid_empty(o_end)))
-  {
-    // TODO repair
-    struct oid *o = snmp_oid_duplicate(p->pool, o_start);
-    snmp_oid_ip4_index(o, 5, net4_prefix(&net));
-
-    return o;
-  }
-
-  return NULL;
-}
-
-static struct oid *
-search_bgp_dynamic(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid
-UNUSED, u8 next_state)
-{
-  struct oid *o_copy = o_start;
-  do
-  {
-    o_start = o_copy = update_bgp_oid(o_copy, next_state);
-
-    o_start = bgp_find_dynamic_oid(p, o_start, o_end, next_state);
-
-    next_state = snmp_bgp_next_state(next_state);
-    /* 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;
-
-  } while (o_start == NULL && next_state < BGP_INTERNAL_END);
-
-  return o_start;
-}
-
 /**
  * snmp_bgp_find_next_oid - walk bgp peer addresses and update @o_start oid
  *
@@ -801,7 +745,6 @@ static int
 snmp_bgp_find_next_oid(struct snmp_proto *p, struct oid *oid, uint UNUSED contid)
 {
   ip4_addr ip4 = ip4_from_oid(oid);
-  //ip_add4 dest = ip4_from_u32(0xFFFFFFFF);
 
   net_addr net;
   net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH);
@@ -823,13 +766,9 @@ snmp_bgp_find_next_oid(struct snmp_proto *p, struct oid *oid, uint UNUSED contid
 
   if (trie_walk_next(&ws, &net))
   {
-    u32 res = ipa_to_u32(net_prefix(&net));
-
     ASSUME(oid->n_subid == 9);
-    oid->ids[5] = (res & 0xFF000000) >> 24;
-    oid->ids[6] = (res & 0x00FF0000) >> 16;
-    oid->ids[7] = (res & 0x0000FF00) >>  8;
-    oid->ids[8] = (res & 0x000000FF) >>  0;
+    ip4_addr res = ipa_to_ip4(net_prefix(&net));
+    ip4_to_oid(oid, res);
     return 1;
   }
 
@@ -840,9 +779,9 @@ static enum snmp_search_res
 snmp_bgp_search_dynamic(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint UNUSED contid, u8 next_state)
 {
   struct oid *oid = *searched;
-  u8 end_state = MIN(snmp_bgp_state(o_end), BGP_INTERNAL_PEER_TABLE_END);
+  u8 end_state = MIN(snmp_bgp_state(o_end), BGP4_MIB_S_PEER_TABLE_END);
 
-  ASSUME(end_state <= BGP_INTERNAL_END);
+  ASSUME(end_state <= BGP4_MIB_S_END);
   ASSUME(oid != NULL);
 
   oid = update_bgp_oid(oid, next_state);
@@ -851,14 +790,14 @@ snmp_bgp_search_dynamic(struct snmp_proto *p, struct oid **searched, const struc
   while (!(found = snmp_bgp_find_next_oid(p, oid, contid)) && next_state <= end_state)
   {
     next_state = snmp_bgp_next_state(next_state);
-    if (next_state == BGP_INTERNAL_IDENTIFIER)
+    if (next_state == BGP4_MIB_S_IDENTIFIER)
       break;
     oid = update_bgp_oid(oid, next_state);
     /* In case of search for next bgp state, we want to start from beginning. */
     oid->ids[5] = oid->ids[6] = oid->ids[7] = oid->ids[8] = 0;
   }
 
-  if (next_state < BGP_INTERNAL_PEER_TABLE_END && next_state <= end_state)
+  if (next_state < BGP4_MIB_S_PEER_TABLE_END && next_state <= end_state)
   {
     *searched = oid;
     return SNMP_SEARCH_OK;
@@ -868,13 +807,13 @@ snmp_bgp_search_dynamic(struct snmp_proto *p, struct oid **searched, const struc
 }
 
 enum snmp_search_res
-snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid)
+snmp_bgp_search(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid)
 {
   enum snmp_search_res r = SNMP_SEARCH_END_OF_VIEW;
   u8 bgp_state = snmp_bgp_state(*searched);
   u8 state;
 
-  if (bgp_state == BGP_INTERNAL_END)
+  if (bgp_state == BGP4_MIB_S_END)
   {
     return SNMP_SEARCH_NO_OBJECT;
   }
@@ -909,7 +848,7 @@ snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *
   }
 
   state = snmp_bgp_next_state(bgp_state);
-  if (state <= BGP_INTERNAL_IDENTIFIER)
+  if (state <= BGP4_MIB_S_IDENTIFIER)
   {
     *searched = update_bgp_oid(*searched, state);
     return SNMP_SEARCH_OK;
@@ -921,40 +860,6 @@ snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *
   return SNMP_SEARCH_END_OF_VIEW;
 }
 
-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);
-
-  // print debugging information
-  print_bgp_record_all(p);
-
-  if (o_start->include && snmp_bgp_has_value(start_state) &&
-      !is_dynamic(start_state) && o_start->n_subid == 3)
-  {
-    /* We disable including for next time searching. */
-    o_start->include = 0;
-    return o_start;
-  }
-  else if (o_start->include && snmp_bgp_has_value(start_state) &&
-          is_dynamic(start_state))
-    return search_bgp_dynamic(p, o_start, o_end, contid, start_state);
-
-  /* o_start is not inclusive */
-
-  u8 next_state = snmp_bgp_next_state(start_state);
-  // TODO more checks ?!?
-  if (!is_dynamic(next_state))
-  {
-    o_start = update_bgp_oid(o_start, next_state);
-    return o_start;
-  }
-
-  /* is_dynamic(next_state) == 1 */
-
-  return search_bgp_dynamic(p, o_start, o_end, 0, next_state);
-}
-
 static byte *
 bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
                 struct snmp_pdu *c, u8 state)
@@ -1011,18 +916,18 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
   snmp_bgp_last_error(bgp_proto, last_error);
   switch (state)
   {
-    case BGP_INTERNAL_PEER_IDENTIFIER:
-      if (fsm_state == BGP_MIB_OPENCONFIRM || fsm_state == BGP_MIB_ESTABLISHED)
+    case BGP4_MIB_S_PEER_IDENTIFIER:
+      if (fsm_state == BGP4_MIB_OPENCONFIRM || fsm_state == BGP4_MIB_ESTABLISHED)
        pkt = snmp_varbind_ip4(vb, size, ip4_from_u32(bgp_proto->remote_id));
       else
        pkt = snmp_varbind_ip4(vb, size, IP4_NONE);
       break;
 
-    case BGP_INTERNAL_STATE:
+    case BGP4_MIB_S_STATE:
       pkt = snmp_varbind_int(vb, size, fsm_state);
       break;
 
-    case BGP_INTERNAL_ADMIN_STATUS:
+    case BGP4_MIB_S_ADMIN_STATUS:
       if (bgp_proto->p.disabled)
        pkt = snmp_varbind_int(vb, size, AGENTX_ADMIN_STOP);
       else
@@ -1030,79 +935,73 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
 
       break;
 
-    case BGP_INTERNAL_NEGOTIATED_VERSION:
-      if (fsm_state == BGP_MIB_ESTABLISHED || fsm_state == BGP_MIB_ESTABLISHED)
-       pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_VALUE);
+    case BGP4_MIB_S_NEGOTIATED_VERSION:
+      if (fsm_state == BGP4_MIB_ESTABLISHED || fsm_state == BGP4_MIB_ESTABLISHED)
+       pkt = snmp_varbind_int(vb, size, BGP4_MIB_NEGOTIATED_VER_VALUE);
       else
-       pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_NO_VALUE);
+       pkt = snmp_varbind_int(vb, size, BGP4_MIB_NEGOTIATED_VER_NO_VALUE);
 
       break;
 
-    case BGP_INTERNAL_LOCAL_ADDR:
+    case BGP4_MIB_S_LOCAL_ADDR:
       pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->local_ip));
       break;
 
-    case BGP_INTERNAL_LOCAL_PORT:
+    case BGP4_MIB_S_LOCAL_PORT:
       pkt = snmp_varbind_int(vb, size, bgp_conf->local_port);
       break;
 
-    case BGP_INTERNAL_REMOTE_ADDR:
+    case BGP4_MIB_S_REMOTE_ADDR:
       pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->remote_ip));
       break;
 
-    case BGP_INTERNAL_REMOTE_PORT:
+    case BGP4_MIB_S_REMOTE_PORT:
       pkt = snmp_varbind_int(vb, size, bgp_conf->remote_port);
       break;
 
-    case BGP_INTERNAL_REMOTE_AS:
+    case BGP4_MIB_S_REMOTE_AS:
       pkt = snmp_varbind_int(vb, size, bgp_proto->remote_as);
       break;
 
-    /* IN UPDATES */
-    case BGP_INTERNAL_RX_UPDATES:
+    case BGP4_MIB_S_RX_UPDATES:          /* bgpPeerInUpdates */
       pkt = snmp_varbind_counter32(vb, size, bgp_stats->rx_updates);
       break;
 
-    /* OUT UPDATES */
-    case BGP_INTERNAL_TX_UPDATES:
+    case BGP4_MIB_S_TX_UPDATES:          /* bgpPeerOutUpdate */
       pkt = snmp_varbind_counter32(vb, size, bgp_stats->tx_updates);
       break;
 
-    /* IN MESSAGES */
-    case BGP_INTERNAL_RX_MESSAGES:
+    case BGP4_MIB_S_RX_MESSAGES:  /* bgpPeerInTotalMessages */
       pkt = snmp_varbind_counter32(vb, size, bgp_stats->rx_messages);
       break;
 
-    /* OUT MESSAGES */
-    case BGP_INTERNAL_TX_MESSAGES:
+    case BGP4_MIB_S_TX_MESSAGES:  /* bgpPeerOutTotalMessages */
       pkt = snmp_varbind_counter32(vb, size, bgp_stats->tx_messages);
       break;
 
-    case BGP_INTERNAL_LAST_ERROR:
+    case BGP4_MIB_S_LAST_ERROR:
       pkt = snmp_varbind_nstr(vb, size, last_error, 2);
       break;
 
-    case BGP_INTERNAL_FSM_TRANSITIONS:
+    case BGP4_MIB_S_FSM_TRANSITIONS:
       pkt = snmp_varbind_counter32(vb, size,
          bgp_stats->fsm_established_transitions);
       break;
 
-    case BGP_INTERNAL_FSM_ESTABLISHED_TIME:
+    case BGP4_MIB_S_FSM_ESTABLISHED_TIME:
       pkt = snmp_varbind_gauge32(vb, size,
            (current_time() - bgp_proto->last_established) TO_S);
       break;
 
-    case BGP_INTERNAL_RETRY_INTERVAL:
-      // retry interval != 0
+    case BGP4_MIB_S_RETRY_INTERVAL: /* retry inverval value should be != 0 */
       pkt = snmp_varbind_int(vb, size, bgp_conf->connect_retry_time);
       break;
 
-    case BGP_INTERNAL_HOLD_TIME:
-      // (0, 3..65535)
+    case BGP4_MIB_S_HOLD_TIME: /* hold time should be == 0 or in 3..65535 */
       pkt = snmp_varbind_int(vb, size, (bgp_conn) ?  bgp_conn->hold_time : 0);
       break;
 
-    case BGP_INTERNAL_KEEPALIVE:
+    case BGP4_MIB_S_KEEPALIVE:
       if (!bgp_conf->hold_time)
        pkt = snmp_varbind_int(vb, size, 0);
       else
@@ -1110,11 +1009,11 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
          (bgp_conn) ? bgp_conn->keepalive_time : 0);
       break;
 
-    case BGP_INTERNAL_HOLD_TIME_CONFIGURED:
+    case BGP4_MIB_S_HOLD_TIME_CONFIGURED:
       pkt = snmp_varbind_int(vb, size, bgp_conf->hold_time);
       break;
 
-    case BGP_INTERNAL_KEEPALIVE_CONFIGURED:
+    case BGP4_MIB_S_KEEPALIVE_CONFIGURED:
       if (!bgp_conf->keepalive_time)
        pkt = snmp_varbind_int(vb, size, 0);
       else
@@ -1122,35 +1021,35 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
          (bgp_conn) ? bgp_conn->keepalive_time : 0);
       break;
 
-    case BGP_INTERNAL_ORIGINATION_INTERVAL:
-      // (1..65535) but is not supported
+    case BGP4_MIB_S_ORIGINATION_INTERVAL:
+      /* value should be in 1..65535 but is not supported by bird */
       pkt = snmp_varbind_int(vb, size, 0);
       break;
 
-    case BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT:
-      // (1..65535) but is not supported
+    case BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT:
+      /* value should be in 1..65535 but is not supported by bird */
       pkt = snmp_varbind_int(vb, size, 0);
       break;
 
-    case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
+    case BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME:
       pkt = snmp_varbind_gauge32(vb, size,
        (current_time() - bgp_proto->last_rx_update) TO_S
       );
       break;
 
-    case BGP_INTERNAL_END:
+    case BGP4_MIB_S_END:
       break;
 
-    case BGP_INTERNAL_INVALID:
+    case BGP4_MIB_S_INVALID:
       break;
 
-    case BGP_INTERNAL_BGP:
+    case BGP4_MIB_S_BGP:
       break;
-    case BGP_INTERNAL_PEER_TABLE:
+    case BGP4_MIB_S_PEER_TABLE:
       break;
-    case BGP_INTERNAL_PEER_ENTRY:
+    case BGP4_MIB_S_PEER_ENTRY:
       break;
-    case BGP_INTERNAL_NO_VALUE:
+    case BGP4_MIB_S_NO_VALUE:
       break;
   }
 
@@ -1176,7 +1075,7 @@ UNUSED, uint contid UNUSED, u8 state)
    * snmp_bgp_state() check only prefix. To be sure on OID equivalence we need to
    * compare the oid->n_subid length. All BGP static fields have same n_subid.
    */
-  if (oid_state_compare(oid, state) < 0 || state == BGP_INTERNAL_END)
+  if (oid_state_compare(oid, state) < 0 || state == BGP4_MIB_S_END)
   {
     vb->type = AGENTX_NO_SUCH_OBJECT;
     return pkt + snmp_varbind_header_size(vb);
@@ -1189,15 +1088,15 @@ UNUSED, uint contid UNUSED, u8 state)
 
   switch (state)
   {
-    case BGP_INTERNAL_VERSION:
+    case BGP4_MIB_S_VERSION:
       pkt = snmp_varbind_nstr(vb, size, BGP4_VERSIONS, 1);
       break;
 
-    case BGP_INTERNAL_LOCAL_AS:
+    case BGP4_MIB_S_LOCAL_AS:
       pkt = snmp_varbind_int(vb, size, p->bgp_local_as);
       break;
 
-    case BGP_INTERNAL_IDENTIFIER:
+    case BGP4_MIB_S_IDENTIFIER:
       pkt = snmp_varbind_ip4(vb, size, p->bgp_local_id);
       break;
 
@@ -1231,19 +1130,10 @@ snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb,
     return;
   }
 
-  vb->type = AGENTX_NO_SUCH_OBJECT;  // TODO
+  vb->type = AGENTX_NO_SUCH_OBJECT;
   ADVANCE(c->buffer, c->size, snmp_varbind_header_size(vb));
 }
 
-#if 0
-int
-snmp_bgp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, void *tr, struct oid *oid, uint pkt_size)
-{
-  // TODO: check the type of varbind vb and it's value correctness, don't overflow the pkt_size
-  return 0;
-}
-#endif
-
 /*
  * snmp_bgp_start - prepare BGP4-MIB
  * @p - SNMP protocol instance holding memory pool
@@ -1261,9 +1151,6 @@ snmp_bgp_start(struct snmp_proto *p)
   WALK_LIST(b, cf->bgp_entries)
   {
     const struct bgp_config *bgp_config = (struct bgp_config *) b->config;
-    if (ipa_zero(bgp_config->remote_ip))
-      die("unsupported dynamic BGP");
-
     const struct bgp_proto *bgp = SKIP_BACK(struct bgp_proto, p,
       bgp_config->c.proto);
 
index 4fcd96aebb624d4a664fbea0f053feed8fabbef1..c044c0ef2583358d41ab13ec700e38c9b4e10412 100644 (file)
@@ -4,39 +4,41 @@
 #include "snmp.h"
 #include "subagent.h"
 
+#define BGP4_MIB 15
+
 /* peers attributes */
-enum BGP4_MIB_PEER_TABLE {
-  SNMP_BGP_PEER_IDENTIFIER         =  1,
-  SNMP_BGP_STATE                   =  2,
-  SNMP_BGP_ADMIN_STATUS                    =  3,   /* in read-only mode */
-  SNMP_BGP_NEGOTIATED_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,
-  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,
+enum bgp4_mib_peer_entry_row {
+  BGP4_MIB_PEER_IDENTIFIER         =  1,
+  BGP4_MIB_STATE                   =  2,
+  BGP4_MIB_ADMIN_STATUS                    =  3,   /* in read-only mode */
+  BGP4_MIB_NEGOTIATED_VERSION      =  4,
+  BGP4_MIB_LOCAL_ADDR              =  5,
+  BGP4_MIB_LOCAL_PORT              =  6,
+  BGP4_MIB_REMOTE_ADDR             =  7,
+  BGP4_MIB_REMOTE_PORT             =  8,
+  BGP4_MIB_REMOTE_AS               =  9,
+  BGP4_MIB_RX_UPDATES              = 10,   /* in updates */
+  BGP4_MIB_TX_UPDATES              = 11,   /* out updates */
+  BGP4_MIB_RX_MESSAGES             = 12,   /* in total messages */
+  BGP4_MIB_TX_MESSAGES             = 13,   /* out total messages */
+  BGP4_MIB_LAST_ERROR              = 14,
+  BGP4_MIB_FSM_TRANSITIONS         = 15,   /* FSM established transitions */
+  BGP4_MIB_FSM_ESTABLISHED_TIME            = 16,
+  BGP4_MIB_RETRY_INTERVAL          = 17,
+  BGP4_MIB_HOLD_TIME               = 18,
+  BGP4_MIB_KEEPALIVE               = 19,
+  BGP4_MIB_HOLD_TIME_CONFIGURED            = 20,
+  BGP4_MIB_KEEPALIVE_CONFIGURED            = 21,
+  BGP4_MIB_ORIGINATION_INTERVAL            = 22,   /* UNSUPPORTED - 0 */
+  BGP4_MIB_MIN_ROUTE_ADVERTISEMENT  = 23,   /* UNSUPPORTED - 0 */
+  BGP4_MIB_IN_UPDATE_ELAPSED_TIME   = 24,
 } PACKED;
 
 /* version of BGP, here BGP-4 */
 #define BGP4_VERSIONS ((char[]) { 0x10 }) /* OID bgp.bgpVersion */
 /* for OID bgp.bgpPeerTable.bgpPeerEntry.bgpPeerNegotiatedVersion */
-#define SNMP_BGP_NEGOTIATED_VER_VALUE 4
-#define SNMP_BGP_NEGOTIATED_VER_NO_VALUE 0
+#define BGP4_MIB_NEGOTIATED_VER_VALUE 4
+#define BGP4_MIB_NEGOTIATED_VER_NO_VALUE 0
 
 
 void snmp_bgp_register(struct snmp_proto *p);
@@ -46,66 +48,81 @@ void snmp_bgp_reg_failed(struct snmp_proto *p, struct agentx_response *r, struct
 u8 snmp_bgp_get_valid(u8 state);
 u8 snmp_bgp_getnext_valid(u8 state);
 
-struct oid *snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid);
-enum snmp_search_res snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid);
+enum snmp_search_res snmp_bgp_search(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid);
 void snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, struct snmp_pdu *c);
 //int snmp_bgp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, void* tr, struct oid *oid, uint pkt_type);
 
 void snmp_bgp_notify_established(struct snmp_proto *p, struct bgp_proto *bgp);
 void snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp);
 
-#define SNMP_BGP_VERSION    1
-#define SNMP_BGP_LOCAL_AS   2
-#define SNMP_BGP_PEER_TABLE 3
-#define SNMP_BGP_PEER_ENTRY   1
-#define SNMP_BGP_IDENTIFIER 4    /* BGP4-MIB::bgpIdentifier local router id */
-
-/* BGP linearized state */
-enum BGP_INTERNAL_STATES {
-  BGP_INTERNAL_INVALID = 0,
-  BGP_INTERNAL_START = 1,
-  BGP_INTERNAL_BGP,
-  BGP_INTERNAL_VERSION,
-  BGP_INTERNAL_LOCAL_AS,
-  BGP_INTERNAL_PEER_TABLE,
-  BGP_INTERNAL_PEER_ENTRY,
-  BGP_INTERNAL_PEER_IDENTIFIER,
-  BGP_INTERNAL_STATE,
-  BGP_INTERNAL_ADMIN_STATUS,
-  BGP_INTERNAL_NEGOTIATED_VERSION,
-  BGP_INTERNAL_LOCAL_ADDR,
-  BGP_INTERNAL_LOCAL_PORT,
-  BGP_INTERNAL_REMOTE_ADDR,
-  BGP_INTERNAL_REMOTE_PORT,
-  BGP_INTERNAL_REMOTE_AS,
-  BGP_INTERNAL_RX_UPDATES,
-  BGP_INTERNAL_TX_UPDATES,
-  BGP_INTERNAL_RX_MESSAGES,
-  BGP_INTERNAL_TX_MESSAGES,
-  BGP_INTERNAL_LAST_ERROR,
-  BGP_INTERNAL_FSM_TRANSITIONS,
-  BGP_INTERNAL_FSM_ESTABLISHED_TIME,
-  BGP_INTERNAL_RETRY_INTERVAL,
-  BGP_INTERNAL_HOLD_TIME,
-  BGP_INTERNAL_KEEPALIVE,
-  BGP_INTERNAL_HOLD_TIME_CONFIGURED,
-  BGP_INTERNAL_KEEPALIVE_CONFIGURED,
-  BGP_INTERNAL_ORIGINATION_INTERVAL,
-  BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT,
-  BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME,
-  BGP_INTERNAL_PEER_TABLE_END,
-  BGP_INTERNAL_IDENTIFIER,     /* local identification */
-  BGP_INTERNAL_END,
-  BGP_INTERNAL_NO_VALUE = 255,
+enum bgp4_mib_rows {
+  BGP4_MIB_VERSION    = 1,
+  BGP4_MIB_LOCAL_AS   = 2,
+  BGP4_MIB_PEER_TABLE = 3,    /* subtable */
+  BGP4_MIB_IDENTIFIER = 4,    /* BGP4-MIB::bgpIdentifier local router id */
+};
+
+enum bgp4_mib_peer_table_rows {
+  BGP4_MIB_PEER_ENTRY = 1,
+};
+
+enum bgp4_mib_linearized_states {
+  BGP4_MIB_S_INVALID = 0, /* state invalid */
+  BGP4_MIB_S_START = 1,
+  BGP4_MIB_S_BGP,
+  BGP4_MIB_S_VERSION,
+  BGP4_MIB_S_LOCAL_AS,
+  BGP4_MIB_S_PEER_TABLE,
+  BGP4_MIB_S_PEER_ENTRY,
+  BGP4_MIB_S_PEER_IDENTIFIER,
+  BGP4_MIB_S_STATE,
+  BGP4_MIB_S_ADMIN_STATUS,
+  BGP4_MIB_S_NEGOTIATED_VERSION,
+  BGP4_MIB_S_LOCAL_ADDR,
+  BGP4_MIB_S_LOCAL_PORT,
+  BGP4_MIB_S_REMOTE_ADDR,
+  BGP4_MIB_S_REMOTE_PORT,
+  BGP4_MIB_S_REMOTE_AS,
+  BGP4_MIB_S_RX_UPDATES,
+  BGP4_MIB_S_TX_UPDATES,
+  BGP4_MIB_S_RX_MESSAGES,
+  BGP4_MIB_S_TX_MESSAGES,
+  BGP4_MIB_S_LAST_ERROR,
+  BGP4_MIB_S_FSM_TRANSITIONS,
+  BGP4_MIB_S_FSM_ESTABLISHED_TIME,
+  BGP4_MIB_S_RETRY_INTERVAL,
+  BGP4_MIB_S_HOLD_TIME,
+  BGP4_MIB_S_KEEPALIVE,
+  BGP4_MIB_S_HOLD_TIME_CONFIGURED,
+  BGP4_MIB_S_KEEPALIVE_CONFIGURED,
+  BGP4_MIB_S_ORIGINATION_INTERVAL,
+  BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT,
+  BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME,
+  BGP4_MIB_S_PEER_TABLE_END,
+  BGP4_MIB_S_IDENTIFIER,       /* state local identification */
+  BGP4_MIB_S_END,
+  BGP4_MIB_S_NO_VALUE = 255,
 } PACKED;
 
+/* valid values for BGP4_MIB_STATE */
 enum bgp4_mib_bgp_states {
-  BGP_MIB_IDLE = 1,
-  BGP_MIB_CONNECT = 2,
-  BGP_MIB_ACTIVE = 3,
-  BGP_MIB_OPENSENT = 4,
-  BGP_MIB_OPENCONFIRM = 5,
-  BGP_MIB_ESTABLISHED = 6,
+  BGP4_MIB_IDLE = 1,
+  BGP4_MIB_CONNECT = 2,
+  BGP4_MIB_ACTIVE = 3,
+  BGP4_MIB_OPENSENT = 4,
+  BGP4_MIB_OPENCONFIRM = 5,
+  BGP4_MIB_ESTABLISHED = 6,
 };
 
+STATIC_ASSERT(BGP4_MIB_IDLE == BS_IDLE + 1);
+STATIC_ASSERT(BGP4_MIB_CONNECT == BS_CONNECT + 1);
+STATIC_ASSERT(BGP4_MIB_ACTIVE == BS_ACTIVE + 1);
+STATIC_ASSERT(BGP4_MIB_OPENSENT == BS_OPENSENT + 1);
+STATIC_ASSERT(BGP4_MIB_OPENCONFIRM == BS_OPENCONFIRM + 1);
+STATIC_ASSERT(BGP4_MIB_ESTABLISHED == BS_ESTABLISHED + 1);
+
+/* Traps OID sub-identifiers */
+#define BGP4_MIB_ESTABLISHED_NOTIFICATION 1
+#define BGP4_MIB_BACKWARD_TRANS_NOTIFICATION 2
+
 #endif
index fbff7270bb6f9b65635722d73b0246547b899e4e..fe7e8f5fbadd7af820c571913b5fc8b7f239428b 100644 (file)
@@ -1,5 +1,4 @@
-/*
- *     BIRD -- Simple Network Management Protocol (SNMP) *
+/**    BIRD -- Simple Network Management Protocol (SNMP) *
  *      (c) 2022 Vojtech Vilimek <vojtech.vilimek@nic.cz>
  *      (c) 2022 CZ.NIC z.s.p.o.
  *
@@ -134,7 +133,6 @@ static void snmp_cleanup(struct snmp_proto *p);
 static int
 snmp_rx_skip(sock UNUSED *sk, uint UNUSED size)
 {
-  log(L_INFO "snmp_rx_skip with size %u", size);
   return 1;
 }
 
@@ -144,29 +142,38 @@ snmp_rx_skip(sock UNUSED *sk, uint UNUSED size)
  *
  * The socket tx_hook is called when the TX-buffer is empty, i.e. all data was
  * send. This function is used only when we found malformed PDU and we are
- * resetting the established session. If called we direcly reset the session.
+ * resetting the established session. If called, we are reseting the session.
  */
 static void
 snmp_tx_skip(sock *sk)
 {
-  log(L_INFO "snmp_tx_skip()");
   struct snmp_proto *p = sk->data;
-  snmp_set_state(p, SNMP_DOWN);
+  proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
 }
 
 /*
  * snmp_set_state - change state with associated actions
  * @p - SNMP protocol instance
  * @state - new SNMP protocol state
+ *
+ * This function does not notify the bird about protocol state. It is therefore
+ * a responsibility of the caller to use the returned value appropriately.
+ *
+ * Return current protocol state.
  */
-void
+int
 snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
 {
   enum snmp_proto_state last = p->state;
 
   TRACE(D_EVENTS, "SNMP changing state to %u", state);
 
-  p->state = state;
+  if (state == SNMP_DOWN && (last == SNMP_REGISTER || last == SNMP_CONN))
+  {
+    /* We have a connection established (at least send out agentx-Open-PDU) */
+    state = SNMP_STOP;
+  }
+  /* else - We did not send any packet, we perform protocol cleanup only. */
 
   if (last == SNMP_RESET)
   {
@@ -174,10 +181,12 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
     p->sock = NULL;
   }
 
+  p->state = state;
+
   switch (state)
   {
   case SNMP_INIT:
-    debug("snmp -> SNMP_INIT\n");
+    DBG("snmp -> SNMP_INIT\n");
     ASSERT(last == SNMP_DOWN);
     struct object_lock *lock;
     lock = p->lock = olock_new(p->pool);
@@ -192,12 +201,11 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
     lock->hook = snmp_start_locked;
     lock->data = p;
     olock_acquire(lock);
-    break;
+    return PS_START;
 
   case SNMP_LOCKED:
-    debug("snmp -> SNMP_LOCKED\n");
+    DBG("snmp -> SNMP_LOCKED\n");
     ASSERT(last == SNMP_INIT || SNMP_RESET);
-    snmp_unset_header(p);
     sock *s = sk_new(p->pool);
     s->type = SK_TCP_ACTIVE;
     s->saddr = ipa_from_ip4(p->local_ip);
@@ -220,60 +228,56 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
       p->sock = NULL;
       tm_start(p->startup_timer, p->timeout);
     }
-    break;
+    return PS_START;
 
   case SNMP_OPEN:
-    debug("snmp -> SNMP_OPEN\n");
+    DBG("snmp -> SNMP_OPEN\n");
     ASSERT(last == SNMP_LOCKED);
     p->sock->rx_hook = snmp_rx;
     p->sock->tx_hook = NULL;
-    log(L_WARN " Staring subagent %u %u %u %u", p->header_offset, p->last_index, p->last_size, p->last_pkt_id);
     snmp_start_subagent(p);
     // handle no response (for long time)
-    break;
+    return PS_START;
 
   case SNMP_REGISTER:
-    debug("snmp -> SNMP_REGISTER\n");
+    DBG("snmp -> SNMP_REGISTER\n");
     ASSERT(last == SNMP_OPEN);
     snmp_register_mibs(p);
-    break;
+    return PS_START;
 
   case SNMP_CONN:
-    debug("snmp -> SNMP_CONN\n");
+    DBG("snmp -> SNMP_CONN\n");
     ASSERT(last == SNMP_REGISTER);
-    proto_notify_state(&p->p, PS_UP);
-    break;
+    return PS_UP;
 
   case SNMP_STOP:
-    debug("snmp -> SNMP_STOP\n");
+    DBG("snmp -> SNMP_STOP\n");
     ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
     snmp_stop_subagent(p);
     p->sock->rx_hook = snmp_rx_skip;
     p->sock->tx_hook = snmp_tx_skip;
     p->startup_timer->hook = snmp_stop_timeout;
     tm_start(p->startup_timer, p->timeout);
-    proto_notify_state(&p->p, PS_STOP);
-    break;
+    return PS_STOP;
 
   case SNMP_DOWN:
-    debug("snmp -> SNMP_DOWN\n");
-    //ASSUME(last == SNMP_STOP || SNMP_INIT || SNMP_LOCKED || SNMP_OPEN);
+    DBG("snmp -> SNMP_DOWN\n");
     snmp_cleanup(p);
     // FIXME: handle the state in which we call proto_notify_state and
     // immediately return PS_DOWN from snmp_shutdown()
-    proto_notify_state(&p->p, PS_DOWN);
-    break;
+    return PS_DOWN;
 
   case SNMP_RESET:
-    debug("snmp -> SNMP_RESET\n");
+    DBG("snmp -> SNMP_RESET\n");
     ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
     ASSUME(p->sock);
     p->sock->rx_hook = snmp_rx_skip;
     p->sock->tx_hook = snmp_tx_skip;
-    break;
+    return PS_STOP;
 
   default:
-    die("unknown state transition");
+    die("unknown snmp state transition");
+    return PS_DOWN;
   }
 }
 
@@ -281,7 +285,7 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
  * snmp_init - preinitialize SNMP instance
  * @CF - SNMP configuration generic handle
  *
- * Return value is generic handle pointing to preinitialized SNMP procotol
+ * Returns a generic handle pointing to preinitialized SNMP procotol
  * instance.
  */
 static struct proto *
@@ -344,24 +348,8 @@ snmp_cleanup(struct snmp_proto *p)
   p->bgp_trie = NULL;
 }
 
-#if 0
-/*
- * snmp_down - stop the SNMP protocol and free resources
- * @p - SNMP protocol instance
- *
- * AgentX session is destroyed by closing underlying socket and all resources
- * are freed. Afterwards, the PS_DOWN protocol state is announced.
- */
-void
-snmp_down(struct snmp_proto *p)
-{
-  snmp_cleanup(p);
-  proto_notify_state(&p->p, PS_DOWN);
-}
-#endif
-
 /*
- * snmp_connected - start AgentX session on established channel
+ * snmp_connected - start AgentX session on created socket
  * @sk - socket owned by SNMP protocol instance
  *
  * Starts the AgentX communication by sending an agentx-Open-PDU.
@@ -375,32 +363,18 @@ snmp_connected(sock *sk)
 }
 
 /*
- * snmp_sock_disconnect - end or reset socket connection
+ * snmp_reset - end the communication on AgentX session
  * @p - SNMP protocol instance
  *
- * If the @reconnect flags is set, we close the socket and then reestablish
- * the AgentX session by reentering the start procedure as from the
- * snmp_start_locked() function.
- * Otherwise we simply shutdown the SNMP protocol if the flag is clear.
+ * End the communication on AgentX session by downing the whole procotol. This
+ * causes socket closure that implies AgentX session disconnection.
  * This function is internal and shouldn't be used outside the SNMP module.
  */
 void
-snmp_sock_disconnect(struct snmp_proto *p, int reconnect)
+snmp_reset(struct snmp_proto *p)
 {
   tm_stop(p->ping_timer);
-
-  if (!reconnect)
-  {
-    snmp_set_state(p, SNMP_DOWN);
-    return;
-  }
-
-  // TODO - wouldn't be better to use inter jump state RESET (soft reset) ?
-  snmp_set_state(p, SNMP_DOWN);
-
-  /* We try to reconnect after a short delay */
-  //p->startup_timer->hook = snmp_startup_timeout;
-  //tm_start(p->startup_timer, 4); // TODO make me configurable
+  proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
 }
 
 /*
@@ -414,7 +388,7 @@ snmp_sock_err(sock *sk, int UNUSED err)
   struct snmp_proto *p = sk->data;
 
   TRACE(D_EVENTS, "SNMP socket error %d", err);
-  snmp_sock_disconnect(p, 1);
+  snmp_reset(p);
 }
 
 /*
@@ -444,79 +418,16 @@ snmp_start_locked(struct object_lock *lock)
  * snmp_reconnect - helper restarting the AgentX session on packet errors
  * @tm - the startup_timer holding the SNMP protocol instance
  *
- * Rerun the SNMP module start procedure. Used in situations when the master
- * agent returns an agentx-Response-PDU with 'Not Opened' error. We do not close
- * the socket if have one.
+ * Try to recover from an error by reseting the SNMP protocol. It is a simple
+ * snmp_reset() wrapper for timers.
  */
 void
 snmp_reconnect(timer *tm)
 {
   struct snmp_proto *p = tm->data;
-  // TODO
-  snmp_set_state(p, SNMP_DOWN);
+  snmp_reset(p);
   return;
-  /* reset the connection */
-  snmp_sock_disconnect(p, 1);
-  // TODO better snmp_set_state(SNMP_DOWM); ??
-  if (p->state == SNMP_STOP ||
-      p->state == SNMP_DOWN)
-    return;
-
-  // TO-DO is SNMP_RESET really needed ?
-  if (p->state == SNMP_INIT ||
-      p->state == SNMP_RESET)
-    //snmp_startup(p);
-    {}
-
-  if (!p->sock)
-    snmp_start_locked(p->lock);
-  else
-    snmp_connected(p->sock);
-}
-
-#if 0
-/*
- * snmp_startup - start initialized SNMP protocol
- * @p - SNMP protocol to start
- *
- * Starting of SNMP protocols begins with address acqusition through object
- * lock. Next step is handled by snmp_start_locked() function.
- * This function is internal and shouldn't be used outside the SNMP
- * module.
- */
-void
-snmp_startup(struct snmp_proto *p)
-{
-  // TODO inline to snmp_start()
-  if (p->state == SNMP_OPEN ||
-      p->state == SNMP_REGISTER ||
-      p->state == SNMP_CONN)
-  {
-    return;
-  }
-
-  if (p->lock)
-  {
-    snmp_start_locked(p->lock);
-    return;
-  }
-
-  p->state = SNMP_INIT;
-
-  struct object_lock *lock;
-  lock = p->lock = olock_new(p->pool);
-
-  // lock->addr
-  // lock->port
-  // lock->iface
-  // lock->vrf
-  lock->type = OBJLOCK_TCP;
-  lock->hook = snmp_start_locked;
-  lock->data = p;
-
-  olock_acquire(lock);
 }
-#endif
 
 /*
  * snmp_startup_timeout - start the initiliazed SNMP protocol
@@ -547,14 +458,15 @@ static void
 snmp_stop_timeout(timer *tm)
 {
   struct snmp_proto *p = tm->data;
-  snmp_set_state(p, SNMP_DOWN);
+  proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
 }
 
 /*
  * snmp_ping_timeout - send a agentx-Ping-PDU
  * @tm - the ping_timer holding the SNMP protocol instance.
  *
- * Send an agentx-Ping-PDU and reset the timer for next ping.
+ * Send an agentx-Ping-PDU. This function is periodically called by ping
+ * timer.
  */
 static void
 snmp_ping_timeout(timer *tm)
@@ -568,7 +480,7 @@ snmp_ping_timeout(timer *tm)
  * @P - SNMP protocol generic handle
  *
  * The first step in AgentX subagent startup is protocol initialition.
- * We must prepare lists, find BGP peers and finally asynchornously open
+ * We must prepare lists, find BGP peers and finally asynchronously open
  * a AgentX subagent session through snmp_startup() function call.
  */
 static int
@@ -584,7 +496,7 @@ snmp_start(struct proto *P)
   p->bgp_local_as = cf->bgp_local_as;
   p->bgp_local_id = cf->bgp_local_id;
   p->timeout = cf->timeout;
-  // add default value for startup_delay inside bison .Y file
+  // TODO add default value for startup_delay inside bison .Y file
   p->startup_delay = cf->startup_delay;
 
   p->pool = p->p.pool;
@@ -602,11 +514,7 @@ snmp_start(struct proto *P)
 
   snmp_bgp_start(p);
 
-  snmp_unset_header(p);
-
-  snmp_set_state(p, SNMP_INIT);
-
-  return PS_START;
+  return snmp_set_state(p, SNMP_INIT);
 }
 
 static inline int
@@ -647,23 +555,23 @@ skip:
  * @CF - SNMP protocol configuration generic handle carring new values
  *
  * We accept the reconfiguration if the new configuration @CF is identical with
- * the currently deployed. Otherwise we deny reconfiguration because
+ * the currently deployed configuration. Otherwise we deny reconfiguration because
  * the implementation would be cumbersome.
  */
 static int
 snmp_reconfigure(struct proto *P, struct proto_config *CF)
 {
-  // remove lost bonds, add newly created
   struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
   const struct snmp_config *new = SKIP_BACK(struct snmp_config, cf, CF);
 
+  /* We are searching for configuration changes */
   int retval = snmp_reconfigure_logic(p, new);
 
-  if (retval) {
+  if (retval)
+  {
     /* Reinitialize the hash after snmp_shutdown() */
     HASH_INIT(p->bgp_hash, p->pool, 10);
     snmp_bgp_start(p);
-    snmp_unset_header(p);
   }
 
   return retval;
@@ -683,7 +591,6 @@ snmp_show_proto_info(struct proto *P)
 
   // TODO move me into the bgp_mib.c
   cli_msg(-1006, "    BGP4-MIB");
-  // TODO enabled
   cli_msg(-1006, "      Local AS %u", p->bgp_local_as);
   cli_msg(-1006, "      Local router id %R", p->bgp_local_id);
   cli_msg(-1006, "      BGP peers");
@@ -726,20 +633,7 @@ static int
 snmp_shutdown(struct proto *P)
 {
   struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
-
-  if (p->state == SNMP_REGISTER ||
-      p->state == SNMP_CONN)
-  {
-    /* We have a connection established (at leased send out Open-PDU). */
-    snmp_set_state(p, SNMP_STOP);
-    return PS_STOP;
-  }
-  else
-  {
-    /* We did not create a connection, we clean the lock and other stuff. */
-    snmp_set_state(p, SNMP_DOWN);
-    return PS_DOWN;
-  }
+  return snmp_set_state(p, SNMP_DOWN);
 }
 
 
index 35f7817dde523b921748b1090040bd8663654839..cb80cdf4e7bb7bd03967ab209c0cb075e6a38a51 100644 (file)
@@ -29,6 +29,7 @@
 
 #define SNMP_RX_BUFFER_SIZE 8192
 #define SNMP_TX_BUFFER_SIZE 8192
+#define SNMP_PKT_SIZE_MAX 8192
 
 enum snmp_proto_state {
   SNMP_DOWN = 0,
@@ -60,11 +61,15 @@ struct snmp_config {
   btime timeout;
   btime startup_delay;
   u8 priority;
-  //struct iface *iface;
+  //struct iface *iface;  TODO
   u32 bonds;
-  const char *description;
-  list bgp_entries;
-  // TODO add support for subagent oid identification
+  const char *description;       /* The order of fields is not arbitrary */
+  list bgp_entries;              /* We want dynamically allocated fields to be
+                                  * at the end of the config struct.
+                                  * We use this fact to check differences of
+                                  * nonallocated parts of configs with memcpy
+                                  */
+  //const struct oid *oid_identifier;  TODO 
 };
 
 #define SNMP_BGP_P_REGISTERING 0x01
@@ -109,13 +114,6 @@ struct snmp_proto {
 
   sock *sock;
 
-  /* Partial packet processing */
-  uint header_offset;            /* offset of PDU header in TX-buffer during
-                                  * partial parsing */
-  uint last_index;               /* stores last index during partial parsing */
-  uint last_size;                /* number of bytes used inside TX-buffer */
-  uint last_pkt_id;              /* stores packetId to use for partial packet */
-
 
   btime timeout;                 /* timeout is part of MIB registration. It
                                    specifies how long should the master
@@ -147,8 +145,8 @@ void snmp_startup(struct snmp_proto *p);
 void snmp_connected(sock *sk);
 void snmp_startup_timeout(timer *tm);
 void snmp_reconnect(timer *tm);
-void snmp_sock_disconnect(struct snmp_proto *p, int reconnect);
-void snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state);
+int snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state);
 
+void snmp_reset(struct snmp_proto *p);
 
 #endif
index cc78f85eabc1f060671d691f359fe2da8ae61d83..5e706dbb454bf91a874e4c7cbab02af9df37a7bb 100644 (file)
 #include "snmp_utils.h"
 
 inline void
-snmp_pdu_context(const struct snmp_proto *p, struct snmp_pdu *pdu, sock *sk)
+snmp_pdu_context(struct snmp_pdu *pdu, sock *sk)
 {
   pdu->error = AGENTX_RES_NO_ERROR;
-  if (!snmp_is_partial(p))
-  {
-    pdu->buffer = sk->tpos;
-    pdu->size = sk->tbuf + sk->tbsize - sk->tpos;
-    pdu->index = 0;
-    return;
-  }
-
-  pdu->buffer = sk->tbuf + p->header_offset + p->last_size;
-  pdu->size = sk->tbuf + sk->tbsize - pdu->buffer;
-  pdu->index = p->last_index;
+  pdu->buffer = sk->tpos;
+  pdu->size = sk->tbuf + sk->tbsize - sk->tpos;
+  pdu->index = 0;
 }
 
+/**
+ * snmp_session - store packet ids from protocol to header
+ * @p: source SNMP protocol instance
+ * @h: dest PDU header
+ */
 inline void
 snmp_session(const struct snmp_proto *p, struct agentx_header *h)
 {
   STORE_U32(h->session_id, p->session_id);
   STORE_U32(h->transaction_id, p->transaction_id);
   STORE_U32(h->packet_id, p->packet_id);
-  //log(L_INFO "storing packet id %u into the header %p", p->packet_id, h);
 }
 
 inline int
@@ -42,17 +38,6 @@ snmp_has_context(const struct agentx_header *h)
   return h->flags & AGENTX_NON_DEFAULT_CONTEXT;
 }
 
-inline byte *
-snmp_add_context(struct snmp_proto *p, struct agentx_header *h, uint contid)
-{
-  u8 flags = LOAD_U8(h->flags);
-  STORE_U8(h->flags, flags | AGENTX_NON_DEFAULT_CONTEXT);
-  // TODO append the context after the header
-  (void)p;
-  (void)contid;
-  return (void *)h + AGENTX_HEADER_SIZE;
-}
-
 inline void *
 snmp_varbind_data(const struct agentx_varbind *vb)
 {
@@ -64,11 +49,12 @@ snmp_varbind_data(const struct agentx_varbind *vb)
  * snmp_is_oid_empty - check if oid is null-valued
  * @oid: object identifier to check
  *
- * Test if the oid header is full of zeroes. For @oid NULL returns 0.
+ * Test if the oid header is full of zeroes. For NULL-pointer @oid returns 0.
  */
 int
 snmp_is_oid_empty(const struct oid *oid)
 {
+  /* We intentionaly ignore padding that should be zeroed */
   if (oid != NULL)
     return LOAD_U8(oid->n_subid) == 0 && LOAD_U8(oid->prefix) == 0 &&
        LOAD_U8(oid->include) == 0;
@@ -96,9 +82,9 @@ void
 snmp_oid_copy(struct oid *dest, const struct oid *src)
 {
   STORE_U8(dest->n_subid, src->n_subid);
-  STORE_U8(dest->prefix,  src->prefix);
+  STORE_U8(dest->prefix, src->prefix);
   STORE_U8(dest->include, src->include ? 1 : 0);
-  STORE_U8(dest->pad,    0);
+  STORE_U8(dest->reserved, 0);
 
   for (int i = 0; i < LOAD_U8(src->n_subid); i++)
     STORE_U32(dest->ids[i], src->ids[i]);
@@ -118,7 +104,7 @@ snmp_oid_duplicate(pool *pool, const struct oid *oid)
 }
 
 /**
- * create new null oid (blank)
+ * snmp_oid_blank - create new null oid (blank)
  * @p: pool hodling snmp_proto structure
  */
 struct oid *
@@ -128,10 +114,10 @@ snmp_oid_blank(struct snmp_proto *p)
 }
 
 /**
- * snmp_str_size_from_len - return in-buffer octet-string size
+ * snmp_str_size_from_len - return in-buffer octet string size
  * @len: length of C-string, returned from strlen()
  */
-size_t
+inline size_t
 snmp_str_size_from_len(uint len)
 {
   return 4 + BIRD_ALIGN(len, 4);
@@ -157,7 +143,7 @@ snmp_str_size(const char *str)
 uint
 snmp_oid_size(const struct oid *o)
 {
-  return 4 + (o->n_subid * 4);
+  return 4 + (LOAD_U8(o->n_subid) * 4);
 }
 
 /**
@@ -165,7 +151,7 @@ snmp_oid_size(const struct oid *o)
  * @n_subid: number of ids in oid
  */
 inline size_t
-snmp_oid_sizeof(uint n_subid)
+snmp_oid_size_from_len(uint n_subid)
 {
   return sizeof(struct oid) + n_subid * sizeof(u32);
 }
@@ -319,6 +305,32 @@ snmp_varbind_size(const struct agentx_varbind *vb, uint limit)
   }
 }
 
+/**
+ * snmp_varbind_size_from_len - get size in-buffer VarBind for known OID and data
+ * @n_subid: number of subidentifiers of the VarBind's OID name
+ * @type: type of VarBind
+ * @len: length of variably long data
+ *
+ * For types with fixed size the @len is not used. For types such as Octet
+ * String, or OID the @len is used directly.
+ *
+ * Return number of bytes used by VarBind in specified form.
+ */
+inline size_t
+snmp_varbind_size_from_len(uint n_subid, enum agentx_type type, uint len)
+{
+  size_t sz = snmp_oid_size_from_len(n_subid)
+    + sizeof(struct agentx_varbind) - sizeof(struct oid);
+
+  int data_sz = agentx_type_size(type);
+  if (data_sz < 0)
+    sz += len;
+  else
+    sz += data_sz;
+
+  return sz;
+}
+
 /*
  * snmp_test_varbind - test validity of VarBind's type
  * @vb: VarBind to test
@@ -369,7 +381,7 @@ struct agentx_varbind *
 snmp_create_varbind(byte *buf, struct oid *oid)
 {
   struct agentx_varbind *vb = (void *) buf;
-  STORE_U16(vb->pad, 0);
+  STORE_U16(vb->reserved, 0);
   snmp_oid_copy(&vb->name, oid);
   return vb;
 }
@@ -391,7 +403,7 @@ snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new)
 int
 snmp_valid_ip4_index(const struct oid *o, uint start)
 {
-  if (start + 3 < o->n_subid)
+  if (start + 3 < LOAD_U8(o->n_subid))
     return snmp_valid_ip4_index_unsafe(o, start);
   else
     return 0;
@@ -409,7 +421,7 @@ int
 snmp_valid_ip4_index_unsafe(const struct oid *o, uint start)
 {
   for (int i = 0; i < 4; i++)
-    if (o->ids[start + i] >= 256)
+    if (LOAD_U32(o->ids[start + i]) >= 256)
       return 0;
 
   return 1;
@@ -501,6 +513,14 @@ snmp_put_fbyte(byte *buf, u8 data)
   return buf + 3;
 }
 
+/*
+ * snmp_oid_ip4_index - OID append IPv4 index
+ * @o: OID to use
+ * @start: index of IP addr's MSB
+ * @addr: IPv4 address to use
+ *
+ * The indices from start to (inclusive) start+3 are overwritten by @addr bytes.
+ */
 void
 snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr)
 {
@@ -511,37 +531,6 @@ snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr)
   STORE_U32(o->ids[start + 3], temp & 0xFF);
 }
 
-void UNUSED
-snmp_oid_dump(const struct oid *oid)
-{
-  log(L_WARN "OID DUMP ========");
-
-  if (oid == NULL)
-  {
-    log(L_WARN "is eqaul to NULL");
-    log(L_WARN "OID DUMP END ====");
-    log(L_WARN ".");
-    return;
-  }
-
-  else if (snmp_is_oid_empty(oid))
-  {
-    log(L_WARN "is empty");
-    log(L_WARN "OID DUMP END ====");
-    log(L_WARN ".");
-    return;
-  }
-
-  log(L_WARN "  #ids: %4u  prefix %3u  include: %5s",
-    oid->n_subid, oid->prefix, (oid->include)? "true" : "false");
-  log(L_WARN "IDS -------------");
-
-  for (int i = 0; i < oid->n_subid; i++)
-    log(L_WARN "  %2u:  %11u  ~ 0x%08X", i, oid->ids[i], oid->ids[i]);
-
-  log(L_WARN "OID DUMP END ====");
-  log(L_WARN);
-}
 
 /** snmp_oid_compare - find the lexicographical order relation between @left and @right
  * both @left and @right has to be non-blank.
@@ -665,11 +654,13 @@ agentx_type_size(enum agentx_type type)
       type == AGENTX_INTEGER)
     return 4;
 
-  /* AGENTX_COUNTER_64 */
   if (type == AGENTX_COUNTER_64)
     return 8;
 
-  /* AGENTX_OBJECT_ID, AGENTX_OCTET_STRING, AGENTX_IP_ADDRESS, AGENTX_OPAQUE */
+  if (AGENTX_IP_ADDRESS)
+    return snmp_str_size_from_len(4);
+
+  /* AGENTX_OBJECT_ID, AGENTX_OCTET_STRING, AGENTX_OPAQUE */
   else
     return -1;
 }
@@ -759,78 +750,39 @@ snmp_test_close_reason(byte value)
     return 0;
 }
 
-inline struct agentx_header *
-snmp_create_tx_header(struct snmp_proto *p, byte *tbuf)
-{
-  /* the response is created always in TX-buffer */
-  p->header_offset = tbuf - p->sock->tbuf;
-  ASSERT(p->header_offset < p->sock->tbsize);
-  return (struct agentx_header *) tbuf;
-}
 
 /*
- * Partial header manipulation functions
+ *  Debugging
  */
 
-/*
- * snmp_is_partial - check if we have a partially parted packet in TX-buffer
- * @p: SNMP protocol instance
- */
-inline int
-snmp_is_partial(const struct snmp_proto *p)
+void UNUSED
+snmp_oid_dump(const struct oid *oid)
 {
-  return p->last_size > 0;
-}
+  log(L_WARN "OID DUMP ========");
 
-/*
- * snmp_get_header - restore partial packet's header from TX-buffer
- * @p: SNMP protocol instance
- */
-inline struct agentx_header *
-snmp_get_header(const struct snmp_proto *p)
-{
-  /* Nonzero last size indicates existence of partial packet */
-  ASSERT(p->last_size && p->header_offset < p->sock->tbsize);
-  return (struct agentx_header *) (p->sock->tbuf + p->header_offset);
-}
+  if (oid == NULL)
+  {
+    log(L_WARN "is eqaul to NULL");
+    log(L_WARN "OID DUMP END ====");
+    log(L_WARN ".");
+    return;
+  }
 
-/*
- * snmp_set_header - store partial packet's header into protocol
- * @p: SNMP protocol instance
- * @h: header of the currently parsed PDU
- * @c: SNMP PDU context
- *
- * Store the needed values regarding later partial PDU processing.
- */
-inline void
-snmp_set_header(struct snmp_proto *p, struct agentx_header *h, struct snmp_pdu *c)
-{
-  sock *sk = p->sock;
-  // TODO agentx_headier in last_size or not?
-  ASSERT(c->buffer - sk->tpos >= AGENTX_HEADER_SIZE);
-  p->last_size = c->buffer - sk->tpos + p->last_size;
-  p->header_offset = (((byte *) h) - sk->tbuf);
-  p->last_index = c->index;
-  log(L_INFO "using p->packet_id %u as a p->last_pkt_id %u", p->packet_id, p->last_pkt_id);
-  p->last_pkt_id = p->packet_id;
-  log(L_INFO "snmp_set_header() tbuf %p tpos %p buffer %p header %p header2 %p offset %u last_size %u last_index %u last_pkt_id %u",
-      sk->tbuf, sk->tpos, c->buffer,h,(byte*)h, p->header_offset, p->last_size,
-      p->last_index, p->last_pkt_id);
-}
+  else if (snmp_is_oid_empty(oid))
+  {
+    log(L_WARN "is empty");
+    log(L_WARN "OID DUMP END ====");
+    log(L_WARN ".");
+    return;
+  }
 
-/*
- * snmp_unset_header - clean partial packet's header
- * @p: SNMP protocol instance
- *
- * Clean the partial packet processing fields of protocol when the packet is
- * fully processed.
- */
-inline void
-snmp_unset_header(struct snmp_proto *p)
-{
-  p->last_size = 0;
-  p->header_offset = 0;
-  p->last_index = 0;
-  p->last_pkt_id = 0;
-}
+  log(L_WARN "  #ids: %4u  prefix %3u  include: %5s",
+    oid->n_subid, oid->prefix, (oid->include)? "true" : "false");
+  log(L_WARN "IDS -------------");
 
+  for (int i = 0; i < oid->n_subid; i++)
+    log(L_WARN "  %2u:  %11u  ~ 0x%08X", i, oid->ids[i], oid->ids[i]);
+
+  log(L_WARN "OID DUMP END ====");
+  log(L_WARN);
+}
index 52ba14787a7118cbb3915746c8e3b63ba104f92e..3026f77a5dd075d245d48b3b6b207865e92c7135 100644 (file)
@@ -4,78 +4,94 @@
 #include "subagent.h"
 
 uint snmp_pkt_len(const byte *start, const byte *end);
+
+/*
+ *
+ *    AgentX Variable Biding (VarBind) utils
+ *
+ */
+
+/*
+ *  AgentX - Variable Binding (VarBind) type utils
+ */
+void snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t);
+enum agentx_type snmp_get_varbind_type(const struct agentx_varbind *vb);
+int agentx_type_size(enum agentx_type t);
+
+/* type Octet String */
 size_t snmp_str_size_from_len(uint len);
 size_t snmp_str_size(const char *str);
+
+/* type OID - Object Identifier */
 int snmp_is_oid_empty(const struct oid *oid);
+uint snmp_oid_size(const struct oid *o);
+size_t snmp_oid_size_from_len(uint n_subid);
+void snmp_oid_copy(struct oid *dest, const struct oid *src);
+int snmp_oid_compare(const struct oid *first, const struct oid *second);
+
+/* type IPv4 */
 int snmp_valid_ip4_index(const struct oid *o, uint start);
 int snmp_valid_ip4_index_unsafe(const struct oid *o, uint start);
-uint snmp_oid_size(const struct oid *o);
-size_t snmp_oid_sizeof(uint n_subid);
+void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr);
+
+/*
+ *  AgentX - Variable Binding (VarBind) manupulation
+ */
 uint snmp_varbind_hdr_size_from_oid(const struct oid *oid);
 uint snmp_varbind_header_size(const struct agentx_varbind *vb);
 uint snmp_varbind_size(const struct agentx_varbind *vb, uint limit);
 uint snmp_varbind_size_unsafe(const struct agentx_varbind *vb);
+size_t snmp_varbind_size_from_len(uint n_subid, enum agentx_type t, uint len);
 int snmp_test_varbind(const struct agentx_varbind *vb);
+void *snmp_varbind_data(const struct agentx_varbind *vb);
+
+/*
+ *  AgentX - PDU headers, types, contexts
+ */
 void snmp_session(const struct snmp_proto *p, struct agentx_header *h);
 int snmp_has_context(const struct agentx_header *h);
-void snmp_pdu_context(const struct snmp_proto *p, struct snmp_pdu *pdu, sock *sk);
-
-void snmp_oid_copy(struct oid *dest, const struct oid *src);
-
+void snmp_pdu_context(struct snmp_pdu *pdu, sock *sk);
 struct oid *snmp_oid_duplicate(pool *pool, const struct oid *oid);
 struct oid *snmp_oid_blank(struct snmp_proto *p);
 
-void *snmp_varbind_data(const struct agentx_varbind *vb);
+int snmp_test_close_reason(byte value);
+
+/*
+ *  AgentX - TX buffer manipulation
+ */
+
+/* Functions filling buffer a typed value */
 struct agentx_varbind *snmp_create_varbind(byte *buf, struct oid *oid);
 struct agentx_varbind *snmp_create_varbind_null(byte *buf);
-byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new);
-
-int snmp_oid_compare(const struct oid *first, const struct oid *second);
+byte *snmp_varbind_int(struct agentx_varbind *vb, uint size, u32 val);
+byte *snmp_varbind_counter32(struct agentx_varbind *vb, uint size, u32 val);
+byte *snmp_varbind_gauge32(struct agentx_varbind *vb, uint size, s64 val);
+byte *snmp_varbind_ticks(struct agentx_varbind *vb, uint size, u32 val);
+byte *snmp_varbind_ip4(struct agentx_varbind *vb, uint size, ip4_addr addr);
+byte *snmp_varbind_nstr(struct agentx_varbind *vb, uint size, const char *str, uint len);
 
+/* Raw */
 byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid);
 byte *snmp_no_such_instance(byte *buf, struct agentx_varbind *vb, struct oid *oid);
-
 byte *snmp_put_str(byte *buf, const char *str);
 byte *snmp_put_nstr(byte *buf, const char *str, uint len);
 byte *snmp_put_blank(byte *buf);
 byte *snmp_put_oid(byte *buf, struct oid *oid);
-
 byte *snmp_put_ip4(byte *buf, ip4_addr ip4);
-
 byte *snmp_put_fbyte(byte *buf, u8 data);
 
-void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr);
-
-void snmp_oid_dump(const struct oid *oid);
-
-void snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t);
-enum agentx_type snmp_get_varbind_type(const struct agentx_varbind *vb);
-
-//struct oid *snmp_prefixize(struct snmp_proto *p, struct oid *o);
 
+/*
+ *
+ *    Helpers, Misc, Debugging
+ *
+ */
 struct snmp_registration *snmp_registration_create(struct snmp_proto *p, u8 mib_class);
 int snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, u8 class);
 
-/* Functions filling buffer a typed value */
-byte *snmp_varbind_int(struct agentx_varbind *vb, uint size, u32 val);
-byte *snmp_varbind_counter32(struct agentx_varbind *vb, uint size, u32 val);
-byte *snmp_varbind_gauge32(struct agentx_varbind *vb, uint size, s64 val);
-byte *snmp_varbind_ticks(struct agentx_varbind *vb, uint size, u32 val);
-byte *snmp_varbind_ip4(struct agentx_varbind *vb, uint size, ip4_addr addr);
-byte *snmp_varbind_nstr(struct agentx_varbind *vb, uint size, const char *str, uint len);
-
 void snmp_dump_packet(byte *pkt, uint size);
+void snmp_oid_dump(const struct oid *oid);
 
 enum agentx_type snmp_search_res_to_type(enum snmp_search_res res);
 
-int agentx_type_size(enum agentx_type t);
-
-int snmp_test_close_reason(byte value);
-
-struct agentx_header *snmp_create_tx_header(struct snmp_proto *p, byte *rbuf);
-int snmp_is_partial(const struct snmp_proto *p);
-struct agentx_header *snmp_get_header(const struct snmp_proto *p);
-void snmp_set_header(struct snmp_proto *p, struct agentx_header *h, struct snmp_pdu *c);
-void snmp_unset_header(struct snmp_proto *p);
-
 #endif
diff --git a/proto/snmp/splitter.py b/proto/snmp/splitter.py
new file mode 100755 (executable)
index 0000000..ebd4f34
--- /dev/null
@@ -0,0 +1,92 @@
+#! /bin/env python3
+
+"""
+A very simple script used to test that BIRD does not segfaults on randomly split
+AgentX PDUs.
+"""
+
+import socket
+import random
+import time
+import math
+
+ADDRESS = "127.0.0.1"
+PORT = 5000
+AGENTX_MASTER_PORT = 705
+
+def chunks(lst, n):
+    l = len(lst)
+    for i in range(0, l, n):
+        yield lst[i: min(i+n, l)]
+
+def print_msg(header, msg, total):
+    print(header, "{}/{}".format(len(msg), total))
+    for line in chunks(msg, 16):
+        print("  ", end="")
+        for char in line:
+            print("0x{:02x} ".format(char), end="")
+
+        print()
+
+def create_listen():
+    tun = socket.socket()
+    print(f"Binding to port {PORT} on {ADDRESS}")
+    tun.bind((ADDRESS, PORT))
+    print(f"Listening on {ADDRESS} port {PORT}")
+    tun.listen(2)
+
+    return tun
+
+def io_loop(rx, tx):
+    while True:
+        try:
+            to_master = rx.recv(8192)
+        except BlockingIOError:
+            to_master = None
+
+        try:
+            to_subagent = tx.recv(8192)
+        except BlockingIOError:
+            to_subagent = None
+
+        if to_master is not None and len(to_master) > 0:
+            print_msg("S=>M: ", to_master, len(to_master))
+            tx.send(to_master)
+
+        if to_subagent is not None and len(to_subagent) > 0:
+            limit = 5 * len(to_subagent) / 100
+            part_len = random.randint(math.ceil(limit),
+                       math.floor(len(to_subagent) - limit))
+
+            print(f"M->S: {len(to_subagent[:part_len])}/{len(to_subagent)}")
+            rx.send(to_subagent[:part_len])
+            time.sleep(0.4)
+            print_msg("M=>S: ", to_subagent, len(to_subagent))
+            rx.send(to_subagent[part_len:])
+
+        time.sleep(0.02)
+
+def safe_io_loop(tun):
+    while True:
+        try:
+            rx, addr = tun.accept()
+            print("Subagent connected")
+
+            tx = socket.socket()
+            tx.connect((ADDRESS, AGENTX_MASTER_PORT))
+            print("Connected to master agent")
+
+            rx.setblocking(False)
+            tx.setblocking(False)
+
+            io_loop(rx, tx)
+        except BrokenPipeError:
+            rx.close()
+            tx.close()
+
+def main():
+    with create_listen() as listening:
+        safe_io_loop(listening)
+
+if __name__ == '__main__':
+        main()
index 5da01bafe0de577b95ae131ef740926da6b568db..c25155b50fbe053f955ce68d44b9ee0fab2f96ee 100644 (file)
  */
 
 static void snmp_mib_fill2(struct snmp_proto *p, struct oid *oid, struct snmp_pdu *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);
-static uint parse_gets2_pdu(struct snmp_proto *p, byte *buf, uint size, uint *skip);
+static uint parse_response(struct snmp_proto *p, byte *buf);
+static void do_response(struct snmp_proto *p, byte *buf);
+static uint parse_gets_pdu(struct snmp_proto *p, byte *pkt);
 static struct agentx_response *prepare_response(struct snmp_proto *p, struct snmp_pdu *c);
 static void response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_response_errs err, u16 ind);
-static uint update_packet_size(struct snmp_proto *p, struct agentx_header *start, byte *end);
+static uint update_packet_size(struct agentx_header *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 *c, enum snmp_search_res *result);
 
 u32 snmp_internet[] = { SNMP_ISO, SNMP_ORG, SNMP_DOD, SNMP_INTERNET };
@@ -80,20 +80,36 @@ snmp_is_active(struct snmp_proto *p)
       p->state == SNMP_CONN;
 }
 
+/*
+ * snmp_header - store packet information into buffer
+ * @h: pointer to created packet header in TX-buffer
+ * @type: created PDU type
+ * @flags: set flags
+ *
+ * Payload length is set to zero legth. Padding is also zeroed. Real stored
+ * flags are dependent on compile-time message byte-order configuration.
+ */
 static inline void
 snmp_header(struct agentx_header *h, enum agentx_pdu_types type, u8 flags)
 {
   STORE_U8(h->version, AGENTX_VERSION);
-  STORE_U8(h->type, (u8) type);
+  STORE_U8(h->type, type);
   STORE_U8(h->flags, flags | SNMP_ORDER);
-  STORE_U8(h->pad, 0);
+  STORE_U8(h->reserved, 0);
   STORE_U32(h->payload, 0);
 }
 
+/*
+ * snmp_blank_header - create header with no flags except default
+ * @h: pointer to created header in TX-buffer
+ * @type: create PDU type
+ *
+ * Only flag possibly set may be packet byte order configuration.
+ */
 static inline void
 snmp_blank_header(struct agentx_header *h, enum agentx_pdu_types type)
 {
-  snmp_header(h, type, 0);
+  snmp_header(h, type, (u8) 0);
 }
 
 /*
@@ -109,7 +125,7 @@ snmp_blank_header(struct agentx_header *h, enum agentx_pdu_types type)
 static void
 snmp_register_ok(struct snmp_proto *p, struct agentx_response *res, struct oid *oid, u8 UNUSED class)
 {
-  // TODO switch based on oid type
+  // todo switch based on oid type
   snmp_bgp_reg_ok(p, res, oid);
 }
 
@@ -120,21 +136,21 @@ snmp_register_ok(struct snmp_proto *p, struct agentx_response *res, struct oid *
  * @oid: OID whose registration failed
  * @class: MIB subtree of @oid
  *
- * Send a notification to MIB (selected by @class) about @oid registraion
+ * Send a notification to MIB (selected by @class) about @oid registration
  * failure.
  */
 static void
 snmp_register_failed(struct snmp_proto *p, struct agentx_response *res, struct oid *oid, u8 UNUSED class)
 {
-  // TODO switch based on oid type
+  // todo switch based on oid type
   snmp_bgp_reg_failed(p, res, oid);
 }
 
 /*
- * snmp_register_ack - handle registration -- response to agentx-Register-PDU
+ * snmp_register_ack - handle registration response
  * @p: SNMP protocol instance
  * @res: header of agentx-Response-PDU
- * @class: MIB subtree associated with agentx-Register-PDU
+ * @class: MIB subtree associated with agentx-Register-PDU 
  */
 void
 snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class)
@@ -142,7 +158,7 @@ snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class)
   struct snmp_registration *reg;
   WALK_LIST(reg, p->registration_queue)
   {
-    // TODO add support for more mib trees (other than BGP)
+    // todo add support for more mib trees (other than BGP4-MIB)
     if (snmp_registration_match(reg, &res->h, class))
     {
       struct snmp_registered_oid *ro = \
@@ -179,14 +195,15 @@ snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class)
 static inline void
 snmp_error(struct snmp_proto *p)
 {
-  snmp_set_state(p, SNMP_RESET);
+  snmp_reset(p);
+  //snmp_set_state(p, SNMP_RESET);
 }
 
 /*
  * snmp_simple_response - send an agentx-Response-PDU with no data payload
  * @p: SNMP protocol instance
- * @error: PDU error fields value
- * @index: PDU error index field value
+ * @error: response PDU error fields value
+ * @index: response PDU error index field value
  *
  * This function assumes that the buffer has enough space to fill in the AgentX
  * Response PDU. So it is the responsibility of the caller to provide that.
@@ -196,7 +213,7 @@ snmp_simple_response(struct snmp_proto *p, enum agentx_response_errs error, u16
 {
   sock *sk = p->sock;
   struct snmp_pdu c;
-  snmp_pdu_context(p, &c, sk);
+  snmp_pdu_context(&c, sk);
 
   ASSUME(c.size >= sizeof(struct agentx_response));
 
@@ -220,14 +237,16 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
   sock *sk = p->sock;
 
   struct snmp_pdu c;
-  snmp_pdu_context(p, &c, sk);
+  snmp_pdu_context(&c, sk);
 
-#define TIMEOUT_SIZE 4 /* 1B timeout, 3B zero padding */
+#define TIMEOUT_SIZE sizeof(u32) /* 1B timeout, 3B zero padding */
+
+  /* Make sure that we have enough space in TX-buffer */
   if (c.size < AGENTX_HEADER_SIZE + TIMEOUT_SIZE + snmp_oid_size(oid) +
       + snmp_str_size(cf->description))
     snmp_manage_tbuf(p, &c);
 
-  struct agentx_header *h = snmp_create_tx_header(p, c.buffer);
+  struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
   snmp_blank_header(h, AGENTX_OPEN_PDU);
 
@@ -250,7 +269,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
   c.buffer = snmp_put_oid(c.buffer, oid);
   c.buffer = snmp_put_str(c.buffer, cf->description);
 
-  uint s = update_packet_size(p, h, c.buffer);
+  uint s = update_packet_size(h, c.buffer);
   sk_send(sk, s);
 #undef TIMEOUT_SIZE
 }
@@ -269,7 +288,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
   sock *sk = p->sock;
 
   struct snmp_pdu c;
-  snmp_pdu_context(p, &c, sk);
+  snmp_pdu_context(&c, sk);
 
 #define UPTIME_SIZE \
   (6 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[4] } ) */
@@ -282,14 +301,14 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
   if (include_uptime)
     sz += UPTIME_SIZE;
 
+  /* Make sure that we have enough space in TX-buffer */
   if (c.size < sz)
     snmp_manage_tbuf(p, &c);
 
-  struct agentx_header *h = snmp_create_tx_header(p, c.buffer);
+  struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
   snmp_blank_header(h, AGENTX_NOTIFY_PDU);
-  p->packet_id++;
-  log(L_INFO "incrementing packet_id to %u (notify)", p->packet_id);
+  p->packet_id++;   /* New packet id */
   snmp_session(p, h);
 
   if (include_uptime)
@@ -299,7 +318,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
       .n_subid = 4,
       .prefix = SNMP_MGMT,
       .include = 0,
-      .pad = 0,
+      .reserved = 0,
     };
     /* {mgmt}.mib-2.system.sysUpTime.sysUpTimeInstance (0) */
     u32 uptime_ids[] = { 1, 1, 3, 0 };
@@ -308,7 +327,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
     for (uint i = 0; i < uptime_oid.n_subid; i++)
       STORE_U32(vb->name.ids[i], uptime_ids[i]);
 
-    /* TODO: use time from last reconfiguration instead? [config->load_time] */
+    /* TODO use time from last reconfiguration instead? [config->load_time] */
     btime uptime = current_time() - boot_time;
     snmp_varbind_ticks(vb, c.size, (uptime TO_S) / 100);
     ASSUME(snmp_test_varbind(vb));
@@ -320,7 +339,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
     .n_subid = 6,
     .prefix = 6, /* snmpV2 */
     .include = 0,
-    .pad = 0,
+    .reserved = 0,
   };
   /* {snmpV2}.snmpModules.snmpAlarmNextIndex.snmpMIBObjects.snmpTrap.snmpTrapIOD.0 */
   u32 trap0_ids[] = { 3, 1, 1, 4, 1, 0 };
@@ -335,7 +354,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
   memcpy(c.buffer, data, size);
   ADVANCE(c.buffer, c.size, size);
 
-  uint s = update_packet_size(p, h, c.buffer);
+  uint s = update_packet_size(h, c.buffer);
   sk_send(sk, s);
 
 #undef TRAP0_HEADER_SIZE
@@ -365,27 +384,27 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
  * see snmp_register() and snmp_unregister() functions.
  */
 static void
-un_register_pdu(struct snmp_proto *p, struct oid *oid, uint bound, uint index, enum agentx_pdu_types type, u8 is_instance, uint UNUSED contid)
+un_register_pdu(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, enum agentx_pdu_types type, u8 is_instance, uint UNUSED contid)
 {
   /* used for agentx-Register-PDU and agentx-Unregister-PDU */
   const struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf);
   sock *sk = p->sock;
   struct snmp_pdu c;
-  snmp_pdu_context(p, &c, sk);
+  snmp_pdu_context(&c, sk);
 
+#define BOUND_SIZE sizeof(u32)
   /* conditional +4 for upper-bound (optinal field) */
-  uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) + ((bound > 1) ? 4 : 0);
+  uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) + 
+      ((bound > 1) ? BOUND_SIZE : 0);
 
   if (c.size < sz)
     snmp_manage_tbuf(p, &c);
 
-  struct agentx_header *h = snmp_create_tx_header(p, c.buffer);
+  struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
 
   snmp_header(h, type, is_instance ? AGENTX_FLAG_INSTANCE_REGISTRATION : 0);
   p->packet_id++;
-  log(L_INFO "incementing the packet_id to %u (%s)", p->packet_id, type ==
-    AGENTX_REGISTER_PDU ? "register" : "unregister");
   snmp_session(p, h);
 
   struct agentx_un_register_hdr *ur = (struct agentx_un_register_hdr *) c.buffer;
@@ -395,7 +414,7 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint bound, uint index, e
   /* use selected priority */
   STORE_U8(ur->priority, cf->priority);
   STORE_U8(ur->range_subid, (bound > 1) ? index : 0);
-  STORE_U8(ur->pad, 0);
+  STORE_U8(ur->reserved, 0);
   ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_hdr));
 
   snmp_put_oid(c.buffer, oid);
@@ -405,12 +424,13 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint bound, uint index, e
   if (bound > 1)
   {
     STORE_PTR(c.buffer, bound);
-    ADVANCE(c.buffer, c.size, 4);
+    ADVANCE(c.buffer, c.size, BOUND_SIZE);
   }
 
-  uint s = update_packet_size(p, h, c.buffer);
+  uint s = update_packet_size(h, c.buffer);
 
   sk_send(sk, s);
+#undef BOUND_SIZE
 }
 
 /*
@@ -425,9 +445,8 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint bound, uint index, e
  * For more detailed description see un_register_pdu() function.
  */
 void
-snmp_register(struct snmp_proto *p, struct oid *oid, uint bound, uint index, u8 is_instance, uint contid)
+snmp_register(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, u8 is_instance, uint contid)
 {
-  log(L_INFO "performing a registration");
   un_register_pdu(p, oid, bound, index, AGENTX_REGISTER_PDU, is_instance, contid);
 }
 
@@ -442,9 +461,9 @@ snmp_register(struct snmp_proto *p, struct oid *oid, uint bound, uint index, u8
  * For more detailed description see un_register_pdu() function.
  */
 void UNUSED
-snmp_unregister(struct snmp_proto *p, struct oid *oid, uint len, uint index, uint contid)
+snmp_unregister(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, uint contid)
 {
-  un_register_pdu(p, oid, len, index, AGENTX_UNREGISTER_PDU, 0, contid);
+  un_register_pdu(p, oid, bound, index, AGENTX_UNREGISTER_PDU, 0, contid);
 }
 
 /*
@@ -452,28 +471,27 @@ snmp_unregister(struct snmp_proto *p, struct oid *oid, uint len, uint index, uin
  * @p: SNMP protocol instance
  * @reason: reason for closure
  */
-static void
+static void UNUSED
 close_pdu(struct snmp_proto *p, enum agentx_close_reasons reason)
 {
   sock *sk = p->sock;
   struct snmp_pdu c;
-  snmp_pdu_context(p, &c, sk);
+  snmp_pdu_context(&c, sk);
 
-#define REASON_SIZE 4
+#define REASON_SIZE sizeof(u32)
   if (c.size < AGENTX_HEADER_SIZE + REASON_SIZE)
     snmp_manage_tbuf(p, &c);
 
-  struct agentx_header *h = snmp_create_tx_header(p, c.buffer);
+  struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
   snmp_blank_header(h, AGENTX_CLOSE_PDU);
   p->packet_id++;
-  log(L_INFO "incrementing packet_id %u (close)", p->packet_id);
   snmp_session(p, h);
 
   snmp_put_fbyte(c.buffer, (u8) reason);
   ADVANCE(c.buffer, c.size, 4);
 
-  uint s = update_packet_size(p, h, c.buffer);
+  uint s = update_packet_size(h, c.buffer);
   sk_send(sk, s);
 #undef REASON_SIZE
 }
@@ -482,40 +500,40 @@ close_pdu(struct snmp_proto *p, enum agentx_close_reasons reason)
  * parse_close_pdu - parse an agentx-Close-PDU
  * @p: SNMP protocol instance
  * @pkt_start: pointer to first byte of PDU
- * @size: number of bytes received from a socket
  *
  * Return number of bytes parsed from RX-buffer.
  */
 static uint
-parse_close_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
+parse_close_pdu(struct snmp_proto *p, byte * const pkt_start)
 {
   TRACE(D_PACKETS, "SNMP received agentx-Close-PDU");
   byte *pkt = pkt_start;
 
-  if (size < sizeof(struct agentx_close_pdu))
+  struct agentx_close_pdu *pdu = (void *) pkt;
+  pkt += sizeof(struct agentx_close_pdu);
+  uint pkt_size = pdu->h.payload;
+
+  if (pkt_size != sizeof(struct agentx_close_pdu))
   {
     TRACE(D_PACKETS, "SNMP malformed agentx-Close-PDU, closing anyway");
     snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
     snmp_set_state(p, SNMP_RESET);
-    return size;
+    return MIN(pkt_size + AGENTX_HEADER_SIZE, sizeof(struct agentx_close_pdu));
   }
 
-  struct agentx_close_pdu *pdu = (void *) pkt;
-  ADVANCE(pkt, size, sizeof(struct agentx_close_pdu));
-
   if (!snmp_test_close_reason(pdu->reason))
   {
-    TRACE(D_PACKETS, "SNMP invalid close reason");
+    TRACE(D_PACKETS, "SNMP invalid close reason %u", pdu->reason);
     snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
     snmp_set_state(p, SNMP_RESET);
-    return sizeof(struct agentx_close_pdu);
+    return pkt_size + AGENTX_HEADER_SIZE;
   }
 
   enum agentx_close_reasons reason = (enum agentx_close_reasons) pdu->reason;
   TRACE(D_PACKETS, "SNMP close reason %u", reason);
   snmp_simple_response(p, AGENTX_RES_NO_ERROR, 0);
   snmp_set_state(p, SNMP_RESET);
-  return sizeof(struct agentx_close_pdu);
+  return pkt_size + AGENTX_HEADER_SIZE;
 }
 
 
@@ -540,7 +558,8 @@ snmp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, struct oid *
 {
   /* Hard-coded no support for writing */
   (void)p;(void)vb;(void)oid;(void)pkt_size;
-  return 0;
+  snmp_simple_response(p, AGENTX_RES_NOT_WRITABLE, 1);
+  return pkt_size + AGENTX_HEADER_SIZE;
 #if 0
   if (!oid)
     return 0;
@@ -565,7 +584,6 @@ refresh_ids(struct snmp_proto *p, struct agentx_header *h)
 {
   p->transaction_id = LOAD_U32(h->transaction_id);
   p->packet_id = LOAD_U32(h->packet_id);
-  //log(L_INFO "loading packet_id %u from header %p", p->packet_id, h);
 }
 
 /*
@@ -576,8 +594,8 @@ refresh_ids(struct snmp_proto *p, struct agentx_header *h)
  *
  * Return number of bytes parsed from RX-buffer.
  */
-static uint
-parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
+static inline uint
+parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start)
 {
   TRACE(D_PACKETS, "SNMP received agentx-TestSet-PDU");
   byte *pkt = pkt_start;  /* pointer to agentx-TestSet-PDU in RX-buffer */
@@ -585,15 +603,12 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
   struct agentx_response *res; /* pointer to reponse in TX-buffer */
 
   struct agentx_header *h = (void *) pkt;
-  ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
-  uint pkt_size = LOAD_U32(h->payload);
-
-  if (pkt_size < size)
-    return 0;
+  pkt += AGENTX_HEADER_SIZE;
+  //uint pkt_size = LOAD_U32(h->payload);
 
   sock *sk = p->sock;
   struct snmp_pdu c;
-  snmp_pdu_context(p, &c, sk);
+  snmp_pdu_context(&c, sk);
 
   if (c.size < AGENTX_HEADER_SIZE)
     snmp_manage_tbuf(p, &c);
@@ -618,10 +633,6 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
     vb = (void *) pkt;
     sz = snmp_varbind_size(vb, size);
 
-    if (sz > size)
-    /* wait for more data to arive */
-      return 0;
-
     if (sz > pkt_size)
     {
       c.error = AGENTX_RES_PARSE_ERROR;
@@ -646,7 +657,7 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
   }
   mb_free(tr);
 #endif
-  s = update_packet_size(p, h, c.buffer);
+  s = update_packet_size(h, c.buffer);
 
   if (c.error != AGENTX_RES_NO_ERROR)
   {
@@ -673,46 +684,38 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
  * parse_sets_pdu - common functionality for commit set and undo set PDUs
  * @p: SNMP protocol instance
  * @pkt_start: pointer to first byte of on of set related PDU
- * @size: number of bytes received from a socket
  * @error: error status to use
  *
  * Return number of bytes parsed from RX-buffer.
  */
 static uint
-parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, enum agentx_response_errs err)
+parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, enum agentx_response_errs err)
 {
   byte *pkt = pkt_start;
   struct agentx_header *h = (void *) pkt;
-  ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
+  pkt += AGENTX_HEADER_SIZE;
   uint pkt_size = LOAD_U32(h->payload);
 
   if (pkt_size != 0)
   {
     TRACE(D_PACKETS, "SNMP received malformed set PDU (size)");
     snmp_simple_response(p, AGENTX_RES_PARSE_ERROR, 0);
-    // TODO: best solution for possibly malicious pkt_size
-    return MIN(size, pkt_size + AGENTX_HEADER_SIZE);
+    // TODO best solution for possibly malicious pkt_size
+    return AGENTX_HEADER_SIZE;
     // use varbind_list_size()??
   }
 
   struct snmp_pdu c;
-  snmp_pdu_context(p, &c, p->sock);
+  snmp_pdu_context(&c, p->sock);
   if (c.size < sizeof(struct agentx_response))
     snmp_manage_tbuf(p, &c);
 
   struct agentx_response *r = prepare_response(p, &c);
 
-  if (size < pkt_size)
-  {
-    c.error = AGENTX_RES_PARSE_ERROR;
-  }
-  else
-  {
-    // TODO: free resource allocated by parse_test_set_pdu()
-    // TODO: do something meaningful
-    //mb_free(tr);
-    c.error = err;
-  }
+  // TODO free resource allocated by parse_test_set_pdu()
+  // TODO do something meaningful
+  //mb_free(tr);
+  c.error = err;
 
   TRACE(D_PACKETS, "SNMP received set PDU with error %u", c.error);
   response_err_ind(p, r, c.error, 0);
@@ -729,51 +732,47 @@ parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, enum age
  * parse_commit_set_pdu - parse an agentx-CommitSet-PDU
  * @p: SNMP protocol instance
  * @pkt: pointer to first byte of PDU inside RX-buffer
- * @size: number of bytes received from a socket
  *
  * Return number of bytes parsed from RX-buffer.
  */
-static uint
-parse_commit_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
+static inline uint
+parse_commit_set_pdu(struct snmp_proto *p, byte *pkt)
 {
   // don't forget to free resoures allocated by parse_test_set_pdu()
   //mb_free(tr);
   TRACE(D_PACKETS, "SNMP received agentx-CommitSet-PDU");
-  return parse_sets_pdu(p, pkt, size, AGENTX_RES_COMMIT_FAILED);
+  return parse_sets_pdu(p, pkt, AGENTX_RES_COMMIT_FAILED);
 }
 
 /*
  * parse_undo_set_pdu - parse an agentx-UndoSet-PDU
  * @p: SNMP protocol instance
  * @pkt: pointer to first byte of PDU inside RX-buffer
- * @size: number of bytes received from a socket
  *
  * Return number of bytes parsed from buffer.
  */
-static uint
-parse_undo_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
+static inline uint
+parse_undo_set_pdu(struct snmp_proto *p, byte *pkt)
 {
   // don't forget to free resources allocated by parse_test_set_pdu()
   //mb_free(tr);
   TRACE(D_PACKETS, "SNMP received agentx-UndoSet-PDU");
-  return parse_sets_pdu(p, pkt, size, AGENTX_RES_UNDO_FAILED);
+  return parse_sets_pdu(p, pkt, AGENTX_RES_UNDO_FAILED);
 }
 
 /*
  * parse_cleanup_set_pdu - parse an agentx-CleanupSet-PDU
  * @p: SNMP protocol instance
  * @pkt_start: pointer to first byte of PDU inside RX-buffer
- * @size: number of bytes received from a socket
  *
  * Return number of bytes parsed from RX-buffer.
  */
 static uint
-parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
+parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start)
 {
   TRACE(D_PACKETS, "SNMP received agentx-CleanupSet-PDU");
   (void)p;
-  //TODO:
-  // don't forget to free resources allocated by parse_test_set_pdu()
+  // TODO don't forget to free resources allocated by parse_test_set_pdu()
   //mb_free(p->tr);
 
   byte *pkt = pkt_start;
@@ -784,7 +783,7 @@ parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
   if (pkt_size != 0)
   {
     // TODO should we free even for malformed packets ??
-    return MIN(size, pkt_size + AGENTX_HEADER_SIZE);
+    return AGENTX_HEADER_SIZE;
   }
 
   /* No agentx-Response-PDU is sent in response to agentx-CleanupSet-PDU */
@@ -812,12 +811,11 @@ space_for_response(const sock *sk)
  * @p: SNMP protocol instance
  * @pkt: first byte of PDU inside RX-buffer
  * @size: number of bytes received from a socket
- * @skip: length of header that stays still in partial processing
  *
  * Return number of bytes parsed from RX-buffer.
  */
 static uint
-parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip)
+parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
 {
   /* TX-buffer free space */
   ASSERT(snmp_is_active(p));
@@ -831,21 +829,29 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip)
   struct agentx_header *h = (void *) pkt;
   uint pkt_size = LOAD_U32(h->payload);
 
+  /* RX side checks - too big packet */
   if (pkt_size > SNMP_PKT_SIZE_MAX)
-    return simple_response(p, AGENTX_RES_GEN_ERR, 0);
+  {
+    snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
+    snmp_reset(p);
+    return 0; // TODO return size??
+  }
+
+  /* This guarantees that we have the full packet already received */
+  if (size < pkt_size + AGENTX_HEADER_SIZE)
+    return 0; /* no bytes parsed */
 
   /* We need to see the responses for PDU such as
    * agentx-Open-PDU, agentx-Register-PDU, ...
    * even when we are outside the SNMP_CONNECTED state
    */
   if (h->type == AGENTX_RESPONSE_PDU)
-    return parse_response(p, pkt, size);
+    return parse_response(p, pkt);
 
   ASSERT(snmp_is_active(p));
   if (p->state != SNMP_CONN ||
       p->session_id != LOAD_U32(h->session_id))
   {
-    // TODO: resolve issues connected to partial processed packets
     struct agentx_header copy = {
       .session_id = p->session_id,
       .transaction_id = p->transaction_id,
@@ -864,14 +870,14 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip)
      * After unexpected state, we simply reset the session
      * only sending the agentx-Response-PDU.
      */
-    snmp_set_state(p, SNMP_RESET);
-    return 0;
+    snmp_reset(p);
+    return 0; // return size??
   }
 
   ASSERT(snmp_is_active(p));
   if (h->flags & AGENTX_NON_DEFAULT_CONTEXT)
   {
-    // TODO: add non-default context support
+    // TODO add non-default context support
     TRACE(D_PACKETS, "SNMP received PDU with unexpected byte order");
     snmp_simple_response(p, AGENTX_RES_UNSUPPORTED_CONTEXT, 0);
     /* We always accept the packet length as correct, up to set limit */
@@ -885,22 +891,22 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip)
     case AGENTX_GET_PDU:
     case AGENTX_GET_NEXT_PDU:
     case AGENTX_GET_BULK_PDU:
-      return parse_gets2_pdu(p, pkt, size, skip);
+      return parse_gets_pdu(p, pkt);
 
     case AGENTX_CLOSE_PDU:
-      return parse_close_pdu(p, pkt, size);
+      return parse_close_pdu(p, pkt);
 
     case AGENTX_TEST_SET_PDU:
-      return parse_test_set_pdu(p, pkt, size);
+      return parse_test_set_pdu(p, pkt);
 
     case AGENTX_COMMIT_SET_PDU:
-      return parse_commit_set_pdu(p, pkt, size);
+      return parse_commit_set_pdu(p, pkt);
 
     case AGENTX_UNDO_SET_PDU:
-      return parse_undo_set_pdu(p, pkt, size);
+      return parse_undo_set_pdu(p, pkt);
 
     case AGENTX_CLEANUP_SET_PDU:
-      return parse_cleanup_set_pdu(p, pkt, size);
+      return parse_cleanup_set_pdu(p, pkt);
 
     default:
       /* We reset the connection for malformed packet (Unknown packet type) */
@@ -915,39 +921,34 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip)
  * parse_response - parse an agentx-Response-PDU
  * @p: SNMP protocol instance
  * @res: pointer of agentx-Response-PDU header in RX-buffer
- * @size: number of bytes received from a socket
  *
  * Return number of bytes parsed from RX-buffer.
  */
 static uint
-parse_response(struct snmp_proto *p, byte *res, uint size)
+parse_response(struct snmp_proto *p, byte *res)
 {
-  log(L_WARN "parse response");
-  if (size < sizeof(struct agentx_response))
-    return 0;
-
   struct agentx_response *r = (void *) res;
   struct agentx_header *h = (void *) r;
 
   // todo reject not compiled byte order
   uint pkt_size = LOAD_U32(h->payload);
-  if (size < pkt_size + AGENTX_HEADER_SIZE)
-    return 0;
 
   switch (r->error)
   {
     case AGENTX_RES_NO_ERROR:
       TRACE(D_PACKETS, "SNMP received agetnx-Response-PDU");
-      do_response(p, res, size);
+      do_response(p, res);
       break;
 
     /* Registration errors */
     case AGENTX_RES_DUPLICATE_REGISTER:
     case AGENTX_RES_REQUEST_DENIED:
     case AGENTX_RES_UNKNOWN_REGISTER:
-      // TODO: more direct path to mib-specifiec code
+      // TODO more direct path to mib-specific code
       TRACE(D_PACKETS, "SNMP received agentx-Response-PDU with error %u", r->error);
-      snmp_register_ack(p, r, size);
+      byte *pkt = res + sizeof(struct agentx_response);
+      struct oid *failed = (void *) pkt;
+      snmp_register_ack(p, r, snmp_get_mib_class(failed));
       break;
 
     /*
@@ -984,15 +985,14 @@ snmp_register_mibs(struct snmp_proto *p)
 /*
  * do_response - act on agentx-Response-PDU and protocol state
  * @p: SNMP protocol instance
- * @buf: RX-buffer with PDU bytes
- * @size: number of bytes received from a socket
+ * @pkt: RX-buffer with PDU bytes
  *
  * Return number of bytes parsed from RX-buffer.
  */
 static void
-do_response(struct snmp_proto *p, byte *buf, uint size)
+do_response(struct snmp_proto *p, byte *pkt)
 {
-  struct agentx_response *r = (void *) buf;
+  struct agentx_response *r = (void *) pkt;
   struct agentx_header *h = (void *) r;
 
   /* TODO make it asynchronous for better speed */
@@ -1017,8 +1017,7 @@ do_response(struct snmp_proto *p, byte *buf, uint size)
       break;
 
     case SNMP_REGISTER:;
-      byte *pkt = buf;
-      ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
+      pkt += AGENTX_HEADER_SIZE;
 
       const struct oid *oid = (void *) pkt;
 
@@ -1205,14 +1204,13 @@ snmp_get_bulk2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end,
 
 /*
  * update_packet_size - set PDU size
- * @p - SNMP protocol instance
  * @start - pointer to PDU data start (excluding header size)
  * @end - pointer after the last PDU byte
  *
  * Return number of bytes in TX-buffer (including header size).
  */
 static inline uint
-update_packet_size(struct snmp_proto *p, struct agentx_header *start, byte *end)
+update_packet_size(struct agentx_header *start, byte *end)
 {
   uint s = snmp_pkt_len((byte *) start, end);
   STORE_U32(start->payload, s);
@@ -1254,32 +1252,40 @@ response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_
     STORE_U32(res->index, 0);
 }
 
+static uint
+parse_gets_error(struct snmp_proto *p, struct snmp_pdu *c, uint len)
+{
+  TRACE(D_PACKETS, "SNMP error %u while parsing gets PDU", c->error);
+  if (c->index > UINT16_MAX)
+    snmp_simple_response(p, AGENTX_RES_GEN_ERROR, UINT16_MAX);
+  else
+    snmp_simple_response(p, AGENTX_RES_GEN_ERROR, c->index);
+
+  return len + AGENTX_HEADER_SIZE;
+}
 /*
  * parse_gets_pdu - parse received gets PDUs
  * @p: SNMP protocol instance
  * @pkt_start: pointer to first byte of received PDU
- * @size: number of bytes received from a socket
- * @skip: length of header that stays still in partial processing
  *
  * Gets PDUs are agentx-Get-PDU, agentx-GetNext-PDU, agentx-GetBulk-PDU.
  *
  * Return number of bytes parsed from RX-buffer
  */
 static uint
-parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *skip)
+parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
 {
   // TODO checks for c.size underflow
-  uint ret = 0;
   struct oid *o_start = NULL, *o_end = NULL;
   byte *pkt = pkt_start;
 
   struct agentx_header *h = (void *) pkt;
-  ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
+  pkt += AGENTX_HEADER_SIZE;
   uint pkt_size = LOAD_U32(h->payload);
 
   sock *sk = p->sock;
   struct snmp_pdu c;
-  snmp_pdu_context(p, &c, sk);
+  snmp_pdu_context(&c, sk);
 
   /*
    * Get-Bulk processing stops if all the varbind have type END_OF_MIB_VIEW
@@ -1289,15 +1295,11 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s
   struct agentx_bulk_state bulk_state = { };
   if (h->type == AGENTX_GET_BULK_PDU)
   {
-    if (size < sizeof(struct agentx_getbulk))
-      goto wait;
-
     if (pkt_size < sizeof(struct agentx_getbulk))
     {
       c.error = AGENTX_RES_PARSE_ERROR;
       c.index = 0;
-      ret = pkt_size + AGENTX_HEADER_SIZE;
-      goto error;
+      return parse_gets_error(p, &c, pkt_size);
     }
 
     struct agentx_getbulk *bulk_info = (void *) pkt;
@@ -1316,38 +1318,19 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s
 
   struct agentx_response *response_header = prepare_response(p, &c);
 
-  while (c.error == AGENTX_RES_NO_ERROR && size > 0 && pkt_size > 0)
+  while (c.error == AGENTX_RES_NO_ERROR && pkt_size > 0)
   {
-    if (size < snmp_oid_sizeof(0))
-      goto partial;
-
     /* We load search range start OID */
     const struct oid *o_start_b = (void *) pkt;
     uint sz;
     if ((sz = snmp_oid_size(o_start_b)) > pkt_size)
     {
       c.error = AGENTX_RES_PARSE_ERROR;
-      ret = MIN(size, pkt_size + AGENTX_HEADER_SIZE);
-      goto error;
-    }
-
-    /*
-     * 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 received.
-     */
-    if (sz > size && c.index > 0)
-    {
-      goto partial;
-    }
-    else if (sz > size)
-    {
-      goto wait;
+      return parse_gets_error(p, &c, pkt_size);
     }
 
     /* Update buffer pointer and remaining size counters. */
     ADVANCE(pkt, pkt_size, sz);
-    size -= sz;
 
     /*
      * We load search range end OID
@@ -1358,24 +1341,12 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s
     if ((sz = snmp_oid_size(o_end_b)) > pkt_size)
     {
       c.error = AGENTX_RES_PARSE_ERROR;
-      ret = MIN(size, pkt_size + AGENTX_HEADER_SIZE);
-      goto error;
-    }
-
-    if (sz > size && c.index > 0)
-    {
-      size += snmp_oid_size(o_start_b);
-      goto partial;
-    }
-    else if (sz > size)
-    {
-      goto wait;
+      return parse_gets_error(p, &c, pkt_size);
     }
 
     ADVANCE(pkt, pkt_size, sz);
-    size -= sz;
 
-    // TODO check for oversized OIDs before any allocation (in prefixize())
+    /* We don't too to check for oversided OID because the PDU has 8k size limit */
 
     /* We create copy of OIDs outside of rx-buffer and also prefixize them */
     o_start = snmp_prefixize(p, o_start_b);
@@ -1387,11 +1358,12 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s
     if (!snmp_is_oid_empty(o_end) && snmp_oid_compare(o_start, o_end) > 0)
     {
       c.error = AGENTX_RES_GEN_ERROR;
-      ret = MIN(size, pkt_size + AGENTX_HEADER_SIZE);
-      goto error;
+      mb_free(o_start);
+      mb_free(o_end);
+      return parse_gets_error(p, &c, pkt_size);
     }
 
-    /* TODO find mib_class, check if type is GET of GET_NEXT, act acordingly */
+    /* TODO find mib_class, check if type is GET of GET_NEXT, act accordingly */
     switch (h->type)
     {
       case AGENTX_GET_PDU:
@@ -1441,61 +1413,18 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s
     }
   }
 
-  /* send the constructed packet */
-  struct agentx_response *res;
-  if (snmp_is_partial(p))
-  {
-    snmp_log("snmp_is_partial() <pkt> packet_id %u last_pkt_id %u [proto packet_id] %u", LOAD_U32(res->h.packet_id), p->last_pkt_id, p->packet_id);
-    res = SKIP_BACK(struct agentx_response, h, snmp_get_header(p));
-    ASSERT(LOAD_U32(res->h.packet_id) == p->last_pkt_id);
-    STORE_U32(res->h.packet_id, p->last_pkt_id);
-    snmp_unset_header(p);
-  }
-  else
-    res = response_header;
-
   /* We update the error, index pair on the beginning of the packet. */
-  response_err_ind(p, res, c.error, c.index + 1);
-  uint s = update_packet_size(p, &res->h, c.buffer);
+  response_err_ind(p, response_header, c.error, c.index + 1);
+  uint s = update_packet_size(&response_header->h, c.buffer);
 
   /* We send the message in TX-buffer. */
-  snmp_unset_header(p);
   sk_send(sk, s);
   // TODO think through the error state
 
   /* number of bytes parsed from RX-buffer */
-  ret = pkt - pkt_start;
-  goto free;
-
-partial:
-  /* need to tweak RX buffer packet size */
-  //STORE_U32(h->payload, pkt_size);
-  *skip = AGENTX_HEADER_SIZE;
-  snmp_set_header(p, &response_header->h, &c);
-
-  /* number of bytes parsed from RX-buffer */
-  ret = pkt - pkt_start;
-  /* update the packet length such that the used bytes are not included */
-  STORE_U32(h->payload, LOAD_U32(h->payload) - ret + AGENTX_HEADER_SIZE);
-  goto free;
-
-wait:
-  p->packet_id--; /* we did not use the packetID */
-  log(L_INFO "decrementing back the packet_id to %u", p->packet_id);
-  ret = 0;
-  goto free;
-
-error:
-  TRACE(D_PACKETS, "SNMP error %u while parsing gets PDU", c.error);
-  if (c.index > UINT16_MAX)
-    snmp_simple_response(p, AGENTX_RES_GEN_ERROR, UINT16_MAX);
-  else
-    snmp_simple_response(p, c.error, c.index);
-
-free:
   mb_free(o_start);
   mb_free(o_end);
-  return ret;
+  return pkt - pkt_start;
 }
 
 /*
@@ -1526,7 +1455,8 @@ void
 snmp_stop_subagent(struct snmp_proto *p)
 {
   tm_stop(p->ping_timer);
-  close_pdu(p, AGENTX_CLOSE_SHUTDOWN);
+  /* This cause problems with net-snmp daemon witch halts afterwards */
+  //close_pdu(p, AGENTX_CLOSE_SHUTDOWN);
 }
 
 /*
@@ -1542,38 +1472,25 @@ snmp_rx(sock *sk, uint size)
   byte *pkt_start = sk->rbuf;
   byte *end = pkt_start + size;
 
-  byte *last_pkt = pkt_start;
-
-  /*
-   * In some cases we want to save the header for future parsing, skip is number
-   * of bytes that should not be overriden by memmove()
-   */
-  uint skip = 0;
-
-  while (snmp_is_active(p) && end >= pkt_start + AGENTX_HEADER_SIZE && skip == 0)
+  while (snmp_is_active(p) && end >= pkt_start + AGENTX_HEADER_SIZE)
   {
-    uint parsed_len = parse_pkt(p, pkt_start, size, &skip);
+    uint parsed_len = parse_pkt(p, pkt_start, size);
 
     if (parsed_len == 0)
       break;
 
-    last_pkt = pkt_start;
     pkt_start += parsed_len;
     size -= parsed_len;
   }
 
-  if (!snmp_is_active(p))
-    return 1;
-
-  if (skip != 0 || pkt_start != end)
-  {
-    memmove(sk->rbuf, last_pkt, skip); /* maybe no op */
-    memmove(sk->rbuf + skip, pkt_start, size);
-    sk->rpos = sk->rbuf + size + skip;
-    return 0;
-  }
+  /* We flush the RX-buffer on errors */
+  if (!snmp_is_active(p) || pkt_start == end)
+    return 1; /* The whole RX-buffer was consumed */
 
-  return 1;
+  /* Incomplete packet parsing */
+  memmove(sk->rbuf, pkt_start, size);
+  sk->rpos = sk->rbuf + size;
+  return 0;
 }
 
 /*
@@ -1611,35 +1528,25 @@ snmp_ping(struct snmp_proto *p)
 
   sock *sk = p->sock;
   struct snmp_pdu c;
-  snmp_pdu_context(p, &c, sk);
+  snmp_pdu_context(&c, sk);
 
   if (c.size < AGENTX_HEADER_SIZE)
     return;
 
   int unused = sk->tbuf + sk->tbsize - c.buffer;
-  if (snmp_is_partial(p) && unused >= AGENTX_HEADER_SIZE)
-  {
-    /* We use the start of unsent TX-buffer to fit in the agentx-Ping-PDU */
-    memmove(sk->tpos + AGENTX_HEADER_SIZE, sk->tpos, p->last_size);
-    p->header_offset += AGENTX_HEADER_SIZE;
-  }
-  else if (snmp_is_partial(p))
-    /* Not enough space inside the buffer */
+  if (unused < AGENTX_HEADER_SIZE)
     return;
 
-  /* we do not use the snmp_create_tx_header() because of side effects */
-  struct agentx_header *h = (void *) sk->tpos;
+  //struct agentx_header *h = (void *) sk->tpos;
+  struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
   snmp_blank_header(h, AGENTX_PING_PDU);
   p->packet_id++;
   log(L_INFO "incrementing packet_id to %u (ping)", p->packet_id);
   snmp_session(p, h);
-  
-  if (snmp_is_partial(p)) // TODO remove me
-    snmp_log("snmp_ping() <pkt> packet_id %u last_pkt_id %u [proto packet_id] ))%u", LOAD_U32(h->packet), p->last_pkt_id, p->packet_id);
 
   /* sending only header */
-  uint s = update_packet_size(p, h, (byte *) h + AGENTX_HEADER_SIZE);
+  uint s = update_packet_size(h, (byte *) h + AGENTX_HEADER_SIZE);
 
   sk_send(sk, s);
 }
@@ -1714,7 +1621,7 @@ search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_
   switch (o_curr->ids[1])
   {
     case SNMP_BGP4_MIB:
-      r = snmp_bgp_search2(p, &o_curr, o_end, 0);
+      r = snmp_bgp_search(p, &o_curr, o_end, 0);
 
       if (r == SNMP_SEARCH_OK)
       {
@@ -1863,11 +1770,8 @@ snmp_manage_tbuf(struct snmp_proto UNUSED *p, struct snmp_pdu *c)
 static struct agentx_response *
 prepare_response(struct snmp_proto *p, struct snmp_pdu *c)
 {
-  if (snmp_is_partial(p))
-    return (struct agentx_response *) snmp_get_header(p);
-
   struct agentx_response *r = (void *) c->buffer;
-  struct agentx_header *h = snmp_create_tx_header(p, (byte *) r);
+  struct agentx_header *h = &r->h;
 
   snmp_blank_header(h, AGENTX_RESPONSE_PDU);
   snmp_session(p, h);
index c91206ea7c2dff2e3b73fd1cb322ea78c87ab631..b08519ff0aa6ac9f151b33635442f7a2d299b5a4 100644 (file)
@@ -151,7 +151,7 @@ struct agentx_header {
   u8 version;
   u8 type;
   u8 flags;
-  u8 pad;
+  u8 reserved;         /* always zero filled */
   u32 session_id;      /* AgentX sessionID established by Open-PDU */
   u32 transaction_id;  /* last transactionID seen/used */
   u32 packet_id;       /* last packetID seen/used */
@@ -165,13 +165,13 @@ struct oid {
   u8 n_subid;
   u8 prefix;
   u8 include;
-  u8 pad;
+  u8 reserved; /* always zero filled */
   u32 ids[];
 };
 
 struct agentx_varbind {
   u16 type;
-  u16 pad;
+  u16 reserved; /* always zero filled */
   /* oid part */
   struct oid name;
   /* AgentX variable binding data optionaly here */
@@ -205,15 +205,15 @@ STATIC_ASSERT(4 + 2 + 2 + AGENTX_HEADER_SIZE == sizeof(struct agentx_response));
 struct agentx_close_pdu {
   struct agentx_header h;
   u8 reason;
-  u8 pad1;
-  u16 pad2;
+  u8 reserved1; /* reserved u24 */
+  u16 reserved2; /* whole u24 is always zero filled */
 };
 
 struct agentx_un_register_hdr {
   u8 timeout;
   u8 priority;
   u8 range_subid;
-  u8 pad;
+  u8 reserved; /* always zero filled */
 };
 
 struct agentx_bulk_state {