]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
fixup! SNMP: tmp -- fix byte order handling
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 13 Aug 2024 15:47:15 +0000 (17:47 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 13 Aug 2024 15:47:15 +0000 (17:47 +0200)
proto/snmp/snmp.c
proto/snmp/snmp.h
proto/snmp/snmp_utils.c
proto/snmp/snmp_utils.h
proto/snmp/subagent.c
proto/snmp/subagent.h

index c37f4394a3307c21bec41d5a811a929f823ab86e..72040aaa0a68c4030ac685fc62d66a3051b5f4fb 100644 (file)
@@ -393,6 +393,9 @@ snmp_cleanup(struct snmp_proto *p)
   rfree(p->lp);
   p->bgp_trie = NULL;
 
+  rfree(p->end_oids);
+  p->end_oids = NULL;
+
   p->state = SNMP_DOWN;
 }
 
@@ -539,6 +542,7 @@ snmp_start(struct proto *P)
   p->lp = lp_new(p->pool);
   p->mib_tree = mb_alloc(p->pool, sizeof(struct mib_tree));
   p->bgp_trie = f_new_trie(p->lp, 0);
+  p->end_oids = lp_new(p->pool);
 
   p->startup_timer = tm_new_init(p->pool, snmp_startup_timeout, p, 0, 0);
   p->ping_timer = tm_new_init(p->pool, snmp_ping_timeout, p, p->timeout, 0);
@@ -675,7 +679,6 @@ static int
 snmp_shutdown(struct proto *P)
 {
   struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
-  return snmp_set_state(p, SNMP_DOWN);
   return snmp_reset(p);
 }
 
index b8c057d23241eeb8f8c7833259fccc7266a15100..7e7968416f977932e81c7ac4ee9c30836d3752ce 100644 (file)
@@ -98,6 +98,7 @@ struct snmp_proto {
   struct object_lock *lock;
   pool *pool;                    /* a shortcut to the procotol mem. pool */
   linpool *lp;                   /* linpool for bgp_trie nodes */
+  linpool *end_oids;
 
   enum snmp_proto_state state;
 
index a64b820e83ec253b764e4c648153ada98377264e..6187eaba3bef82dc35f9a4a716f60ce228fbb25f 100644 (file)
@@ -78,7 +78,7 @@ void
 snmp_varbind_duplicate_hdr(struct snmp_pdu *c, struct agentx_varbind **vb)
 {
   ASSUME(vb != NULL && *vb != NULL);
-  uint hdr_size = snmp_varbind_header_size(*vb->name);
+  uint hdr_size = snmp_varbind_header_size(&(*vb)->name);
   (void) snmp_tbuf_reserve(c, hdr_size);
 
   ASSERT(c->size >= hdr_size);
@@ -158,8 +158,8 @@ snmp_oid_copy(struct oid *dest, const struct oid *src)
 
 /*
  * snmp_oid_from_buf - copy OID from RX buffer to dest in native byte order
- * @dst: destination to use
- * @src: OID to be copied from
+ * @dst: destination to use (native byte order)
+ * @src: OID to be copied from (packet byte order)
  */
 void
 snmp_oid_from_buf(struct oid *dst, const struct oid *src)
@@ -173,6 +173,23 @@ snmp_oid_from_buf(struct oid *dst, const struct oid *src)
     dst->ids[i] = LOAD_U32(src->ids[i]);
 }
 
+/*
+ * snmp_oid_to_buf - copy OID to TX buffer with packet byte order
+ * @dst: destination to use (packet byte order)
+ * @src: OID to be copied from (native byte order)
+ */
+void
+snmp_oid_to_buf(struct oid *dst, const struct oid *src)
+{
+  STORE_U8(dst->n_subid, src->n_subid);
+  STORE_U8(dst->prefix, src->prefix);
+  STORE_U8(dst->include, (src->include) ? 1 : 0);
+  STORE_U8(dst->reserved, 0);
+
+  for (uint i = 0; i < src->n_subid; i++)
+    STORE_U32(dst->ids[i], src->ids[i]);
+}
+
 /*
  * snmp_oid_duplicate - duplicate an OID from memory pool
  * @pool: pool to use
@@ -242,47 +259,6 @@ snmp_oid_size_from_len(uint n_subid)
   return sizeof(struct oid) + n_subid * sizeof(u32);
 }
 
-/*
- * snmp_set_varbind_type - set VarBind's type field
- * @vb: Varbind inside TX buffer
- * @t: a valid type to be set
- *
- * This function assumes valid @t.
- */
-inline enum snmp_search_res
-snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t)
-{
-  ASSUME(t != AGENTX_INVALID);
-  STORE_U16(vb->type, t);
-  STORE_U16(vb->reserved, 0);
-
-  switch (t)
-  {
-    case AGENTX_END_OF_MIB_VIEW:
-      return SNMP_SEARCH_END_OF_VIEW;
-    case AGENTX_NO_SUCH_OBJECT:
-      return SNMP_SEARCH_NO_OBJECT;
-    case AGENTX_NO_SUCH_INSTANCE:
-      return SNMP_SEARCH_NO_INSTANCE;
-
-    /* valid varbind types */
-    case AGENTX_INTEGER:
-    case AGENTX_OCTET_STRING:
-    case AGENTX_NULL:
-    case AGENTX_OBJECT_ID:
-    case AGENTX_IP_ADDRESS:
-    case AGENTX_COUNTER_32:
-    case AGENTX_GAUGE_32:
-    case AGENTX_TIME_TICKS:
-    case AGENTX_OPAQUE:
-    case AGENTX_COUNTER_64:
-      return SNMP_SEARCH_OK;
-
-    default:
-      die("invalid varbind type %d", (int) t);
-  }
-}
-
 static inline uint
 snmp_get_octet_size(const struct agentx_octet_str *str)
 {
@@ -309,13 +285,10 @@ snmp_varbind_header_size(const struct oid *vb_name)
  *
  */
 uint
-snmp_varbind_size_unsafe(const struct agentx_varbind *vb, int is_pkt_bo)
+snmp_varbind_size_unsafe(const struct agentx_varbind *vb)
 {
-  ASSUME(snmp_test_varbind(vb));
-
-  enum agentx_type type = (is_pkt_bo) ? LOAD_U16(vb->type) : vb->type;
-  int value_size = agentx_type_size(type);
-
+  ASSUME(snmp_test_varbind_type(vb->type));
+  int value_size = agentx_type_size(vb->type);
   uint vb_header = snmp_varbind_header_size(&vb->name);
 
   if (value_size == 0)
@@ -324,7 +297,7 @@ snmp_varbind_size_unsafe(const struct agentx_varbind *vb, int is_pkt_bo)
   if (value_size > 0)
     return vb_header + value_size;
 
-  switch (type)
+  switch (vb->type)
   {
     case AGENTX_OBJECT_ID:;
       struct oid *oid = snmp_varbind_data(vb);
@@ -338,30 +311,31 @@ snmp_varbind_size_unsafe(const struct agentx_varbind *vb, int is_pkt_bo)
 
     default:
       /* Shouldn't happen */
-      die("getting size of VarBind with unknown type (%u)", type);
+      die("getting size of VarBind with unknown type (%u)", vb->type);
       return 0;
   }
 }
 
 /**
  * snmp_varbind_size - get size of in-buffer VarBind
- * @vb: VarBind to measure
+ * @vb: VarBind in cpu native byte order to measure
  * @limit: upper limit of bytes that can be used
  *
  * This functions assumes valid VarBind type.
  * Return 0 for Varbinds longer than limit, Varbind's size otherwise.
  */
-uint
+uint UNUSED
 snmp_varbind_size(const struct agentx_varbind *vb, uint limit)
 {
-  //ASSUME(snmp_test_varbind(vb));
-
   if (limit < sizeof(struct agentx_varbind))
     return 0;
 
-  enum agentx_type type = agentx_type_size(snmp_get_varbind_type(vb));
+  if (!snmp_test_varbind_type(vb->type))
+    return 0;
+
+  enum agentx_type type = vb->type;
   int s = agentx_type_size(type);
-  uint vb_header = snmp_varbind_header_size(vb);
+  uint vb_header = snmp_varbind_header_size(&vb->name);
 
   if (limit < vb_header)
     return 0;
@@ -374,17 +348,27 @@ snmp_varbind_size(const struct agentx_varbind *vb, uint limit)
   else if (s > 0)
     return 0;
 
+  uint sz;
   switch (type)
   {
     case AGENTX_OBJECT_ID:;
       struct oid *oid = snmp_varbind_data(vb);
-      return vb_header + snmp_oid_size(oid);
+      /* snmp_oid_size works for both native and packet byte order */
+      sz = snmp_oid_size(oid);
+      if (limit < vb_header + sz)
+       return 0;
+      else
+       return vb_header + snmp_oid_size(oid);
 
     case AGENTX_OCTET_STRING:
     case AGENTX_IP_ADDRESS:
     case AGENTX_OPAQUE:;
       struct agentx_octet_str *os = snmp_varbind_data(vb);
-      return vb_header + snmp_get_octet_size(os);
+      sz = snmp_get_octet_size(os);
+      if (limit < vb_header + sz)
+       return 0;
+      else
+       return vb_header + sz;
 
     default:
       /* This should not happen */
@@ -420,10 +404,10 @@ snmp_varbind_size_from_len(uint n_subid, enum agentx_type type, uint len)
 
 /*
  * snmp_test_varbind - test validity of VarBind type
- * @type: Type of VarBind
+ * @type: Type of VarBind in cpu native byte order
  */
 int
-snmp_test_varbind(u16 type)
+snmp_test_varbind_type(u16 type)
 {
   if (type == AGENTX_INTEGER  ||
       type == AGENTX_OCTET_STRING  ||
@@ -443,31 +427,6 @@ snmp_test_varbind(u16 type)
     return 0;
 }
 
-/*
- * snmp_create_varbind - create a null-typed VarBind in buffer
- * @buf: buffer to use
- */
-struct agentx_varbind *
-snmp_create_varbind_null(byte *buf)
-{
-  struct oid o = { 0 };
-  struct agentx_varbind *vb = snmp_create_varbind(buf, &o);
-  snmp_set_varbind_type(vb, AGENTX_NULL);
-  return vb;
-}
-
-/*
- * snmp_create_varbind - initialize in-buffer non-typed VarBind
- * @buf: pointer to first unused buffer byte
- * @oid: OID to use as VarBind name
- */
-struct agentx_varbind *
-snmp_create_varbind(byte *buf, struct oid *oid)
-{
-  struct agentx_varbind *vb = (void *) buf;
-  snmp_oid_copy(&vb->name, oid);
-  return vb;
-}
 
 /**
  * snmp_oid_ip4_index - check IPv4 address validity in oid
@@ -645,7 +604,7 @@ snmp_oid_compare(const struct oid *left, const struct oid *right)
       (int) right_subids);
     for (int i = 0; i < limit; i++)
     {
-      u32 left_id = left->ids[i + ARRAY_SIZE(snmp_internet + 1)];
+      u32 left_id = left->ids[i + ARRAY_SIZE(snmp_internet) + 1];
       u32 right_id = right->ids[i];
       if (left_id < right_id)
        return -1;
@@ -763,7 +722,7 @@ snmp_varbind_type32(struct agentx_varbind *vb, struct snmp_pdu *c, enum agentx_t
 {
   ASSUME(agentx_type_size(type) == 4); /* type as 4B representation */
 
-  snmp_set_varbind_type(vb, type);
+  vb->type = type;
   u32 *data = snmp_varbind_data(vb);
   STORE_PTR(data, val);
   data++;
@@ -798,7 +757,7 @@ snmp_varbind_gauge32(struct snmp_pdu *c, s64 time)
 inline void
 snmp_varbind_ip4(struct snmp_pdu *c, ip4_addr addr)
 {
-  snmp_set_varbind_type(c->sr_vb_start, AGENTX_IP_ADDRESS);
+  c->sr_vb_start->type = AGENTX_IP_ADDRESS;
   c->buffer = snmp_put_ip4(snmp_varbind_data(c->sr_vb_start), addr);
 }
 
@@ -809,7 +768,7 @@ snmp_varbind_nstr2(struct snmp_pdu *c, uint size, const char *str, uint len)
   if (size < snmp_str_size_from_len(len))
     return NULL;
 
-  snmp_set_varbind_type(c->sr_vb_start, AGENTX_OCTET_STRING);
+  c->sr_vb_start = AGENTX_OCTET_STRING;
   return snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len);
 }
 #endif
@@ -828,7 +787,7 @@ snmp_varbind_nstr2(struct snmp_pdu *c, uint size, const char *str, uint len)
 void
 snmp_varbind_nstr(struct snmp_pdu *c, const char *str, uint len)
 {
-  snmp_set_varbind_type(c->sr_vb_start, AGENTX_OCTET_STRING);
+  c->sr_vb_start->type = AGENTX_OCTET_STRING;
   c->buffer = snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len);
 }
 
@@ -841,7 +800,7 @@ snmp_varbind_nstr(struct snmp_pdu *c, const char *str, uint len)
 void
 snmp_varbind_oid(struct snmp_pdu *c, const struct oid *oid_val)
 {
-  snmp_set_varbind_type(c->sr_vb_start, AGENTX_OBJECT_IDENTIFIER);
+  c->sr_vb_start->type = AGENTX_OBJECT_ID;
   snmp_oid_to_buf(snmp_varbind_data(c->sr_vb_start), oid_val);
 }
 
@@ -943,7 +902,7 @@ snmp_oid_common_ancestor(const struct oid *left, const struct oid *right, struct
 {
   ASSERT(left && right && out);
 
-  out->include, 0;
+  out->include = 0;
   out->reserved = 0;
   out->prefix = 0;
 
@@ -1033,8 +992,6 @@ snmp_walk_init(struct mib_tree *tree, struct mib_walk_state *walk, const struct
 {
   mib_tree_walk_init(walk, tree);
 
-  snmp_vb_to_tx(c, oid);
-
   mib_node_u *node = mib_tree_find(tree, walk, &c->sr_vb_start->name);
 
   // TODO hide me in mib_tree code
@@ -1116,21 +1073,30 @@ snmp_walk_fill(struct mib_leaf *leaf, struct mib_walk_state *walk, struct snmp_p
 {
   struct agentx_varbind *vb = c->sr_vb_start;
 
+  enum agentx_search_res res;
+  if (snmp_oid_compare(&c->sr_vb_start->name, c->sr_o_end) >= 0)
+  {
+    res = AGENTX_END_OF_MIB_VIEW;
+    vb->type = snmp_search_res_to_type(res);
+    return res;
+  }
+
   if (!leaf)
     return SNMP_SEARCH_NO_OBJECT;
 
   uint size = 0;
+  enum agentx_type type = AGENTX_NULL;
   if (leaf->size >= 0)
   {
     if (leaf->type == AGENTX_OCTET_STRING || leaf->type == AGENTX_OPAQUE ||
          leaf->type == AGENTX_OBJECT_ID)
     {
-      snmp_set_varbind_type(vb, leaf->type);
+      type = leaf->type;
       size = leaf->size;
     }
     else if (leaf->type != AGENTX_INVALID)
     {
-      snmp_set_varbind_type(vb, leaf->type);
+      type = leaf->type;
       size = agentx_type_size(leaf->type);
     }
     else
@@ -1138,17 +1104,17 @@ snmp_walk_fill(struct mib_leaf *leaf, struct mib_walk_state *walk, struct snmp_p
   }
 
   (void) snmp_tbuf_reserve(c, size);
+  vb->type = (u16) type;
 
-  enum snmp_search_res res = leaf->filler(walk, c);
+  res = leaf->filler(walk, c);
 
   vb = c->sr_vb_start;
 
   if (res != SNMP_SEARCH_OK)
-    snmp_set_varbind_type(vb, snmp_search_res_to_type(res));
+    vb->type = snmp_search_res_to_type(res);
 
-  u16 type = vb->type;
-  ASSUME(type == leaf->type || type == AGENTX_END_OF_MIB_VIEW || type == AGENTX_NO_SUCH_OBJECT ||
-    type == AGENTX_NO_SUCH_INSTANCE);
+  ASSUME(vb->type == leaf->type || vb->type == AGENTX_END_OF_MIB_VIEW ||
+    vb->type == AGENTX_NO_SUCH_OBJECT || vb->type == AGENTX_NO_SUCH_INSTANCE);
 
   return res;
 }
index 4ac86aa2ce72856d31c44426babf184854bc6b41..41ec42c4969135ebce93212cdcf8284546267aba 100644 (file)
@@ -15,7 +15,6 @@ uint snmp_pkt_len(const byte *start, const byte *end);
 /*
  *  AgentX - Variable Binding (VarBind) type utils
  */
-enum snmp_search_res snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t);
 int agentx_type_size(enum agentx_type t);
 
 /* type Octet String */
@@ -52,7 +51,7 @@ uint snmp_varbind_header_size(const struct oid *vb_name);
 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);
+int snmp_test_varbind_type(u16 type);
 void *snmp_varbind_data(const struct agentx_varbind *vb);
 struct oid *snmp_varbind_set_name_len(struct snmp_pdu *c, struct agentx_varbind **vb, u8 len);
 void snmp_varbind_duplicate_hdr(struct snmp_pdu *c, struct agentx_varbind **vb);
@@ -73,8 +72,6 @@ int snmp_test_close_reason(byte value);
  */
 
 /* 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);
 void snmp_varbind_int(struct snmp_pdu *c, u32 val);
 void snmp_varbind_counter32(struct snmp_pdu *c, u32 val);
 void snmp_varbind_gauge32(struct snmp_pdu *c, s64 time);
index 56f5420a90b11ecb9c3e696b71e9ec652967182c..f1a54a7b52f10439dc52697b2134756bd78f5e6c 100644 (file)
@@ -35,7 +35,7 @@ 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 void response_err_ind(struct agentx_response *res, enum agentx_response_errs err, u16 ind);
 static uint update_packet_size(struct agentx_header *start, byte *end);
 
 /* standard SNMP internet prefix (.1.3.6.1) */
@@ -55,7 +55,7 @@ snmp_header(struct agentx_header *h, enum agentx_pdu_types type, u8 flags)
 {
   STORE_U8(h->version, AGENTX_VERSION);
   STORE_U8(h->type, type);
-  STORE_U8(h->flags, flags | SNMP_ORDER);
+  STORE_U8(h->flags, flags | SNMP_BYTE_ORDER);
   STORE_U8(h->reserved, 0);
   STORE_U32(h->payload, 0);
 }
@@ -123,7 +123,7 @@ snmp_simple_response(struct snmp_proto *p, enum agentx_response_errs error, u16
   ASSUME(c.size >= sizeof(struct agentx_response));
 
   struct agentx_response *res = prepare_response(p, &c);
-  response_err_ind(p, res, error, index);
+  response_err_ind(res, error, index);
   sk_send(sk, sizeof(struct agentx_response));
 }
 
@@ -256,9 +256,10 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
   struct agentx_varbind *trap_vb = (struct agentx_varbind *) c.buffer;
   snmp_oid_to_buf(&trap_vb->name, trap_0);
   /* snmp_oid_size() works for both byte orders same */
-  snmp_varbind_oid(trap_vb, oid);
+  c.sr_vb_start = trap_vb;
+  snmp_varbind_oid(&c, oid);
   ADVANCE(c.buffer, c.size, snmp_varbind_size_unsafe(trap_vb));
-  STORE_U16(trap_vb, trap_vb);
+  STORE_U16(trap_vb->type, trap_vb->type);
   /* We do not need to call the snmp_varbind_leave() because we used the packet
    * byte order in the first place.
    */
@@ -493,20 +494,20 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start)
 
   if (c.error != AGENTX_RES_NO_ERROR)
   {
-    response_err_ind(p, res, c.error, c.index + 1);
+    response_err_ind(res, c.error, c.index + 1);
     snmp_reset(p);
   }
   else if (all_possible)
   {
     /* All values in the agentx-TestSet-PDU are OK, realy to commit them */
-    response_err_ind(p, res, AGENTX_RES_NO_ERROR, 0);
+    response_err_ind(res, AGENTX_RES_NO_ERROR, 0);
   }
   else
   {
     // Currently the only reachable branch
     //TRACE(D_PACKETS, "SNMP SET action failed (not writable)");
     /* This is a recoverable error, we do not need to reset the connection */
-    response_err_ind(p, res, AGENTX_RES_NOT_WRITABLE, c.index + 1);
+    response_err_ind(res, AGENTX_RES_NOT_WRITABLE, c.index + 1);
   }
 
   sk_send(sk, s);
@@ -550,7 +551,7 @@ parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, enum agentx_respons
   c.error = err;
 
   TRACE(D_PACKETS, "SNMP received set PDU with error %u", c.error);
-  response_err_ind(p, r, c.error, 0);
+  response_err_ind(r, c.error, 0);
   sk_send(p->sock, AGENTX_HEADER_SIZE);
 
   /* Reset the connection on unrecoverable error */
@@ -613,7 +614,7 @@ parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start)
   if (pkt_size != 0)
   {
     return AGENTX_HEADER_SIZE;
-    TRACE(D_PACKET, "SNMP received malformed agentx-CleanupSet-PDU");
+    TRACE(D_PACKETS, "SNMP received malformed agentx-CleanupSet-PDU");
     snmp_reset(p);
     return 0;
   }
@@ -657,10 +658,11 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
     return 0;
 
   struct agentx_header *h = (struct agentx_header *) pkt;
-  if (h->flags & AGENTX_NETWORK_BYTE_ORDER)
+  if (h->flags & AGENTX_NETWORK_BYTE_ORDER != SNMP_BYTE_ORDER)
   {
     TRACE(D_PACKETS, "SNMP received PDU with unexpected byte order");
-    snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
+    if (h->type != AGENTX_RESPONSE_PDU)
+      snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
     snmp_reset(p);
     return 0;
   }
@@ -671,7 +673,8 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
   if (pkt_size > SNMP_PKT_SIZE_MAX)
   {
     TRACE(D_PACKETS, "SNMP received PDU is too long");
-    snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
+    if (h->type != AGENTX_RESPONSE_PDU)
+      snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
     snmp_reset(p);
     return 0;
   }
@@ -802,7 +805,6 @@ parse_response(struct snmp_proto *p, byte *res)
     case AGENTX_RES_PROCESSING_ERR:
     default:
       TRACE(D_PACKETS, "SNMP agentx-Response-PDU with unexepected error %u", r->error);
-      //snmp_stop(p);
       snmp_reset(p);
       break;
   }
@@ -896,10 +898,8 @@ snmp_oid_prefixize_unsafe(struct oid *dest, const struct oid *src)
   dest->reserved = 0;
 
   /* The LOAD_U32() and STORE_U32() cancel out */
-  for (i = 0; i < dest->n_subid; i++)
+  for (u8 i = 0; i < dest->n_subid; i++)
     dest->ids[i] = LOAD_U32(src->ids[i + 5]);
-
-  return dest;
 }
 
 /*
@@ -911,7 +911,7 @@ snmp_oid_prefixize_unsafe(struct oid *dest, const struct oid *src)
  * is @oid. Because we want to simplify code dealing with OIDs, the byte order
  * of the name is optionally swapped to match cpu native byte order.
  */
-void
+struct agentx_varbind *
 snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid)
 {
   uint vb_hdr_size = snmp_varbind_header_size(oid);
@@ -921,7 +921,7 @@ snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid)
   struct agentx_varbind *vb = (struct agentx_varbind *) c->buffer;
   ADVANCE(c->buffer, c->size, sizeof(struct agentx_varbind) - sizeof(struct oid));
   /* Move the c->buffer so that is points at &vb->name */
-  snmp_set_varbind_type(vb, AGENTX_NULL);
+  vb->type = AGENTX_NULL;
 
   if (snmp_oid_is_prefixable(oid) && !snmp_oid_is_prefixed(oid))
   {
@@ -929,14 +929,13 @@ snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid)
     ADVANCE(c->buffer, c->size, snmp_oid_size_from_len(subids));
     snmp_oid_prefixize_unsafe(&vb->name, oid);
 
-    c->sr_vb_start = vb;
-    return;
+    return vb;
   }
 
   ADVANCE(c->buffer, c->size, snmp_oid_size(oid));
   snmp_oid_from_buf(&vb->name, oid);
 
-  c->sr_vb_start = vb;
+  return vb;
 }
 
 /*
@@ -977,7 +976,6 @@ update_packet_size(struct agentx_header *start, byte *end)
 
 /*
  * response_err_ind - update response error and index
- * @p: SNMP protocol instance
  * @res: response PDU header
  * @err: error status
  * @ind: index of error, ignored for noAgentXError
@@ -986,7 +984,7 @@ update_packet_size(struct agentx_header *start, byte *end)
  * error is not noError, also set the corrent response PDU payload size.
  */
 static inline void
-response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_response_errs err, u16 ind)
+response_err_ind(struct agentx_response *res, enum agentx_response_errs err, u16 ind)
 {
   STORE_U16(res->error, (u16) err);
   // TODO deal with auto-incrementing of snmp_pdu context c.ind
@@ -1019,27 +1017,27 @@ void
 snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk)
 {
   struct mib_leaf *leaf;
-  leaf = snmp_walk_init(p->mib_tree, walk, o_start, c);
+  leaf = snmp_walk_init(p->mib_tree, walk, &c->sr_vb_start->name, c);
 
   enum snmp_search_res res;
   res = snmp_walk_fill(leaf, walk, c);
 
   if (res != SNMP_SEARCH_OK)
-    snmp_set_varbind_type(c->sr_vb_start, snmp_search_res_to_type(res));
+    c->sr_vb_start->type = snmp_search_res_to_type(res);
 }
 
 /* agentx-GetNext-PDU */
 int
 snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk)
 {
-  (void) snmp_walk_init(p->mib_tree, walk, o_start, c);
+  (void) snmp_walk_init(p->mib_tree, walk, &c->sr_vb_start->name, c);
   struct mib_leaf *leaf = snmp_walk_next(p->mib_tree, walk, c);
 
   enum snmp_search_res res;
   res = snmp_walk_fill(leaf, walk, c);
 
   if (res != SNMP_SEARCH_OK)
-    snmp_set_varbind_type(c->sr_vb_start, AGENTX_END_OF_MIB_VIEW);
+    c->sr_vb_start->type = AGENTX_END_OF_MIB_VIEW;
 
   return res == SNMP_SEARCH_OK;
 }
@@ -1056,53 +1054,63 @@ snmp_get_bulk_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_
   bulk->has_any |= snmp_get_next_pdu(p, c, o_start, walk);
 }
 
-static inline const struct oid *
+int
 snmp_load_oids(byte **pkt_ptr, uint *pkt_sz, struct snmp_pdu *c)
 {
   byte *pkt = *pkt_ptr;
   uint pkt_size = *pkt_sz;
 
   uint sz;
-  const struct oid *start = (const struct oid *) pkt;
-
-  if ((sz = snmp_oid_size(start)) > pkt_size)
+  /* in packet byte order */
+  const struct oid *start_buf = (const struct oid *) pkt;
+  if ((sz = snmp_oid_size(start_buf)) > pkt_size ||
+      LOAD_U8(start_buf->n_subid) >= OID_MAX_LEN)
   {
     c->error = AGENTX_RES_PARSE_ERROR;
     *pkt_ptr = pkt;
     *pkt_sz = pkt_size;
-    return NULL;
+    return 0;
   }
 
   ADVANCE(pkt, pkt_size, sz);
 
-  const struct oid *end = (const struct oid *) pkt;
-  if ((sz = snmp_oid_size(end)) > pkt_size)
+  /* in packet byte order */
+  const struct oid *end_buf = (const struct oid *) pkt;
+  if ((sz = snmp_oid_size(end_buf)) > pkt_size ||
+      LOAD_U8(end_buf->n_subid) >= OID_MAX_LEN)
   {
     c->error = AGENTX_RES_PARSE_ERROR;
     *pkt_ptr = pkt;
     *pkt_sz = pkt_size;
-    return NULL;
+    return 0;
   }
 
+  /* in cpu native byte order */
+  struct agentx_varbind *start_vb = snmp_vb_to_tx(c, start_buf);
+
+  /* in cpu native byte order */
+  struct oid *end_oid = tmp_alloc(sz);
+  snmp_oid_from_buf(end_oid, end_buf);
+
   ADVANCE(pkt, pkt_size, sz);
 
-  // TODO: this does not work
-  if (!snmp_is_oid_empty(end) &&
-      snmp_oid_compare(start, end) > 0)
+  if (!snmp_is_oid_empty(end_oid) &&
+      snmp_oid_compare(&start_vb->name, end_oid) > 0)
   {
     c->error = AGENTX_RES_GEN_ERROR;
     *pkt_ptr = pkt;
     *pkt_sz = pkt_size;
-    return NULL;
+    return 0;
   }
 
-  ASSERT(start != NULL);
-  ASSERT(end != NULL);
+  ASSERT(start_vb != NULL);
+  ASSERT(end_oid != NULL);
 
-  c->sr_o_end = end;
+  c->sr_vb_start = start_vb;
+  c->sr_o_end = end_oid;
   *pkt_ptr = pkt;
   *pkt_sz = pkt_size;
-  return start;
+  return 1; /* ok */
 }
 
 /*
@@ -1169,13 +1177,12 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
   {
     lp_restore(tmp_linpool, &tmps);
 
-    const struct oid *start_rx;
-    if (!(start_rx = snmp_load_oids(&pkt, &pkt_size, &c)))
+    if (!snmp_load_oids(&pkt, &pkt_size, &c))
     {
       snmp_simple_response(p, c.error,
        (c.index > UINT16_MAX) ? UINT16_MAX : c.index);
       snmp_reset(p);
-      return pkt_size + AGENTX_HEADER_SIZE;
+      return 0;
     }
 
     switch (h->type)
@@ -1196,6 +1203,8 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
        die("implementation failure");
     }
 
+    snmp_varbind_leave(c.sr_vb_start);
+
     c.sr_vb_start = NULL;
     c.sr_o_end = NULL;
 
@@ -1213,7 +1222,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
 #endif
 
   /* We update the error, index pair on the beginning of the packet. */
-  response_err_ind(p, response_header, c.error, c.index + 1);
+  response_err_ind(response_header, c.error, c.index + 1);
   uint s = update_packet_size(&response_header->h, c.buffer);
 
   /* We send the message in TX buffer. */
index a2c0807a441bc619d225600c1685ada43f6a8c97..3e922d929e716c59a24bdc5a18e50b496fe3e8c2 100644 (file)
@@ -87,7 +87,7 @@ enum agentx_flags {
   | AGENTX_NETWORK_BYTE_ORDER)
 
 // TODO - make me compile time option
-#define SNMP_NATIVE
+#define SNMP_NETWORK_BYTE_ORDER
 
 #if !(defined(SNMP_NATIVE) || defined(SNMP_NETWORK_BYTE_ORDER))
 # error "SNMP: currently support only native byte order or network byte order."
@@ -99,9 +99,9 @@ enum agentx_flags {
 #endif
 
 #if (defined(SNMP_NATIVE) && defined(CPU_BIG_ENDIAN)) || defined(SNMP_NETWORK_BYTE_ORDER)
-#define SNMP_ORDER AGENTX_NETWORK_BYTE_ORDER
+#define SNMP_BYTE_ORDER AGENTX_NETWORK_BYTE_ORDER
 #else
-#define SNMP_ORDER 0
+#define SNMP_BYTE_ORDER 0
 #endif
 
 /* We recommend using STORE_U32 over VALUE_U32 when possible */
@@ -359,7 +359,7 @@ snmp_is_active(const struct snmp_proto *p)
       p->state == SNMP_CONN;
 }
 
-void snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid);
+struct agentx_varbind *snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid);
 u8 snmp_get_mib_class(const struct oid *oid);
 
 void snmp_register_mibs(struct snmp_proto *p);