]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
changes in bgp_mib.c API (mainly)
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Wed, 26 Jul 2023 12:02:23 +0000 (14:02 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Wed, 26 Jul 2023 12:02:23 +0000 (14:02 +0200)
proto/snmp/bgp_mib.c
proto/snmp/bgp_mib.h
proto/snmp/snmp_utils.c
proto/snmp/snmp_utils.h
proto/snmp/subagent.h

index 12fe859ed91912e1aaa0c6a0ebea8a5ce617320f..b46772d022060f627d009f3fadcdfa58961abbec 100644 (file)
@@ -194,17 +194,23 @@ bgp_get_candidate(u32 field)
   /* first value is in secord cell of array translation_table (as the
    * SNMP_BPG_IDENTIFIER == 1
    */
-  if (field > 0 && field < sizeof(translation_table) / sizeof(translation_table[0]))
+  if (field > 0 && field <= sizeof(translation_table) / sizeof(translation_table[0]))
     return translation_table[field];
+  if (field == 0)
+    return BGP_INTERNAL_INVALID;
   else
-    return BGP_INTERNAL_NO_VALUE;
+    return BGP_INTERNAL_END;
 }
 
 static inline struct ip4_addr
 ip4_from_oid(const struct oid *o)
 {
-  return (o->n_subid == 9) ? ip4_build(o->ids[5], o->ids[6], o->ids[7],
-o->ids[8]) : ip4_from_u32(0xFFFFFFFF);
+  return ip4_build(
+    o->n_subid > 5 ? (o->ids[5] & 0xff) : 0,
+    o->n_subid > 6 ? (o->ids[6] & 0xff) : 0,
+    o->n_subid > 7 ? (o->ids[7] & 0xff) : 0,
+    o->n_subid > 8 ? (o->ids[8] & 0xff) : 0
+  );
 }
 
 static void
@@ -283,6 +289,9 @@ snmp_bgp_state(struct oid *oid)
    *   -> BGP4-MIB::bgp (root)
    */
 
+  if (snmp_is_oid_empty(oid))
+    return BGP_INTERNAL_END;
+
   u8 state = BGP_INTERNAL_NO_VALUE;
 
   u8 candidate;
@@ -374,15 +383,10 @@ snmp_bgp_has_value(u8 state)
   if (state <= BGP_INTERNAL_BGP ||
       state == BGP_INTERNAL_PEER_TABLE ||
       state == BGP_INTERNAL_PEER_ENTRY ||
-
-      /* unsupported fields */
-      state == BGP_INTERNAL_FSM_ESTABLISHED_TIME ||
-      state == BGP_INTERNAL_ORIGINATION_INTERVAL ||
-      state == BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT ||
-      state == BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME)
-    return 0; /* hasn't value */
+      state >= BGP_INTERNAL_END)
+    return 0;
   else
-    return 1; /* has value */
+    return 1;
 }
 
 /**
@@ -423,15 +427,8 @@ snmp_bgp_next_state(u8 state)
     case BGP_INTERNAL_PEER_ENTRY:
       return BGP_INTERNAL_IDENTIFIER;
 
-    case BGP_INTERNAL_FSM_TRANSITIONS:
-    case BGP_INTERNAL_FSM_ESTABLISHED_TIME:
-      return BGP_INTERNAL_RETRY_INTERVAL;
-
-
     case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
-
     case BGP_INTERNAL_END:
-
       return BGP_INTERNAL_END;
 
     default:
@@ -445,20 +442,19 @@ snmp_bgp_is_supported(struct oid *o)
   /* most likely not functioning */
   if (o->prefix == 2 && o->n_subid > 0 && o->ids[0] == 1)
   {
-    if (o->n_subid == 2 && o->ids[1] == BGP4_MIB_VERSION ||
-        o->ids[1] == BGP4_MIB_LOCAL_AS)
+    if (o->n_subid == 2 && (o->ids[1] == BGP4_MIB_VERSION ||
+        o->ids[1] == BGP4_MIB_LOCAL_AS))
       return 1;
     else if (o->n_subid > 2 && o->ids[1] == BGP4_PEER_TABLE &&
              o->ids[2] == BGP4_PEER_ENTRY)
     {
        if (o->n_subid == 3)
          return 1;
-       if (o->n_subid == 8 &&
-           o->ids[3] > 0 &&
+       if (o->n_subid == 8 && o->ids[3] > 0)
            /* do not include bgpPeerInUpdatesElapsedTime
               and bgpPeerFsmEstablishedTime */
-           o->ids[3] < SNMP_BGP_IN_UPDATE_ELAPSED_TIME &&
-           o->ids[3] != SNMP_BGP_FSM_ESTABLISHED_TIME)
+          //&& o->ids[3] < SNMP_BGP_IN_UPDATE_ELAPSED_TIME
+          //&& o->ids[3] != SNMP_BGP_FSM_ESTABLISHED_TIME)
              return 1;
     }
     else
@@ -468,50 +464,127 @@ snmp_bgp_is_supported(struct oid *o)
   return 0;
 }
 
+static int
+oid_state_compare(const struct oid *oid, u8 state)
+{
+  ASSUME(oid != NULL);
+  if (state >= BGP_INTERNAL_IDENTIFIER &&
+      state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME)
+    return (oid->n_subid > 9) - (oid->n_subid < 9);
+  if (state >= BGP_INTERNAL_VERSION && state <= BGP_INTERNAL_PEER_TABLE)
+    return (oid->n_subid > 3) - (oid->n_subid < 3);
+  if (state == BGP_INTERNAL_PEER_ENTRY)
+    return (oid->n_subid > 4) - (oid->n_subid < 4);
+  if (state == BGP_INTERNAL_BGP)
+    return (oid->n_subid > 2) - (oid->n_subid < 2);
+
+  return -1;
+}
+
 static struct oid *
 update_bgp_oid(struct oid *oid, u8 state)
 {
-  ASSERT (state != BGP_INTERNAL_INVALID);
-  ASSERT (state != BGP_INTERNAL_NO_VALUE);
-  ASSERT (state != BGP_INTERNAL_END);
+  snmp_log("update_bgp_oid()");
+  if (state == BGP_INTERNAL_END || state == BGP_INTERNAL_INVALID ||
+      state == BGP_INTERNAL_NO_VALUE)
+    return oid;
 
   /* if same state, no need to realloc anything */
   if (snmp_bgp_state(oid) == state)
-    return oid;
+  {
+    if (state >= BGP_INTERNAL_IDENTIFIER &&
+       state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME &&
+       oid->n_subid == 9)
+      return oid;
+    if (state >= BGP_INTERNAL_VERSION &&
+       state <= BGP_INTERNAL_PEER_TABLE && oid->n_subid == 3)
+      return oid;
+    if (state == BGP_INTERNAL_PEER_ENTRY && oid->n_subid == 4)
+      return oid;
+    if (state == BGP_INTERNAL_BGP && oid->n_subid == 2)
+      return oid;
+  }
 
+  snmp_log("update work");
   switch (state)
   {
     case BGP_INTERNAL_BGP:
       /* could destroy same old data */
-      oid = mb_realloc(oid, snmp_oid_sizeof(2));
+      if (oid->n_subid != 2)
+      {
+       snmp_log("realloc");
+       oid = mb_realloc(oid, snmp_oid_sizeof(2));
+       snmp_log("/realloc");
+      }
+
       oid->n_subid = 2;
       oid->ids[0] = 1;
       oid->ids[1] = SNMP_BGP4_MIB;
       break;
 
     case BGP_INTERNAL_VERSION:
-      oid = mb_realloc(oid, snmp_oid_sizeof(3));
+      if (oid->n_subid != 3)
+      { snmp_log("realloc");
+       oid = mb_realloc(oid, snmp_oid_sizeof(3));
+      snmp_log("/realloc"); }
+
       oid->n_subid = 3;
       oid->ids[2] = SNMP_BGP_VERSION;
       break;
 
     case BGP_INTERNAL_LOCAL_AS:
+      if (oid->n_subid != 3)
+      { snmp_log("realloc");
+       oid = mb_realloc(oid, snmp_oid_sizeof(3));
+      snmp_log("/realloc"); }
+
+      oid->n_subid = 3;
       oid->ids[2] = 2;
       break;
 
     case BGP_INTERNAL_IDENTIFIER:
-      oid = mb_realloc(oid, snmp_oid_sizeof(9));
-      oid->n_subid = 9;
+      if (oid->n_subid != 9)
+      {
+       snmp_log("realloc");
+       oid = mb_realloc(oid, snmp_oid_sizeof(9));
+       snmp_log("/realloc");
+
+       if (oid->n_subid < 6)
+         oid->ids[5] = 0;
+       if (oid->n_subid < 7)
+         oid->ids[6] = 0;
+       if (oid->n_subid < 8)
+         oid->ids[7] = 0;
+       if (oid->n_subid < 9)
+         oid->ids[8] = 0;
+      }
+
       oid->ids[2] = SNMP_BGP_PEER_TABLE;
       oid->ids[3] = SNMP_BGP_PEER_ENTRY;
+
       oid->ids[4] = SNMP_BGP_IDENTIFIER;
-      /* zero the ip */
-      oid->ids[5] = oid->ids[6] = oid->ids[7] = oid->ids[8] = 0;
+      oid->n_subid = 9;
       break;
 
-#define SNMP_UPDATE_CASE(num, update)        \
-    case num:                                \
-      oid->ids[4] = update;                  \
+#define SNMP_UPDATE_CASE(num, update)                                      \
+    case num:                                                              \
+      if (oid->n_subid != 9)                                               \
+      {                                                                            \
+       snmp_log("realloc");                                                \
+       oid = mb_realloc(oid, snmp_oid_sizeof(9));                          \
+       snmp_log("/realloc");                                               \
+                                                                           \
+       if (oid->n_subid < 6)                                               \
+         oid->ids[5] = 0;                                                  \
+       if (oid->n_subid < 7)                                               \
+         oid->ids[6] = 0;                                                  \
+       if (oid->n_subid < 8)                                               \
+         oid->ids[7] = 0;                                                  \
+       if (oid->n_subid < 9)                                               \
+         oid->ids[8] = 0;                                                  \
+      }                                                                            \
+      oid->n_subid = 9;                                                            \
+      oid->ids[4] = update;                                                \
       break;
 
     SNMP_UPDATE_CASE(BGP_INTERNAL_STATE, SNMP_BGP_STATE)
@@ -559,6 +632,9 @@ update_bgp_oid(struct oid *oid, u8 state)
     SNMP_UPDATE_CASE(BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT, SNMP_BGP_MIN_ROUTE_ADVERTISEMENT)
 
     SNMP_UPDATE_CASE(BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME, SNMP_BGP_IN_UPDATE_ELAPSED_TIME)
+
+    default:
+      die("update unavailable");
   }
 
   return oid;
@@ -567,37 +643,50 @@ update_bgp_oid(struct oid *oid, u8 state)
 
 // TODO test bgp_find_dynamic_oid
 static struct oid *
-bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, u8 state UNUSED)
+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);
+
   snmp_log("bgp_find_dynamic_oid()");
   ip4_addr ip4 = ip4_from_oid(o_start);
-  /* dest is 255.255.255.255 if o_end is empty */
-  ip4_addr dest = ip4_from_oid(o_end);
+  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(0xFFFFFFFF);
+  }
 
   snmp_log("ip addresses build (ip4) %I (dest) %I", ipa_from_ip4(ip4), ipa_from_ip4(dest));
 
-  // why am I allocated dynamically ?!
-  net_addr *net = mb_allocz(p->p.pool, sizeof(struct net_addr));
-  net_fill_ip4(net, ip4, IP4_MAX_PREFIX_LENGTH);
+  net_addr net;
+  net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH);
 
   snmp_log("dynamic part of BGP mib");
 
-  // why am I allocated dynamically ?!
-  struct f_trie_walk_state *ws = mb_allocz(p->p.pool,
-                                          sizeof(struct f_trie_walk_state));
+  struct f_trie_walk_state ws;
 
-  trie_walk_init(ws, p->bgp_trie, NULL);
+  // TODO move to newer API
+  trie_walk_init(&ws, p->bgp_trie, NULL, 0);
 
   snmp_log("walk init");
 
-  if (trie_walk_next(ws, net)) // && ip4_less(net4_prefix(net), dest))
+  if (trie_walk_next(&ws, &net)) // && ip4_less(net4_prefix(net), dest))
   {
     snmp_log("trie_walk_next() returned true");
 
     /*
      * if the o_end is empty then there are no conditions on the ip4 addr
      */
-    int cmp = ip4_compare(net4_prefix(net), dest);
+    //int cmp = (check_dest) ? ip4_compare(net4_prefix(&net), dest) : ;
+    int cmp = ip4_compare(net4_prefix(&net), dest);
     if (cmp < 0 || (cmp == 0 && snmp_is_oid_empty(o_end)))
     {
       snmp_log("ip4_less() returned true");
@@ -605,10 +694,7 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_en
       o->n_subid = 9;
 
       memcpy(o, o_start, snmp_oid_size(o_start));
-      snmp_oid_ip4_index(o, 5, net4_prefix(net));
-
-      mb_free(net);
-      mb_free(ws);
+      snmp_oid_ip4_index(o, 5, net4_prefix(&net));
 
       return o;
     }
@@ -616,9 +702,7 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_en
     // delete me
     else
     {
-      snmp_log("ip4_less() returned false for %I >= %I", net4_prefix(net), dest);
-      mb_free(net);
-      mb_free(ws);
+      snmp_log("ip4_less() returned false for %I >= %I", net4_prefix(&net), dest);
     }
     // delete me end
   }
@@ -626,8 +710,6 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_en
   else
   {
     snmp_log("trie_walk_next() returned false, cleaning");
-    mb_free(net);
-    mb_free(ws);
   }
 
   return NULL;
@@ -652,6 +734,9 @@ UNUSED, u8 current_state)
     snmp_oid_dump(o_start);
 
     next_state = snmp_bgp_next_state(next_state);
+    /* 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;
 
     snmp_log("looping");
   } while (o_start == NULL && next_state < BGP_INTERNAL_END);
@@ -659,9 +744,208 @@ UNUSED, u8 current_state)
   return o_start;
 }
 
+/**
+ * snmp_bgp_find_next_oid - walk bgp peer addresses and update @o_start oid
+ *
+ * @p:
+ * @oid:
+ * @contid:
+ */
+static int
+snmp_bgp_find_next_oid(struct snmp_proto *p, struct oid *oid, uint UNUSED contid)
+{
+  // TODO add o_end paramenter for faster searches
+  ip4_addr ip4 = ip4_from_oid(oid);
+  //ip_add4 dest = ip4_from_u32(0xFFFFFFFF);
+
+  net_addr net;
+  net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH);
+  struct f_trie_walk_state ws;
+
+  int match = trie_walk_init(&ws, p->bgp_trie, &net, 1);
+
+  snmp_log("match %d include %u", match, oid->include);
+  if (match && oid->include)
+  {
+    oid->include = 0;
+    return 1;
+  }
+
+  /* We skip the first match as we should not include ip address in oid */
+  if (match)
+  {
+  snmp_log("continue");
+    trie_walk_next(&ws, &net);
+  }
+
+  if (trie_walk_next(&ws, &net))
+  {
+    snmp_oid_dump(oid);
+    snmp_log("setting up");
+    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;
+    return 1;
+  }
+
+  snmp_log("bad");
+  return 0;
+}
+
+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;
+  snmp_log(" **searched = 0x%p  *oid = 0x%p", searched, oid);
+  snmp_oid_dump(*searched);
+  snmp_oid_dump(oid);
+  u8 end_state = snmp_bgp_state(o_end);
+
+  snmp_log("before assumption %s [%u] < %u INTERNAL_END", debug_bgp_states[end_state], end_state, BGP_INTERNAL_END);
+  // failed
+  ASSUME(end_state <= BGP_INTERNAL_END);
+  snmp_log("before assupmtion oid 0x%p != NULL (0x0)", oid);
+  ASSUME(oid != NULL);
+
+  oid = update_bgp_oid(oid, next_state);
+
+  snmp_log("update bgp oid to state %s [%d]", debug_bgp_states[next_state], next_state);
+  snmp_oid_dump(*searched);
+  snmp_oid_dump(oid);
+
+  int found;
+  while (!(found = snmp_bgp_find_next_oid(p, oid, contid)) && next_state <= end_state)
+  {
+    snmp_log("loop");
+
+    next_state = snmp_bgp_next_state(next_state);
+    if (next_state == BGP_INTERNAL_END)
+      break;
+    oid = update_bgp_oid(oid, next_state);
+    /* in 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 <= end_state)
+  {
+    *searched = oid;
+    return SNMP_SEARCH_OK;
+  }
+
+  // free in the caller ?!
+  mb_free(oid);
+  *searched = NULL;
+  return SNMP_SEARCH_END_OF_VIEW;
+}
+
+enum snmp_search_res
+snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid)
+{
+  u8 bgp_state = snmp_bgp_state(*searched);
+  struct oid *oid = *searched;
+  snmp_log("snmp_bgp_search2() with state %s [%d]", debug_bgp_states[bgp_state], bgp_state);
+
+  /* TODO remove todo below, then remove this code */
+  if (is_dynamic(bgp_state))
+  {
+    snmp_log("returning oid with dynamic state");
+    return snmp_bgp_search_dynamic(p, searched, o_end, contid, bgp_state);
+    //return snmp_bgp_search_dynamic(p, searched, contid, result, bgp_state);
+  }
+
+  /* TODO snmp_bgp_has_value is false only for state which are not dynamic */
+  if (!snmp_bgp_has_value(bgp_state) || !oid->include)
+  {
+    bgp_state = snmp_bgp_next_state(bgp_state);
+    snmp_log("altering searched oid with next state %s [%d]", debug_bgp_states[bgp_state], bgp_state);
+    snmp_oid_dump(*searched);
+    snmp_log("after oid update:");
+    snmp_oid_dump(*searched);
+
+    /* zero the ip address section for previously non-dynamic oid (search all peers) */
+    for (int i = 5; i < MIN(9, oid->n_subid); i++)
+      oid->ids[i] = 0;
+  }
+
+  if (is_dynamic(bgp_state))
+  {
+    snmp_log("returning oid with dynamic state 2");
+    return snmp_bgp_search_dynamic(p, searched, o_end, contid, bgp_state);
+    //return snmp_bgp_search_dynamic(p, o_start, contid, result, bgp_state);
+  }
+
+  oid = *searched = update_bgp_oid(*searched, bgp_state);
+  if (oid->n_subid == 3 && oid->ids[2] >= SNMP_BGP_VERSION &&
+      oid->ids[2] <= SNMP_BGP_LOCAL_AS)
+  {
+    snmp_log("oid matches static state");
+    oid->include = 0;
+    return SNMP_SEARCH_OK;
+  }
+
+  snmp_log("reached unguarded code, returning END_OF_VIEW");
+  /* TODO */
+  //if (
+
+
+  return SNMP_SEARCH_END_OF_VIEW;
+  // return SNMP_NO_SUCH_OBJECT;
+
+#if 0
+  if (is_dynamic(bgp_state))
+    return snmp_bgp_search_dynamic(p, o_start, contid, res);
+
+  if (!snmp_bgp_has_value(bgp_state))
+  {
+    bgp_state = x;
+  }
+  print_bgp_record_all(p);
+
+  if (o_start->include)
+    return snmp_bgp_search_included(p, o_start, contid, result, bgp_state);
+
+  u8 next_state = snmp_bgp_next_state(bgp_state);
+  if (!is_dynamic(next_state))
+  {
+    o_start = update_bgp_oid(o_start, next_state);
+    snmp_log("next state is also not dynamic");
+    *res = o_start;
+    return SNMP_SEARCH_OK;
+  }
+
+  return search_bgp_dynamic(p, o_start, o_end, contid, bgp_state);
+
+
+  if (o_start->include && snmp_bgp_has_value(bgp_state))
+      && !is_dynamic(bgp_state))
+  {
+    if (o_start->n_subid == 3)
+    {
+      o_start->include = 0;
+      *result = o_start;
+      return SNMP_SEARCH_OK;
+    }
+    else if (o_start->n_subid > 3)
+      return SNMP_SEARCH_NO_INSTANCE;
+    else
+      return SNMP_SEARCH_NO_OBJECT;
+  }
+  else if (o_start->include && snmp_bgp_has_value(bgp_state))
+          && is_dynamic(bgp_state))
+    return search_bgp_dynamic1(p, o_start, contid, result);
+  else if (o_start
+
+  / * o_start is not inclusive * /
+#endif
+}
+
 /* o_start could be o_curr, but has basically same meaning for searching */
 struct oid *
-search_bgp_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid UNUSED)
+snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid UNUSED)
 {
   u8 start_state = snmp_bgp_state(o_start);
   //u8 state_curr = snmp_bgp_state(o_start);
@@ -674,14 +958,14 @@ search_bgp_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uin
   if (o_start->include && snmp_bgp_has_value(start_state) &&
       !is_dynamic(start_state) && o_start->n_subid == 3)
   {
-    snmp_log("search_bgp_mib() first search element (due to include field) returned");
+    snmp_log("snmp_bgp_search() first search element (due to include field) returned");
     o_start->include = 0;  /* disable including for next time */
     return o_start;
   }
   else if (o_start->include && snmp_bgp_has_value(start_state) &&
-      is_dynamic(start_state))
+          is_dynamic(start_state))
   {
-    snmp_log("search_bgp_mib() first search element matched dynamic entry!");
+    snmp_log("snmp_bgp_search() first search element matched dynamic entry!");
     return search_bgp_dynamic(p, o_start, o_end, contid, start_state);
   }
 
@@ -728,19 +1012,21 @@ search_bgp_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uin
 }
 
 static byte *
-bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind *vb, byte *pkt, uint size
-UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
+bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
+                struct snmp_pdu_context *c, u8 state)
 {
-  //snmp_log("bgp_fill_dynamic() valid ip %s", snmp_bgp_valid_ip4(oid) ? "true" : "false");
-
   struct oid *oid = &vb->name;
+  uint size = c->size - snmp_varbind_header_size(vb);
+  uint UNUSED contid = c->context;
+  byte *pkt;
 
   ip_addr addr;
-  if (snmp_bgp_valid_ip4(oid))
+  if (oid_state_compare(oid, state) == 0 && snmp_bgp_valid_ip4(oid))
     addr = ipa_from_ip4(ip4_from_oid(oid));
   else
   {
-    vb->type = AGENTX_NO_SUCH_OBJECT;
+    vb->type = AGENTX_NO_SUCH_INSTANCE;
+    pkt = ((byte *) vb) + snmp_varbind_header_size(vb);
     return pkt;
   }
 
@@ -754,25 +1040,23 @@ UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
   {
     proto = ((struct proto_config *) pe->config)->proto;
     if (proto->proto == &proto_bgp &&
-       ipa_equal(addr, ((struct bgp_proto *) proto)->remote_ip))
+        ipa_equal(addr, ((struct bgp_proto *) proto)->remote_ip))
     {
       bgp_proto = (struct bgp_proto *) proto;
       snmp_log("bgp_dynamic_fill() using bgp_proto %p", bgp_proto);
     }
-
     /* binded bgp protocol not found */
     else
     {
       die("Binded bgp protocol not found!");
-      vb->type = AGENTX_NO_SUCH_OBJECT;
-      return pkt;
+      vb->type = AGENTX_NO_SUCH_INSTANCE;
+      return ((byte *) vb) + snmp_varbind_header_size(vb);
     }
   }
-
   else
   {
-    vb->type = AGENTX_NO_SUCH_OBJECT;
-    return pkt;
+    vb->type = AGENTX_NO_SUCH_INSTANCE;
+    return ((byte *) vb) + snmp_varbind_header_size(vb);
   }
 
   struct bgp_conn *bgp_conn = bgp_proto->conn;
@@ -794,164 +1078,129 @@ UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
   else
     bgp_state = MAX(bgp_in->state, bgp_out->state);
 
-  btime now;
+  char last_error[2] = { bgp_proto->last_error_code & 0x00FF0000 >> 16,
+                        bgp_proto->last_error_code & 0x000000FF };
   switch (state)
   {
-
     case BGP_INTERNAL_IDENTIFIER:
       if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED)
-      {
-       snmp_put_ip4(pkt, bgp_proto->remote_ip);
-       pkt += 4;
-       /* the inserted ip has size 8 bytes, the BGP_DATA will increment by 4B */
-       BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
-      }
+       pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->remote_ip));
       else
-      {
-       snmp_put_blank(pkt);      /* stores 4B of zeroes */
-       BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
-      }
+       pkt = snmp_varbind_ip4(vb, size, IP4_NONE);
       break;
 
     case BGP_INTERNAL_STATE:
-      STORE_PTR(pkt, bgp_state);
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      pkt = snmp_varbind_int(vb, size, bgp_state);
       break;
 
     case BGP_INTERNAL_ADMIN_STATUS:
       /* struct proto ~ (struct proto *) bgp_proto */
       if (proto->disabled)
-       STORE_PTR(pkt, AGENTX_ADMIN_STOP);
+       pkt = snmp_varbind_int(vb, size, AGENTX_ADMIN_STOP);
       else
-       STORE_PTR(pkt, AGENTX_ADMIN_START);
+       pkt = snmp_varbind_int(vb, size, AGENTX_ADMIN_START);
 
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
       break;
 
     case BGP_INTERNAL_NEGOTIATED_VERSION:
       if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED)
-       STORE_PTR(pkt, 4); // TODO replace with MACRO
+       pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_VALUE);
       else
-       STORE_PTR(pkt, 0); /* zero dictated by rfc */
+       pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_NO_VALUE);
 
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
       break;
 
     case BGP_INTERNAL_LOCAL_ADDR:
       // TODO XXX bgp_proto->link_addr & zero local_ip
-      snmp_put_ip4(pkt, bgp_proto->local_ip);
-      pkt += 4;
-      /* the inserted ip has size 8 bytes, the BGP_DATA will increment by 4B */
-      BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+      pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->local_ip));
       break;
 
     case BGP_INTERNAL_LOCAL_PORT:
-      STORE_PTR(pkt, bgp_conf->local_port);
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      pkt = snmp_varbind_int(vb, size, bgp_conf->local_port);
       break;
 
     case BGP_INTERNAL_REMOTE_ADDR:
-      snmp_put_ip4(pkt, bgp_proto->remote_ip);
-      pkt += 4;
-      /* the inserted ip has size 8 bytes, the BGP_DATA will increment by 4B */
-      BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+      pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->remote_ip));
       break;
 
     case BGP_INTERNAL_REMOTE_PORT:
-      STORE_PTR(pkt, bgp_conf->remote_port);
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      pkt = snmp_varbind_int(vb, size, bgp_conf->remote_port);
       break;
 
     case BGP_INTERNAL_REMOTE_AS:
-      STORE_PTR(pkt, bgp_proto->remote_as);
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      pkt = snmp_varbind_int(vb, size, bgp_proto->remote_as);
       break;
 
     /* IN UPDATES */
     case BGP_INTERNAL_RX_UPDATES:
-      STORE_PTR(pkt, bgp_stats->rx_updates);
-      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      pkt = snmp_varbind_counter32(vb, size, bgp_stats->rx_updates);
       break;
 
     /* OUT UPDATES */
     case BGP_INTERNAL_TX_UPDATES:
-      STORE_PTR(pkt, bgp_stats->tx_updates);
-      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      pkt = snmp_varbind_counter32(vb, size, bgp_stats->tx_updates);
       break;
 
     /* IN MESSAGES */
     case BGP_INTERNAL_RX_MESSAGES:
-      STORE_PTR(pkt, bgp_stats->rx_messages);
-      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      pkt = snmp_varbind_counter32(vb, size, bgp_stats->rx_messages);
       break;
 
     /* OUT MESSAGES */
     case BGP_INTERNAL_TX_MESSAGES:
-      STORE_PTR(pkt, bgp_stats->tx_messages);
-      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      pkt = snmp_varbind_counter32(vb, size, bgp_stats->tx_messages);
       break;
 
     case BGP_INTERNAL_LAST_ERROR:
-      STORE_PTR(pkt, 2);
-      pkt += 4;
-
-      if (bgp_proto->last_error_code)
-      {
-       /* force network order */
-       put_u32(pkt, bgp_proto->last_error_code & 0x00FF0000 << 8 |
-         bgp_proto->last_error_code & 0x000000FF << 24);
-      }
-      else
-       snmp_put_blank(pkt);
-
-      BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
+      pkt = snmp_varbind_nstr(vb, size, last_error, 2);
       break;
 
     // TODO finish me here
     case BGP_INTERNAL_FSM_TRANSITIONS:
-      STORE_PTR(pkt, bgp_stats->fsm_established_transitions);
-      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      pkt = snmp_varbind_counter32(vb, size,
+         bgp_stats->fsm_established_transitions);
       break;
 
     case BGP_INTERNAL_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
-      STORE_PTR(pkt, bgp_conf->connect_retry_time);
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      pkt = snmp_varbind_int(vb, size, bgp_conf->connect_retry_time);
       break;
 
     case BGP_INTERNAL_HOLD_TIME:
       // (0, 3..65535)
-      STORE_PTR(pkt, bgp_conn->hold_time);
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      pkt = snmp_varbind_int(vb, size, bgp_conn->hold_time);
       break;
 
     case BGP_INTERNAL_KEEPALIVE:
-      STORE_PTR(pkt, bgp_conn->keepalive_time);
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      pkt = snmp_varbind_int(vb, size, bgp_conn->keepalive_time);
       break;
 
     case BGP_INTERNAL_HOLD_TIME_CONFIGURED:
-      STORE_PTR(pkt, bgp_conf->hold_time);
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      pkt = snmp_varbind_int(vb, size, bgp_conf->hold_time);
       break;
+
     case BGP_INTERNAL_KEEPALIVE_CONFIGURED:
-      STORE_PTR(pkt, bgp_conf->keepalive_time);
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      pkt = snmp_varbind_int(vb, size, bgp_conf->keepalive_time);
       break;
 
-    // finish me here
     case BGP_INTERNAL_ORIGINATION_INTERVAL:
+      // (1..65535) but is not supported
+      pkt = snmp_varbind_int(vb, size, 0);
       break;
+
     case BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT:
+      // (1..65535) but is not supported
+      pkt = snmp_varbind_int(vb, size, 0);
       break;
 
     case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
-      now = current_time();
-      STORE_PTR(pkt, (now - bgp_proto->last_rx_update) TO_S );
-      BGP_DATA(vb, AGENTX_GAUGE_32, pkt);
+      pkt = snmp_varbind_gauge32(vb, size, (current_time()
+                             - bgp_proto->last_rx_update) TO_S);
       break;
 
     case BGP_INTERNAL_END:
@@ -970,78 +1219,96 @@ UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
       break;
   }
 
+  if (!pkt)
+  {
+    vb->type = AGENTX_NO_SUCH_INSTANCE;
+    return ((byte *) vb) + snmp_varbind_header_size(vb);
+  }
+
   return pkt;
 }
 
+
 static byte *
 bgp_fill_static(struct snmp_proto *p, struct agentx_varbind *vb, byte *pkt, uint size
 UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
 {
   snmp_log("snmp bgp_fill_static ()\n");
   byte *temp = pkt;
+  snmp_log("bgp_fill_static: vb->type %u, ptk %02x", vb->type, *((u32 *) pkt));
 
   struct oid *oid = &vb->name;
+  snmp_oid_dump(oid);
+  snmp_log("bgp_fill_static");
 
   /* 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->n_subid != 3)
+  if (oid_state_compare(oid, state) < 0 || state == BGP_INTERNAL_END)
   {
     vb->type = AGENTX_NO_SUCH_OBJECT;
-    return pkt;
+    return ((byte *) vb) + snmp_varbind_header_size(vb);
+  }
+  else if (oid_state_compare(oid, state) > 0)
+  {
+    vb->type = AGENTX_NO_SUCH_INSTANCE;
+    return ((byte *) vb) + snmp_varbind_header_size(vb);
   }
 
   switch (state)
   {
     case BGP_INTERNAL_VERSION:
-      STORE_PTR(pkt, 1);   /* store string len */
-      pkt += 4;
-      STORE_PTR(pkt, BGP4_VERSIONS);
-
-      /* real size is 8 but we already shifted the pkt by 4 */
-      BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
+      pkt = snmp_varbind_nstr(vb, size, BGP4_VERSIONS, 1);
       break;
 
     case BGP_INTERNAL_LOCAL_AS:
-      // XXX local as to use
-
-      STORE_PTR(pkt, p->local_as);
-      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      pkt = snmp_varbind_int(vb, size, p->local_as);
       break;
 
     case BGP_INTERNAL_BGP:
+    default:
       vb->type = AGENTX_NO_SUCH_OBJECT;
+      pkt = ((byte *) vb) + snmp_varbind_header_size(vb);
+      break;
   }
 
+  snmp_log("bgp_fill_static: type %u  packet %p", vb->type, pkt);
+  snmp_oid_dump(oid);
+
   snmp_log("snmp ended with non empty pkt %u starting from %p to %p\n", pkt -
 temp, temp, pkt);
+  snmp_dump_packet(temp, pkt - temp);
   return pkt;
 }
 
-byte *
-snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, byte *buf UNUSED,
-uint size UNUSED, uint contid UNUSED, int byte_ord UNUSED)
+void
+snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb,
+             struct snmp_pdu_context *c)
 {
   u8 state = snmp_bgp_state(&vb->name);
-  //snmp_log("snmp_bgp_fill() state %u is dynamic %s has value %s", state, is_dynamic(state) ? "true" : "false", snmp_bgp_has_value(state) ? "true" : "false");
+  //byte *tmp;
 
+  byte *pkt;
   if (!is_dynamic(state))
-    return bgp_fill_static(p, vb, buf, size, contid, byte_ord, state);
+  {
+    //return bgp_fill_static(p, vb, c->buffer, c->size, c->context, c->byte_ord, state);
+    pkt = bgp_fill_static(p, vb, c->buffer, c->size, c->context, c->byte_ord, state);
+    ADVANCE(c->buffer, c->size, pkt - c->buffer);
+    return;
+  }
 
   if (is_dynamic(state) && snmp_bgp_has_value(state))
-    return bgp_fill_dynamic(p, vb, buf, size, contid, byte_ord, state);
-
-  else
   {
-    return buf;
+    pkt = bgp_fill_dynamic(p, vb, c, state);
+    ADVANCE(c->buffer, c->size, pkt - c->buffer);
+    return;
   }
-  /*
+  else
   {
-    snmp_log("has no value");
-    struct agentx_varbind *vb = snmp_create_varbind(buf, oid);
-    buf += snmp_varbind_size(vb);
-    vb->type = AGENTX_NO_SUCH_OBJECT;
-    return buf;
+    die("snmp_bgp_fill unreachable");
+    // AGENTX_NO_SUCH_OBJECT
+    ((void) c->buffer);
+    return;
   }
-  */
 }
+
index d2db74673d3499da622b9bf88ce9f23869a42002..e27f1d5110b0160a070eef2cbf92622f016eff56 100644 (file)
@@ -32,6 +32,10 @@ enum BGP4_MIB {
   SNMP_BGP_IN_UPDATE_ELAPSED_TIME   = 24,   /* UNSUPPORTED */
 } PACKED;
 
+/* version of BGP, here BGP-4 */
+#define SNMP_BGP_NEGOTIATED_VER_VALUE 4
+#define SNMP_BGP_NEGOTIATED_VER_NO_VALUE 0
+
 //void snmp_init_bgp_table(void);
 //void snmp_del_bgp_table(void);
 
@@ -45,8 +49,10 @@ u8 snmp_bgp_state(struct oid *o);
 u8 snmp_bgp_get_valid(u8 state);
 u8 snmp_bgp_getnext_valid(u8 state);
 
-struct oid *search_bgp_mib(struct snmp_proto *p , struct oid *o_start, struct oid *o_end, uint contid);
-byte * snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, byte *buf, uint size, uint contid UNUSED, int byte_ord);
+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);
+//byte * snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, byte *buf, uint size, uint contid UNUSED, int byte_ord);
+void snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, struct snmp_pdu_context *c);
 
 #define BGP4_MIB_VERSION 1
 #define BGP4_MIB_LOCAL_AS 2
index 3a06b0c9e8037911be29052bdc86b25ed4f57fde..853697d5b4ab75ebdb1873ed3c1838babf2e4dd2 100644 (file)
@@ -10,6 +10,8 @@
 
 #include "snmp_utils.h"
 
+int agentx_type_size(enum agentx_type t);
+
 /**
  * snmp_is_oid_empty - check if oid is null-valued
  * @oid: object identifier to check
@@ -17,7 +19,7 @@
  * Test if the oid header is full of zeroes. For @oid NULL returns 0.
  */
 int
-snmp_is_oid_empty(struct oid *oid)
+snmp_is_oid_empty(const struct oid *oid)
 {
   if (oid != NULL)
     return oid->n_subid == 0 && oid->prefix == 0 && oid->include == 0;
@@ -30,10 +32,38 @@ snmp_is_oid_empty(struct oid *oid)
  * @buf: packet first byte
  * @pkt: first byte past packet end
  */
-size_t
-snmp_pkt_len(byte *buf, byte *pkt)
+uint
+snmp_pkt_len(byte *start, byte *end)
+{
+  snmp_log("snmp_pkt_len start 0x%p end 0x%p  res %u", start, end, (end - start)
+- AGENTX_HEADER_SIZE);
+  return (end - start) - AGENTX_HEADER_SIZE;
+}
+
+/**
+ *
+ * used for copying oid to in buffer oid @dest
+ */
+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->include, src->include);
+  STORE_U8(dest->pad,    0);
+
+  for (int i = 0; i < src->n_subid; i++)
+    STORE_U32(dest->ids[i], src->ids[i]);
+}
+
+/**
+ *
+ */
+struct oid *
+snmp_oid_duplicate(pool *pool, const struct oid *oid)
 {
-  return (pkt - buf) - AGENTX_HEADER_SIZE;
+  struct oid *res = mb_alloc(pool, snmp_oid_size(oid));
+  memcpy(res, oid, snmp_oid_size(oid));
+  return res;
 }
 
 /**
@@ -46,6 +76,12 @@ snmp_oid_blank(struct snmp_proto *p)
   return mb_allocz(p->p.pool, sizeof(struct oid));
 }
 
+size_t
+snmp_str_size_from_len(uint len)
+{
+  return 4 + BIRD_ALIGN(len, 4);
+}
+
 /**
  * snmp_str_size - return in packet size of supplied string
  * @str: measured string
@@ -53,10 +89,10 @@ snmp_oid_blank(struct snmp_proto *p)
  * Returned value is string length aligned to 4 byte with 32bit length
  * annotation included.
  */
-size_t
+inline size_t
 snmp_str_size(const char *str)
 {
-  return 4 + BIRD_ALIGN(strlen(str), 4);
+  return snmp_str_size_from_len(strlen(str));
 }
 
 /**
@@ -64,7 +100,7 @@ snmp_str_size(const char *str)
  * @o: object identifier to use
  */
 uint
-snmp_oid_size(struct oid *o)
+snmp_oid_size(const struct oid *o)
 {
   return 4 + (o->n_subid * 4);
 }
@@ -79,28 +115,62 @@ snmp_oid_sizeof(uint n_subid)
   return sizeof(struct oid) + n_subid * sizeof(u32);
 }
 
+uint snmp_varbind_hdr_size_from_oid(struct oid *oid)
+{
+  return snmp_oid_size(oid) + 4;
+}
+
 /**
  * snmp_vb_size - measure size of varbind in bytes
  * @vb: variable binding to use
  */
 uint
-snmp_varbind_size(struct agentx_varbind *vb)
+snmp_varbind_header_size(struct agentx_varbind *vb)
 {
-  return snmp_oid_size(&vb->name) + 4;
+  return snmp_varbind_hdr_size_from_oid(&vb->name);
+}
+
+uint
+snmp_varbind_size(struct agentx_varbind *vb, int byte_ord)
+{
+  uint hdr_size = snmp_varbind_header_size(vb);
+  int s = agentx_type_size(vb->type);
+
+  if (s >= 0)
+    return hdr_size + (uint) s;
+
+  void *data = ((void *) vb) + hdr_size;
+
+  if (vb->type == AGENTX_OBJECT_ID)
+    return hdr_size + snmp_oid_size((struct oid *) data);
+
+  /*
+   * Load length of octet string
+   * (AGENTX_OCTET_STRING, AGENTX_IP_ADDRESS, AGENTX_OPAQUE)
+   */
+  return hdr_size + snmp_str_size_from_len(LOAD_PTR(data, byte_ord));
+}
+
+inline uint
+snmp_context_size(struct agentx_context *c)
+{
+  return (c && c->length) ? snmp_str_size_from_len(c->length) : 0;
 }
 
 struct agentx_varbind *
 snmp_create_varbind(byte *buf, struct oid *oid)
 {
   struct agentx_varbind *vb = (void*) buf;
+  vb->pad = 0;
   memcpy(&vb->name, oid, snmp_oid_size(oid));
   return vb;
 }
 
-byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new)
+byte *
+snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new)
 {
   memcpy(&vb->name, new, snmp_oid_size(new));
-  return (void *) vb + snmp_varbind_size(vb);
+  return (void *) vb + snmp_varbind_header_size(vb);
 }
 
 /**
@@ -109,7 +179,7 @@ byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new)
  * @start: index of first address id
  */
 int
-snmp_valid_ip4_index(struct oid *o, uint start)
+snmp_valid_ip4_index(const struct oid *o, uint start)
 {
   if (start + 3 < o->n_subid)
     return snmp_valid_ip4_index_unsafe(o, start);
@@ -126,7 +196,7 @@ snmp_valid_ip4_index(struct oid *o, uint start)
  * length sufficiency is done.
  */
 int
-snmp_valid_ip4_index_unsafe(struct oid *o, uint start)
+snmp_valid_ip4_index_unsafe(const struct oid *o, uint start)
 {
   for (int i = 0; i < 4; i++)
     if (o->ids[start + i] >= 256)
@@ -135,6 +205,23 @@ snmp_valid_ip4_index_unsafe(struct oid *o, uint start)
   return 1; // true
 }
 
+byte *
+snmp_put_nstr(byte *buf, const char *str, uint len)
+{
+  uint alen = BIRD_ALIGN(len, 4);
+
+  // TODO check for '\0' in the str bytes?
+  STORE_PTR(buf, len);
+  buf += 4;
+  memcpy(buf, str, len);
+
+  /* Insert zero padding in the gap at the end */
+  for (uint i = 0; i < alen - len; i++)
+    buf[len + i] = 0x00;
+
+  return buf + alen;
+}
+
 /**
  * snmp_put_str - put string into SNMP PDU transcieve buffer
  * @buf: pointer to first unoccupied buffer byte
@@ -148,28 +235,16 @@ byte *
 snmp_put_str(byte *buf, const char *str)
 {
   uint len = strlen(str);
-  uint slen = BIRD_ALIGN(len, 4);
-
-  if (len > MAX_STR)
-    return NULL;
-
-  STORE_PTR(buf, len);
-
-  memcpy(buf + 4, str, len);
-
-  for (uint i = 0; i < slen - len; i++)
-    buf[len + i] = 0x00;  // PADDING
-
-  return buf + snmp_str_size(str);
+  return snmp_put_nstr(buf, str, len);
 }
 
 byte *
-snmp_put_ip4(byte *buf, ip_addr addr)
+snmp_put_ip4(byte *buf, ip4_addr addr)
 {
   /* octet string has size 4 bytes */
   STORE_PTR(buf, 4);
 
-  put_u32(buf+4, ipa_to_u32(addr));
+  put_u32(buf+4, ip4_to_u32(addr));
 
   return buf + 8;
 }
@@ -231,10 +306,10 @@ void
 snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr)
 {
   u32 temp = ip4_to_u32(addr);
-  STORE(o->ids[start], temp >> 24);
-  STORE(o->ids[start + 1], (temp >> 16) & 0xFF);
-  STORE(o->ids[start + 2], (temp >>  8) & 0xFF);
-  STORE(o->ids[start + 3], temp & 0xFF);
+  STORE_U32(o->ids[start], temp >> 24);
+  STORE_U32(o->ids[start + 1], (temp >> 16) & 0xFF);
+  STORE_U32(o->ids[start + 2], (temp >>  8) & 0xFF);
+  STORE_U32(o->ids[start + 3], temp & 0xFF);
 }
 
 void snmp_oid_dump(struct oid *oid)
@@ -278,7 +353,7 @@ void snmp_oid_dump(struct oid *oid)
  *   and 1 otherwise
  */
 int
-snmp_oid_compare(struct oid *left, struct oid *right)
+snmp_oid_compare(const struct oid *left, const struct oid *right)
 {
   const u32 INTERNET_PREFIX[] = {1, 3, 6, 1};
 
@@ -404,3 +479,113 @@ snmp_dump_packet(byte *pkt, uint size)
     snmp_log("pkt [%d]  0x%02x%02x%02x%02x", i, pkt[i],pkt[i+1],pkt[i+2],pkt[i+3]);
   snmp_log("end dump");
 }
+
+/*
+ * Returns length of agentx_type @type in bytes.
+ * Variable length types result in -1.
+ */
+int
+agentx_type_size(enum agentx_type type)
+{
+  /*
+   * AGENTX_NULL, AGENTX_NO_SUCH_OBJECT, AGENTX_NO_SUCH_INSTANCE,
+   * AGENTX_END_OF_MIB_VIEW
+   */
+  if (type >= AGENTX_NO_SUCH_OBJECT || type == AGENTX_NULL)
+    return 0;
+
+  /* AGENTX_INTEGER, AGENTX_COUNTER_32, AGENTX_GAUGE_32, AGENTX_TIME_TICKS */
+  if (type >= AGENTX_COUNTER_32 && type <= AGENTX_TIME_TICKS ||
+      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 */
+  else
+    return -1;
+}
+
+static inline byte *
+snmp_varbind_type32(struct agentx_varbind *vb, uint size, enum agentx_type type, u32 val)
+{
+  ASSUME(agentx_type_size(type) == 4); /* type has 4B representation */
+
+  if (size < (uint) agentx_type_size(type))
+  {
+    snmp_log("varbind type32 returned NULL");
+    return NULL;
+  }
+
+  vb->type = type;
+  u32 *data = SNMP_VB_DATA(vb);
+  snmp_log("varbind type32 vb data 0x%p (from vb 0x%p)", data, (void *) vb);
+  *data = val;
+  return (byte *)(data + 1);
+}
+
+inline byte *
+snmp_varbind_int(struct agentx_varbind *vb, uint size, u32 val)
+{
+  return snmp_varbind_type32(vb, size, AGENTX_INTEGER, val);
+}
+
+
+inline byte *
+snmp_varbind_counter32(struct agentx_varbind *vb, uint size, u32 val)
+{
+  return snmp_varbind_type32(vb, size, AGENTX_COUNTER_32, val);
+}
+
+inline byte *
+snmp_varbind_gauge32(struct agentx_varbind *vb, uint size, s64 val)
+{
+  return snmp_varbind_type32(vb, size, AGENTX_GAUGE_32,
+                            MAX(0, MIN(val, UINT32_MAX)));
+}
+
+inline byte *
+snmp_varbind_ip4(struct agentx_varbind *vb, uint size, ip4_addr addr)
+{
+  if (size < snmp_str_size_from_len(4))
+  {
+    snmp_log("varbind ip4 NULL");
+    return NULL;
+  }
+
+  vb->type = AGENTX_IP_ADDRESS;
+  snmp_log("snmp_varbind_ip4 vb data 0x%p (from vb 0x%p)", SNMP_VB_DATA(vb), (void
+*) vb);
+  return snmp_put_ip4(SNMP_VB_DATA(vb), addr);
+}
+
+inline byte *
+snmp_varbind_nstr(struct agentx_varbind *vb, uint size, const char *str, uint len)
+{
+  if (size < snmp_str_size_from_len(len))
+  {
+    snmp_log("varbind nstr NULL");
+    return NULL;
+  }
+
+  vb->type = AGENTX_OCTET_STRING;
+  //die("snmp_varbind_nstr() %p.data = %p", vb, SNMP_VB_DATA(vb));
+  snmp_log("snmp_varbind_nstr vb data 0x%p (from vb 0x%p)", SNMP_VB_DATA(vb), (void *) vb);
+  //snmp_log("snmp_varbind_nstr() %p.data = %p", vb, SNMP_VB_DATA(vb));
+  return snmp_put_nstr(SNMP_VB_DATA(vb), str, len);
+}
+
+inline enum agentx_type
+snmp_search_res_to_type(enum snmp_search_res r)
+{
+  ASSUME(r != SNMP_SEARCH_OK);
+  static enum agentx_type type_arr[] = {
+    [SNMP_SEARCH_NO_OBJECT]   = AGENTX_NO_SUCH_OBJECT,
+    [SNMP_SEARCH_NO_INSTANCE] = AGENTX_NO_SUCH_INSTANCE,
+    [SNMP_SEARCH_END_OF_VIEW] = AGENTX_END_OF_MIB_VIEW,
+  };
+
+  return type_arr[r];
+}
index 913cf717476d727fe36c55bc80f0adbe17848cb0..d32477d0db330747b0894c69ffe310f36a5709b9 100644 (file)
@@ -3,30 +3,38 @@
 
 #include "subagent.h"
 
-size_t snmp_pkt_len(byte *buf, byte *pkt);
+uint snmp_pkt_len(byte *start, byte *end);
+size_t snmp_str_size_from_len(uint len);
 size_t snmp_str_size(const char *str);
-int snmp_is_oid_empty(struct oid *oid);
-int snmp_valid_ip4_index(struct oid *o, uint start);
-int snmp_valid_ip4_index_unsafe(struct oid *o, uint start);
-uint snmp_oid_size(struct oid *o);
+int snmp_is_oid_empty(const struct oid *oid);
+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);
-uint snmp_varbind_size(struct agentx_varbind *vb);
+uint snmp_varbind_hdr_size_from_oid(struct oid *oid);
+uint snmp_varbind_header_size(struct agentx_varbind *vb);
+uint snmp_varbind_size(struct agentx_varbind *vb, int byte_ord);
+uint snmp_context_size(struct agentx_context *c);
 
+void snmp_oid_copy(struct oid *dest, const struct oid *src);
+
+struct oid *snmp_oid_duplicate(pool *pool, const struct oid *oid);
 struct oid *snmp_oid_blank(struct snmp_proto *p);
 
 struct agentx_varbind *snmp_create_varbind(byte* buf, struct oid *oid);
 byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new);
 
-int snmp_oid_compare(struct oid *first, struct oid *second);
+int snmp_oid_compare(const struct oid *first, const struct oid *second);
 
 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, ip_addr ip4);
+byte *snmp_put_ip4(byte *buf, ip4_addr ip4);
 
 byte *snmp_put_fbyte(byte *buf, u8 data);
 
@@ -34,13 +42,19 @@ void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr);
 
 void snmp_oid_dump(struct oid *oid);
 
-int snmp_oid_compare(struct oid *left, struct oid *right);
-
-struct oid *snmp_prefixize(struct snmp_proto *p, struct oid *o, int byte_ord);
+//struct oid *snmp_prefixize(struct snmp_proto *p, struct oid *o, int byte_ord);
 
 struct snmp_register *snmp_register_create(struct snmp_proto *p, u8 mib_class);
 
 void snmp_register_ack(struct snmp_proto *p, struct agentx_header *h);
 
+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_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);
+
+enum agentx_type snmp_search_res_to_type(enum snmp_search_res res);
 #endif
index a0313fc13eb93e38240b38c415539754f56995da..6478f59904c8951ff545c6055fd6e536c35bfa4c 100644 (file)
@@ -26,7 +26,7 @@ enum SNMP_CLASSES {
   SNMP_CLASS_END,
 };
 
-#define BGP4_VERSIONS 0x10
+#define BGP4_VERSIONS ((char[]) { 0x10 })
 
 enum agentx_type {
   AGENTX_INTEGER           =   2,
@@ -44,6 +44,13 @@ enum agentx_type {
   AGENTX_END_OF_MIB_VIEW    = 130,
 } PACKED;
 
+enum snmp_search_res {
+  SNMP_SEARCH_OK         = 0,
+  SNMP_SEARCH_NO_OBJECT          = 1,
+  SNMP_SEARCH_NO_INSTANCE = 2,
+  SNMP_SEARCH_END_OF_VIEW = 3,
+};
+
 #define AGENTX_ADMIN_STOP   1
 #define AGENTX_ADMIN_START  2
 
@@ -53,18 +60,15 @@ enum agentx_type {
 #define SNMP_NATIVE
 
 #ifdef SNMP_NATIVE
-#define STORE(v,c) (v) = (u32) (c)
-#define STORE_16(v,c) (v) = (u16) (c)
-#define STORE_PTR(v,c) *((u32 *) (v)) = (u32) (c)
-#define SNMP_UPDATE(h,l) \
-  STORE((h)->payload, l)
-
+#define STORE_U32(dest, val)  ((dest) = (u32) (val))
+#define STORE_U16(dest, val)  ((dest) = (u16) (val))
+#define STORE_U8(dest, val)   ((dest) = (u8) (val))
+#define STORE_PTR(ptr, val)   (*((u32 *) (ptr)) = (u32) (val))
 #else
-#define STORE(v, c) put_u32(&v, c)
-#define STORE_16(v,c) put_u32(&v, c)
-#define STORE_PTR(v,c) put_u32(v, c)
-#define SNMP_UPDATE(h,l) \
-  STORE(h->payload, l)
+#define STORE_U32(dest, val)  put_u32(&(dest), (val))
+#define STORE_U16(dest, val)  put_u16(&(dest), (val))
+#define STORE_U8(dest, val)   put_u8(&(dest), (val))
+#define STORE_PTR(ptr, val)   put_u32(ptr, val)
 #endif
 
 /* storing byte (u8) is always the same */
@@ -82,18 +86,18 @@ enum agentx_type {
 #endif
 
 #define SNMP_B_HEADER(h, t) SNMP_HEADER(h, t, AGENTX_FLAG_BLANK)
-
-#define SNMP_SESSION(h, p)                     \
-  STORE(h->session_id, p->session_id);         \
-  STORE(h->transaction_id, p->transaction_id); \
-  p->transaction_id++;                         \
-  STORE(h->packet_id, p->packet_id);
+#define SNMP_BLANK_HEADER(h, t) SNMP_HEADER(h, t, AGENTX_FLAG_BLANK)
 
 #define SNMP_CREATE(b, t, n)  \
   n = (void *) (b);          \
   memset(n, 0, sizeof(t));    \
   (b) += sizeof(t);
 
+#define SNMP_SESSION(h, p)                                                   \
+  STORE_U32(h->session_id, p->session_id);                                   \
+  STORE_U32(h->transaction_id, p->transaction_id);                           \
+  STORE_U32(h->packet_id, p->packet_id)
+
 #define LOAD(v, bo) ((bo) ? get_u32(&v) : (u32) (v))
 #define LOAD_16(v, bo) ((bo) ? get_u16(&v) : (u16) (v))
 #define LOAD_PTR(v, bo) ((bo) ? get_u32(v) : (u32) *(v))
@@ -125,7 +129,17 @@ enum agentx_type {
   (varbind)->type = type_;               \
   packet += offset;
 
-#define BGP_DATA(varbind, type_, packet) BGP_DATA_(varbind, type_, packet, 4)
+#define SNMP_PUT_OID(buf, size, oid, byte_ord)                             \
+  ({                                                                       \
+    struct agentx_varbind *vb = (void *) buf;                              \
+    SNMP_FILL_VARBIND(vb, oid, byte_ord);                                  \
+  })
+
+#define SNMP_FILL_VARBIND(vb, oid, byte_ord)                               \
+  snmp_oid_copy(&(vb)->name, (oid), (byte_ord)), snmp_oid_size((oid))
+#define SNMP_VB_DATA(varbind)                                              \
+  (((void *)(varbind)) + snmp_varbind_header_size(varbind))
 
 struct agentx_header {
   u8 version;
@@ -273,12 +287,45 @@ enum agentx_response_err {
   AGENTX_RES_PROCESSING_ERR        = 268,
 } PACKED;
 
+struct agentx_context {
+  char *context;  /* string name of this context */
+  uint length;   /* normal strlen() size */
+  /* add buffered context hash? */
+};
+
+struct snmp_pdu_context {
+  byte *buffer;                            /* pointer to buffer */
+  uint size;                       /* unused space in buffer */
+  uint context;                            /* context hash */
+  int byte_ord;                            /* flag signaling NETWORK_BYTE_ORDER */
+  enum agentx_response_err error;   /* storage for result of current action */
+};
+
+struct agentx_alloc_context {
+  u8 is_instance; /* flag INSTANCE_REGISTRATION */
+  u8 new_index;   /* flag NEW_INDEX */
+  u8 any_index;          /* flag ANY_INDEX */
+  char *context;  /* context to allocate in */
+  uint clen;     /* length of context string */
+};
+
+struct additional_buffer {
+  node n;
+  byte *buf;     /* pointer to buffer data */
+  byte *pos;     /* position of first unused byte */
+};
+
 int snmp_rx(sock *sk, uint size);
 int snmp_rx_stop(sock *sk, uint size);
 void snmp_down(struct snmp_proto *p);
 void snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len);
 void snmp_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len);
 
+void snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu_context *c);
+
+struct oid *snmp_prefixize(struct snmp_proto *p, const struct oid *o, int byte_ord);
+u8 snmp_get_mib_class(const struct oid *oid);
+
 // debug wrapper
 #define snmp_log(...) log(L_INFO "snmp " __VA_ARGS__)