0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

SNMP: tmp -- fix byte order handling

This commit is contained in:
Vojtech Vilimek 2024-08-10 00:07:49 +02:00
parent a70ab3051f
commit dd8d706e1b
8 changed files with 294 additions and 308 deletions

View File

@ -245,6 +245,7 @@ snmp_bgp4_register(struct snmp_proto *p)
struct oid *oid = mb_allocz(p->pool, struct oid *oid = mb_allocz(p->pool,
snmp_oid_size_from_len(ARRAY_SIZE(bgp_mib_prefix))); snmp_oid_size_from_len(ARRAY_SIZE(bgp_mib_prefix)));
print(;
STORE_U8(oid->n_subid, ARRAY_SIZE(bgp_mib_prefix)); STORE_U8(oid->n_subid, ARRAY_SIZE(bgp_mib_prefix));
STORE_U8(oid->prefix, SNMP_MGMT); STORE_U8(oid->prefix, SNMP_MGMT);
@ -284,10 +285,10 @@ ip4_to_oid(struct oid *o, ip4_addr addr)
{ {
u32 tmp = ip4_to_u32(addr); u32 tmp = ip4_to_u32(addr);
ASSUME(o->n_subid >= 9); ASSUME(o->n_subid >= 9);
STORE_U32(o->ids[5], (tmp & 0xFF000000) >> 24); o->ids[5] = (tmp & 0xFF000000) >> 24;
STORE_U32(o->ids[6], (tmp & 0x00FF0000) >> 16); o->ids[6] = (tmp & 0x00FF0000) >> 16;
STORE_U32(o->ids[7], (tmp & 0x0000FF00) >> 8); o->ids[7] = (tmp & 0x0000FF00) >> 8;
STORE_U32(o->ids[8], (tmp & 0x000000FF) >> 0); o->ids[8] = (tmp & 0x000000FF) >> 0;
} }
static void UNUSED static void UNUSED
@ -337,7 +338,7 @@ populate_bgp4(struct snmp_pdu *c, ip4_addr *addr, const struct bgp_proto **proto
**conn, const struct bgp_stats **stats, const struct bgp_config **config) **conn, const struct bgp_stats **stats, const struct bgp_config **config)
{ {
const struct oid * const oid = &c->sr_vb_start->name; const struct oid * const oid = &c->sr_vb_start->name;
if (snmp_bgp_valid_ip4(oid) && LOAD_U8(oid->n_subid) == 9) if (snmp_bgp_valid_ip4(oid) && oid->n_subid == 9)
*addr = ip4_from_oid(oid); *addr = ip4_from_oid(oid);
else else
return SNMP_SEARCH_NO_INSTANCE; return SNMP_SEARCH_NO_INSTANCE;
@ -378,7 +379,7 @@ populate_bgp4(struct snmp_pdu *c, ip4_addr *addr, const struct bgp_proto **proto
static enum snmp_search_res static enum snmp_search_res
fill_bgp_version(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c) fill_bgp_version(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c)
{ {
if (LOAD_U8(c->sr_vb_start->name.n_subid) != 3) if (c->sr_vb_start->name.n_subid != 3)
return SNMP_SEARCH_NO_INSTANCE; return SNMP_SEARCH_NO_INSTANCE;
c->size -= snmp_str_size_from_len(1); c->size -= snmp_str_size_from_len(1);
snmp_varbind_nstr(c, BGP4_VERSIONS, 1); snmp_varbind_nstr(c, BGP4_VERSIONS, 1);
@ -388,7 +389,7 @@ fill_bgp_version(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c)
static enum snmp_search_res static enum snmp_search_res
fill_local_as(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c) fill_local_as(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c)
{ {
if (LOAD_U8(c->sr_vb_start->name.n_subid) != 3) if (c->sr_vb_start->name.n_subid != 3)
return SNMP_SEARCH_NO_INSTANCE; return SNMP_SEARCH_NO_INSTANCE;
snmp_varbind_int(c, c->p->bgp_local_as); snmp_varbind_int(c, c->p->bgp_local_as);
return SNMP_SEARCH_OK; return SNMP_SEARCH_OK;
@ -743,7 +744,7 @@ fill_in_update_elapsed_time(struct mib_walk_state *walk UNUSED, struct snmp_pdu
static enum snmp_search_res static enum snmp_search_res
fill_local_id(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c) fill_local_id(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c)
{ {
if (LOAD_U8(c->sr_vb_start->name.n_subid) != 3) if (c->sr_vb_start->name.n_subid != 3)
return SNMP_SEARCH_NO_INSTANCE; return SNMP_SEARCH_NO_INSTANCE;
snmp_varbind_ip4(c, c->p->bgp_local_id); snmp_varbind_ip4(c, c->p->bgp_local_id);
return SNMP_SEARCH_OK; return SNMP_SEARCH_OK;
@ -771,10 +772,10 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c)
const struct oid *peer_oid = (const struct oid *) &bgp4_peer_id; const struct oid *peer_oid = (const struct oid *) &bgp4_peer_id;
int precise = 1; int precise = 1;
if (LOAD_U8(oid->n_subid) > 9) if (oid->n_subid > 9)
precise = 0; precise = 0;
if (LOAD_U8(oid->n_subid) != 9 || snmp_oid_compare(oid, peer_oid) < 0) if (oid->n_subid != 9 || snmp_oid_compare(oid, peer_oid) < 0)
{ {
int old = snmp_oid_size(oid); int old = snmp_oid_size(oid);
int new = snmp_oid_size(peer_oid); int new = snmp_oid_size(peer_oid);
@ -785,7 +786,7 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c)
c->buffer += (new - old); c->buffer += (new - old);
snmp_oid_copy(oid, peer_oid); snmp_oid_copy(oid, peer_oid);
STORE_U8(oid->include, 1); oid->include = 1;
} }
ASSUME(oid->n_subid == 9); ASSUME(oid->n_subid == 9);
@ -799,9 +800,9 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c)
int match = trie_walk_init(&ws, c->p->bgp_trie, &net, 1); int match = trie_walk_init(&ws, c->p->bgp_trie, &net, 1);
if (match && LOAD_U8(oid->include) && precise) if (match && oid->include && precise)
{ {
STORE_U8(oid->include, 0); oid->include = 0;
ip4_to_oid(oid, ip4); ip4_to_oid(oid, ip4);
return 0; return 0;
} }

View File

@ -46,13 +46,13 @@ mib_tree_init(pool *p, struct mib_tree *t)
struct oid *oid = tmp_alloc( struct oid *oid = tmp_alloc(
snmp_oid_size_from_len((uint) ARRAY_SIZE(snmp_internet))); snmp_oid_size_from_len((uint) ARRAY_SIZE(snmp_internet)));
STORE_U8(oid->n_subid, ARRAY_SIZE(snmp_internet)); oid->n_subid = ARRAY_SIZE(snmp_internet);
STORE_U8(oid->prefix, 0); oid->prefix = 0;
STORE_U8(oid->include, 0); oid->include = 0;
STORE_U8(oid->reserved, 0); oid->reserved = 0;
for (size_t i = 0; i < ARRAY_SIZE(snmp_internet); i++) for (size_t i = 0; i < ARRAY_SIZE(snmp_internet); i++)
STORE_U32(oid->ids[i], snmp_internet[i]); oid->ids[i] = snmp_internet[i];
(void) mib_tree_add(p, t, oid, 0); (void) mib_tree_add(p, t, oid, 0);
} }
@ -110,7 +110,7 @@ mib_tree_add(pool *p, struct mib_tree *t, const struct oid *oid, int is_leaf)
mib_tree_walk_init(&walk, t); mib_tree_walk_init(&walk, t);
node = mib_tree_find(t, &walk, oid); node = mib_tree_find(t, &walk, oid);
ASSERT(walk.id_pos <= LOAD_U8(oid->n_subid) + 1); ASSERT(walk.id_pos <= oid->n_subid + 1);
if (node) if (node)
{ {
@ -122,7 +122,7 @@ mib_tree_add(pool *p, struct mib_tree *t, const struct oid *oid, int is_leaf)
return NULL; return NULL;
} }
ASSERT(walk.id_pos < LOAD_U8(oid->n_subid) + 1); ASSERT(walk.id_pos < oid->n_subid + 1);
node = walk.stack[walk.stack_pos - 1]; node = walk.stack[walk.stack_pos - 1];
/* we encounter leaf node before end of OID's id path */ /* we encounter leaf node before end of OID's id path */
@ -161,14 +161,14 @@ mib_tree_add(pool *p, struct mib_tree *t, const struct oid *oid, int is_leaf)
if (walk.stack_pos == ARRAY_SIZE(snmp_internet) + 1) if (walk.stack_pos == ARRAY_SIZE(snmp_internet) + 1)
{ {
u32 old_len = node_inner->child_len; u32 old_len = node_inner->child_len;
node_inner->child_len = MAX(old_len, (u32) LOAD_U8(oid->prefix) + 1); node_inner->child_len = MAX(old_len, (u32) oid->prefix + 1);
node_inner->children = realloc(node_inner->children, node_inner->children = realloc(node_inner->children,
node_inner->child_len * sizeof(mib_node_u *)); node_inner->child_len * sizeof(mib_node_u *));
for (u32 i = old_len; i < node_inner->child_len; i++) for (u32 i = old_len; i < node_inner->child_len; i++)
node_inner->children[i] = NULL; node_inner->children[i] = NULL;
if (is_leaf && !LOAD_U8(oid->n_subid)) if (is_leaf && !oid->n_subid)
{ {
node = allocz(sizeof(struct mib_leaf)); node = allocz(sizeof(struct mib_leaf));
node->empty.flags = MIB_TREE_LEAF; node->empty.flags = MIB_TREE_LEAF;
@ -179,9 +179,9 @@ mib_tree_add(pool *p, struct mib_tree *t, const struct oid *oid, int is_leaf)
node->empty.flags = 0; node->empty.flags = 0;
} }
node->empty.id = LOAD_U8(oid->prefix); node->empty.id = oid->prefix;
/* add node into the parent's children array */ /* add node into the parent's children array */
node_inner->children[LOAD_U8(oid->prefix)] = node; node_inner->children[oid->prefix] = node;
node_inner = &node->inner; node_inner = &node->inner;
walk.stack[walk.stack_pos++] = node; walk.stack[walk.stack_pos++] = node;
} }
@ -190,17 +190,17 @@ mib_tree_add(pool *p, struct mib_tree *t, const struct oid *oid, int is_leaf)
/* snmp_internet + 2 = empty + snmp_internet + prefix */ /* snmp_internet + 2 = empty + snmp_internet + prefix */
if (snmp_oid_is_prefixed(oid) && if (snmp_oid_is_prefixed(oid) &&
walk.stack_pos == ARRAY_SIZE(snmp_internet) + 2 && walk.stack_pos == ARRAY_SIZE(snmp_internet) + 2 &&
LOAD_U8(oid->n_subid) == 0 && oid->n_subid == 0 &&
mib_node_is_leaf(node) == is_leaf) mib_node_is_leaf(node) == is_leaf)
return node; return node;
if (mib_node_is_leaf(node)) if (mib_node_is_leaf(node))
return node; return node;
u8 subids = LOAD_U8(oid->n_subid); u8 subids = oid->n_subid;
u32 old_len = node_inner->child_len; u32 old_len = node_inner->child_len;
u32 child_id = oid->ids[walk.id_pos]; u32 child_id = oid->ids[walk.id_pos];
node_inner->child_len = MAX(old_len, LOAD_U32(child_id) + 1); node_inner->child_len = MAX(old_len, child_id + 1);
node_inner->children = realloc(node_inner->children, node_inner->children = realloc(node_inner->children,
node_inner->child_len * sizeof(mib_node_u *)); node_inner->child_len * sizeof(mib_node_u *));
@ -217,7 +217,7 @@ mib_tree_add(pool *p, struct mib_tree *t, const struct oid *oid, int is_leaf)
parent->children[child_id] = (mib_node_u *) node_inner; parent->children[child_id] = (mib_node_u *) node_inner;
node_inner->c.id = child_id; node_inner->c.id = child_id;
child_id = LOAD_U32(oid->ids[++walk.id_pos]); child_id = oid->ids[++walk.id_pos];
node_inner->child_len = child_id + 1; node_inner->child_len = child_id + 1;
node_inner->children = allocz(node_inner->child_len * sizeof(mib_node_u *)); node_inner->children = allocz(node_inner->child_len * sizeof(mib_node_u *));
@ -430,14 +430,14 @@ mib_tree_find(const struct mib_tree *t, struct mib_walk_state *walk, const struc
/* In any of cases below we did not move in the tree therefore the /* In any of cases below we did not move in the tree therefore the
* walk->id_pos is left untouched. */ * walk->id_pos is left untouched. */
if (snmp_oid_is_prefixed(oid) && if (snmp_oid_is_prefixed(oid) &&
LOAD_U8(oid->n_subid) + ARRAY_SIZE(snmp_internet) + 1 == walk->id_pos) oid->n_subid + ARRAY_SIZE(snmp_internet) + 1 == walk->id_pos)
return node; return node;
else if (snmp_oid_is_prefixed(oid) && else if (snmp_oid_is_prefixed(oid) &&
LOAD_U8(oid->n_subid) + ARRAY_SIZE(snmp_internet) + 1 > walk->id_pos) oid->n_subid + ARRAY_SIZE(snmp_internet) + 1 > walk->id_pos)
return NULL; return NULL;
else if (!snmp_oid_is_prefixed(oid) && LOAD_U8(oid->n_subid) + 1 == walk->id_pos) else if (!snmp_oid_is_prefixed(oid) && oid->n_subid + 1 == walk->id_pos)
return node; return node;
} }
@ -470,7 +470,7 @@ mib_tree_find(const struct mib_tree *t, struct mib_walk_state *walk, const struc
} }
/* walking the prefix continuation (OID field oid->prefix) */ /* walking the prefix continuation (OID field oid->prefix) */
u8 prefix = LOAD_U8(oid->prefix); u8 prefix = oid->prefix;
if (node_inner->child_len <= prefix) if (node_inner->child_len <= prefix)
return NULL; return NULL;
@ -483,18 +483,18 @@ mib_tree_find(const struct mib_tree *t, struct mib_walk_state *walk, const struc
ASSERT(node->empty.id == prefix); ASSERT(node->empty.id == prefix);
walk->stack[walk->stack_pos++] = node; walk->stack[walk->stack_pos++] = node;
if (mib_node_is_leaf(node) && LOAD_U8(oid->n_subid) > 0) if (mib_node_is_leaf(node) && oid->n_subid > 0)
return NULL; return NULL;
} }
u8 subids = LOAD_U8(oid->n_subid); u8 subids = oid->n_subid;
if (subids == 0) if (subids == 0)
return (node == (mib_node_u *) &t->root) ? NULL : node; return (node == (mib_node_u *) &t->root) ? NULL : node;
/* loop for all OID's ids except the last one */ /* loop for all OID's ids except the last one */
for (; oid_pos < subids - 1 && walk->stack_pos < MIB_WALK_STACK_SIZE + 1; oid_pos++) for (; oid_pos < subids - 1 && walk->stack_pos < MIB_WALK_STACK_SIZE + 1; oid_pos++)
{ {
u32 id = LOAD_U32(oid->ids[oid_pos]); u32 id = oid->ids[oid_pos];
if (node_inner->child_len <= id) if (node_inner->child_len <= id)
{ {
/* The walk->id_pos points after the last accepted OID id. /* The walk->id_pos points after the last accepted OID id.
@ -527,7 +527,7 @@ mib_tree_find(const struct mib_tree *t, struct mib_walk_state *walk, const struc
} }
walk->id_pos = oid_pos; walk->id_pos = oid_pos;
u32 last_id = LOAD_U32(oid->ids[oid_pos]); u32 last_id = oid->ids[oid_pos];
if (node_inner->child_len <= last_id || if (node_inner->child_len <= last_id ||
walk->stack_pos >= MIB_WALK_STACK_SIZE + 1) walk->stack_pos >= MIB_WALK_STACK_SIZE + 1)
return NULL; return NULL;
@ -598,9 +598,9 @@ mib_tree_walk_to_oid(const struct mib_walk_state *walk, struct oid *result, u32
/* skip empty prefix, whole snmp_internet .1.3.6.1 and oid->prefix */ /* skip empty prefix, whole snmp_internet .1.3.6.1 and oid->prefix */
index = 2 + ARRAY_SIZE(snmp_internet); index = 2 + ARRAY_SIZE(snmp_internet);
STORE_U8(result->n_subid, walk->stack_pos - (ARRAY_SIZE(snmp_internet) + 2)); result->n_subid = walk->stack_pos - (ARRAY_SIZE(snmp_internet) + 2);
STORE_U8(result->prefix, result->prefix = \
walk->stack[ARRAY_SIZE(snmp_internet) + 1]->empty.id); walk->stack[ARRAY_SIZE(snmp_internet) + 1]->empty.id;
} }
else else
{ {
@ -608,17 +608,17 @@ mib_tree_walk_to_oid(const struct mib_walk_state *walk, struct oid *result, u32
return 1; return 1;
index = 1; /* skip empty prefix */ index = 1; /* skip empty prefix */
STORE_U8(result->n_subid, walk->stack_pos - 1); result->n_subid = walk->stack_pos - 1;
STORE_U8(result->prefix, 0); result->prefix = 0;
} }
STORE_U8(result->include, 0); result->include = 0;
STORE_U8(result->reserved, 0); result->reserved = 0;
u32 i = 0; u32 i = 0;
/* the index could point after last stack array element */ /* the index could point after last stack array element */
for (; index < walk->stack_pos && index < MIB_WALK_STACK_SIZE; index++) for (; index < walk->stack_pos && index < MIB_WALK_STACK_SIZE; index++)
STORE_U32(result->ids[i++], walk->stack[index]->empty.id); result->ids[i++] = walk->stack[index]->empty.id;
return 0; return 0;
} }
@ -639,9 +639,9 @@ mib_tree_walk_oid_compare(const struct mib_walk_state *walk, const struct oid *o
uint walk_idx = 1; uint walk_idx = 1;
u8 walk_subids = walk->stack_pos; /* left_subids */ u8 walk_subids = walk->stack_pos; /* left_subids */
u8 oid_subids = LOAD_U8(oid->n_subid); /* right_subids */ u8 oid_subids = oid->n_subid; /* right_subids */
const u8 oid_prefix = LOAD_U8(oid->prefix); const u8 oid_prefix = oid->prefix;
if (oid_prefix != 0) if (oid_prefix != 0)
{ {
@ -668,7 +668,7 @@ mib_tree_walk_oid_compare(const struct mib_walk_state *walk, const struct oid *o
for (; i < oid_subids && walk_idx < walk_subids; i++, walk_idx++) for (; i < oid_subids && walk_idx < walk_subids; i++, walk_idx++)
{ {
u32 walk_id = walk->stack[walk_idx]->empty.id; u32 walk_id = walk->stack[walk_idx]->empty.id;
u32 oid_id = LOAD_U32(oid->ids[i]); u32 oid_id = oid->ids[i];
if (walk_id < oid_id) if (walk_id < oid_id)
return -1; return -1;
else if (walk_id > oid_id) else if (walk_id > oid_id)
@ -714,16 +714,16 @@ mib_tree_walk_is_oid_descendant(const struct mib_walk_state *walk, const struct
return +1; return +1;
if (i < walk->stack_pos && if (i < walk->stack_pos &&
walk->stack[i]->empty.id != (u32)LOAD_U8(oid->prefix)) walk->stack[i]->empty.id != (u32) oid->prefix)
return -1; return -1;
i++; i++;
} }
u32 ids = LOAD_U8(oid->n_subid); u32 ids = oid->n_subid;
for (; i < walk->stack_pos && j < ids; i++, j++) for (; i < walk->stack_pos && j < ids; i++, j++)
{ {
if (walk->stack[i]->empty.id != LOAD_U32(oid->ids[j])) if (walk->stack[i]->empty.id != oid->ids[j])
return -1; return -1;
} }

View File

@ -140,10 +140,10 @@ void agentx_get_mib_init(pool *p)
struct oid *dest = mb_alloc(p, size); struct oid *dest = mb_alloc(p, size);
memcpy(dest, src, size); memcpy(dest, src, size);
u8 ids = LOAD_U8(src->n_subid); u8 ids = src->n_subid;
if (ids > 0) if (ids > 0)
STORE_U32(dest->ids[ids - 1], LOAD_U32(src->ids[ids - 1]) + 1); dest->ids[ids - 1] = src->ids[ids - 1] + 1;
agentx_available_mibs[AGENTX_MIB_COUNT] = dest; agentx_available_mibs[AGENTX_MIB_COUNT] = dest;
} }

View File

@ -783,17 +783,17 @@ t_walk_oid_desc(void)
case 1: case 1:
{ {
/* oid is longer than walk or has same length */ /* oid is longer than walk or has same length */
u8 ids = LOAD_U8(oid->n_subid); u8 ids = oid->n_subid;
u32 upto = MIN(OID_MAX_LEN - ids, 16); u32 upto = MIN(OID_MAX_LEN - ids, 16);
if (!upto) if (!upto)
continue; continue;
u32 new = xrandom(upto) + 1; u32 new = xrandom(upto) + 1;
STORE_U8(oid->n_subid, ids + new); oid->n_subid = ids + new;
for (u32 i = 0; i < new; i++) for (u32 i = 0; i < new; i++)
STORE_U32(oid->ids[ids + i], xrandom(OID_MAX_ID)); oid->ids[ids + i] = xrandom(OID_MAX_ID);
bt_assert(mib_tree_walk_is_oid_descendant(&walk, oid) > 0); bt_assert(mib_tree_walk_is_oid_descendant(&walk, oid) > 0);
@ -803,7 +803,7 @@ t_walk_oid_desc(void)
case 3: case 3:
{ {
/* oid is shorter than walk */ /* oid is shorter than walk */
u8 ids = LOAD_U8(oid->n_subid); u8 ids = oid->n_subid;
if (ids == 0 || ids == OID_MAX_LEN) if (ids == 0 || ids == OID_MAX_LEN)
continue; continue;
@ -811,14 +811,14 @@ t_walk_oid_desc(void)
u32 split = (ids > 1) ? xrandom(ids - 1) + 1 : 0; u32 split = (ids > 1) ? xrandom(ids - 1) + 1 : 0;
u32 ext = (type == 3) ? xrandom(MIN(OID_MAX_LEN - ids, 16)) : 0; u32 ext = (type == 3) ? xrandom(MIN(OID_MAX_LEN - ids, 16)) : 0;
STORE_U16(oid->n_subid, split + ext); oid->n_subid = split + ext;
for (u32 i = 0; i < ext; i++) for (u32 i = 0; i < ext; i++)
STORE_U32(oid->ids[split + i], xrandom(OID_MAX_ID)); oid->ids[split + i] = xrandom(OID_MAX_ID);
int no_change = 1; int no_change = 1;
for (u32 j = 0; j < MIN(ids - split, ext); j++) for (u32 j = 0; j < MIN(ids - split, ext); j++)
{ {
if (LOAD_U32(oid->ids[split + j]) != LOAD_U32(oids[i]->ids[split + j])) if (oid->ids[split + j] != oids[i]->ids[split + j])
no_change = 0; no_change = 0;
} }
@ -897,18 +897,18 @@ t_walk_oid_compare(void)
case 1: case 1:
{ {
/* oid is longer than walk or has same length */ /* oid is longer than walk or has same length */
u8 ids = LOAD_U8(oid->n_subid); u8 ids = oid->n_subid;
u32 upto = MIN(OID_MAX_LEN - ids, 16); u32 upto = MIN(OID_MAX_LEN - ids, 16);
if (!upto) if (!upto)
continue; continue;
u32 new = xrandom(upto) + 1; u32 new = xrandom(upto) + 1;
STORE_U8(oid->n_subid, ids + new); oid->n_subid = ids + new;
ASSERT(snmp_oid_size(oid) < 1024); ASSERT(snmp_oid_size(oid) < 1024);
for (u32 i = 0; i < new; i++) for (u32 i = 0; i < new; i++)
STORE_U32(oid->ids[ids + i], xrandom(OID_MAX_ID)); oid->ids[ids + i] = xrandom(OID_MAX_ID);
bt_assert(mib_tree_walk_oid_compare(&walk, oid) < 0); bt_assert(mib_tree_walk_oid_compare(&walk, oid) < 0);
@ -918,7 +918,7 @@ t_walk_oid_compare(void)
case 3: case 3:
{ {
/* oid is shorter than walk */ /* oid is shorter than walk */
u8 ids = LOAD_U8(oid->n_subid); u8 ids = oid->n_subid;
if (ids == 0 || ids == OID_MAX_LEN) if (ids == 0 || ids == OID_MAX_LEN)
continue; continue;
@ -926,13 +926,13 @@ t_walk_oid_compare(void)
u32 split = (ids > 1) ? xrandom(ids - 1) + 1 : 0; u32 split = (ids > 1) ? xrandom(ids - 1) + 1 : 0;
u32 ext = (type == 3) ? xrandom(MIN(OID_MAX_LEN - ids, 16)) : 0; u32 ext = (type == 3) ? xrandom(MIN(OID_MAX_LEN - ids, 16)) : 0;
STORE_U16(oid->n_subid, split + ext); oid->n_subid = split + ext;
for (u32 i = 0; i < ext; i++) for (u32 i = 0; i < ext; i++)
STORE_U32(oid->ids[split + i], xrandom(OID_MAX_ID)); oid->ids[split + i] = xrandom(OID_MAX_ID);
int cmp_res = 0; int cmp_res = 0;
for (u32 j = 0; j < MIN(ids - split, ext) && !cmp_res; j++) for (u32 j = 0; j < MIN(ids - split, ext) && !cmp_res; j++)
cmp_res = LOAD_U32(oids[i]->ids[split + j]) - LOAD_U32(oid->ids[split + j]); cmp_res = oids[i]->ids[split + j] - oid->ids[split + j];
if (!cmp_res && split + ext == ids) if (!cmp_res && split + ext == ids)
continue; continue;
@ -1256,16 +1256,16 @@ gen_test_find(struct oid *(*generator)(void))
} }
else else
{ {
for (uint j = 0; j < MIN(LOAD_U8(oids[i]->n_subid), for (uint j = 0; j < MIN(oids[i]->n_subid,
ARRAY_SIZE(snmp_internet)); j++) ARRAY_SIZE(snmp_internet)); j++)
{ {
if (LOAD_U32(oids[i]->ids[j]) == snmp_internet[j] && if (oids[i]->ids[j] == snmp_internet[j] &&
j >= longest_inet_pref_len) j >= longest_inet_pref_len)
{ {
longest_inet_pref->ids[j] = snmp_internet[j]; longest_inet_pref->ids[j] = snmp_internet[j];
longest_inet_pref_len = j + 1; longest_inet_pref_len = j + 1;
} }
else if (LOAD_U32(oids[i]->ids[j]) == snmp_internet[j]) else if (oids[i]->ids[j] == snmp_internet[j])
; ;
else else
break; break;
@ -1360,19 +1360,19 @@ gen_test_find(struct oid *(*generator)(void))
last = found; last = found;
/* test finding with walk state not pointing at the root of the tree */ /* test finding with walk state not pointing at the root of the tree */
u8 subids = LOAD_U8(oids[i]->n_subid); u8 subids = oids[i]->n_subid;
if (subids > 0) if (subids > 0)
{ {
found = NULL; found = NULL;
u32 new_ids = xrandom(subids); u32 new_ids = xrandom(subids);
mib_tree_walk_init(&walk, (xrandom(2)) ? tree : NULL); mib_tree_walk_init(&walk, (xrandom(2)) ? tree : NULL);
STORE_U8(oids[i]->n_subid, new_ids); oids[i]->n_subid = new_ids;
mib_node_u *ignored UNUSED; mib_node_u *ignored UNUSED;
ignored = mib_tree_find(tree, &walk, oids[i]); ignored = mib_tree_find(tree, &walk, oids[i]);
STORE_U8(oids[i]->n_subid, subids); oids[i]->n_subid = subids;
found = mib_tree_find(tree, &walk, oids[i]); found = mib_tree_find(tree, &walk, oids[i]);
@ -1410,7 +1410,7 @@ gen_test_find(struct oid *(*generator)(void))
if (!has_node && !snmp_oid_is_prefixed(oid)) if (!has_node && !snmp_oid_is_prefixed(oid))
{ {
for (uint i = 0; i < MIN(ARRAY_SIZE(snmp_internet), for (uint i = 0; i < MIN(ARRAY_SIZE(snmp_internet),
LOAD_U8(oid->n_subid)); i++) oid->n_subid); i++)
{ {
if (longest_inet_pref->ids[i] != 0 && if (longest_inet_pref->ids[i] != 0 &&
longest_inet_pref->ids[i] == oid->ids[i]) longest_inet_pref->ids[i] == oid->ids[i])
@ -1422,7 +1422,7 @@ gen_test_find(struct oid *(*generator)(void))
} }
} }
if (has_node && LOAD_U8(oid->n_subid) > ARRAY_SIZE(snmp_internet)) if (has_node && oid->n_subid > ARRAY_SIZE(snmp_internet))
has_node = 0; has_node = 0;
} }
@ -1437,19 +1437,19 @@ gen_test_find(struct oid *(*generator)(void))
last = found; last = found;
u8 subids = LOAD_U8(searched[search]->n_subid); u8 subids = searched[search]->n_subid;
if (subids > 0) if (subids > 0)
{ {
found = NULL; found = NULL;
u32 new_ids = xrandom(subids); u32 new_ids = xrandom(subids);
mib_tree_walk_init(&walk, (xrandom(2)) ? tree : NULL); mib_tree_walk_init(&walk, (xrandom(2)) ? tree : NULL);
STORE_U8(searched[search]->n_subid, new_ids); searched[search]->n_subid = new_ids;
mib_node_u *ignored UNUSED; mib_node_u *ignored UNUSED;
ignored = mib_tree_find(tree, &walk, searched[search]); ignored = mib_tree_find(tree, &walk, searched[search]);
STORE_U8(searched[search]->n_subid, subids); searched[search]->n_subid = subids;
found = mib_tree_find(tree, &walk, searched[search]); found = mib_tree_find(tree, &walk, searched[search]);
@ -1725,7 +1725,7 @@ gen_test_traverse(struct oid *(*generator)(void))
{ {
if (snmp_oid_is_prefixed(sorted[d])) if (snmp_oid_is_prefixed(sorted[d]))
bound += 5; bound += 5;
bound += (int)LOAD_U8(sorted[d]->n_subid); bound += (int) sorted[d]->n_subid;
} }
if (!no_inet_prefix) if (!no_inet_prefix)

View File

@ -46,7 +46,7 @@ inline void *
snmp_varbind_data(const struct agentx_varbind *vb) snmp_varbind_data(const struct agentx_varbind *vb)
{ {
uint name_size = snmp_oid_size(&vb->name); uint name_size = snmp_oid_size(&vb->name);
return (void *)&vb->name + name_size; return (void *) &vb->name + name_size;
} }
struct oid * struct oid *
@ -54,23 +54,23 @@ snmp_varbind_set_name_len(struct snmp_pdu *c, struct agentx_varbind **vb, u8 len
{ {
struct oid *oid = &(*vb)->name; struct oid *oid = &(*vb)->name;
if (LOAD_U8(oid->n_subid) >= len) if (oid->n_subid >= len)
{ {
c->size += (LOAD_U8(oid->n_subid) - len) * sizeof(u32); c->size += (oid->n_subid - len) * sizeof(u32);
STORE_U8(oid->n_subid, len); oid->n_subid = len;
return oid; return oid;
} }
/* We need more space */ /* We need more space */
ASSUME(len >= LOAD_U8(oid->n_subid)); ASSUME(len >= oid->n_subid);
uint diff_size = (len - LOAD_U8(oid->n_subid)) * sizeof(u32); uint diff_size = (len - oid->n_subid) * sizeof(u32);
if (snmp_tbuf_reserve(c, diff_size)) if (snmp_tbuf_reserve(c, diff_size))
oid = &(*vb)->name; oid = &(*vb)->name;
ASSERT(c->size >= diff_size); ASSERT(c->size >= diff_size);
c->size -= diff_size; c->size -= diff_size;
STORE_U8(oid->n_subid, len); oid->n_subid = len;
return &(*vb)->name; return &(*vb)->name;
} }
@ -78,7 +78,7 @@ void
snmp_varbind_duplicate_hdr(struct snmp_pdu *c, struct agentx_varbind **vb) snmp_varbind_duplicate_hdr(struct snmp_pdu *c, struct agentx_varbind **vb)
{ {
ASSUME(vb != NULL && *vb != NULL); ASSUME(vb != NULL && *vb != NULL);
uint hdr_size = snmp_varbind_header_size(*vb); uint hdr_size = snmp_varbind_header_size(*vb->name);
(void) snmp_tbuf_reserve(c, hdr_size); (void) snmp_tbuf_reserve(c, hdr_size);
ASSERT(c->size >= hdr_size); ASSERT(c->size >= hdr_size);
@ -100,7 +100,7 @@ snmp_is_oid_empty(const struct oid *oid)
{ {
/* We intentionaly ignore padding that should be zeroed */ /* We intentionaly ignore padding that should be zeroed */
if (oid != NULL) if (oid != NULL)
return LOAD_U8(oid->n_subid) == 0 && LOAD_U8(oid->prefix) == 0; return oid->n_subid == 0 && oid->prefix == 0;
else else
return 0; return 0;
} }
@ -119,10 +119,10 @@ snmp_oid_is_prefixable(const struct oid *oid)
return 0; return 0;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
if (LOAD_U32(oid->ids[i]) != snmp_internet[i]) if (oid->ids[i] != snmp_internet[i])
return 0; return 0;
if (LOAD_U32(oid->ids[4]) >= 256) if (oid->ids[4] >= 256)
return 0; return 0;
return 1; return 1;
@ -148,27 +148,12 @@ snmp_pkt_len(const byte *start, const byte *end)
void void
snmp_oid_copy(struct oid *dest, const struct oid *src) 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 ? 1 : 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]);
}
/* this function assumes enougth space inside dest is allocated */
void
snmp_oid_copy2(struct oid *dest, const struct oid *src)
{
/* The STORE_U8() and LOAD_U8() cancel out */
dest->n_subid = src->n_subid; dest->n_subid = src->n_subid;
dest->prefix = src->prefix; dest->prefix = src->prefix;
dest->include = src->include ? 1 : 0; dest->include = src->include ? 1 : 0;
dest->reserved = 0; dest->reserved = 0;
/* The STORE_U32() and LOAD_U32 cancel out */ memcpy(dest->ids, src->ids, src->n_subid * sizeof(u32));
memcpy(dest->ids, src->ids, LOAD_U8(src->n_subid) * sizeof(u32));
} }
/* /*
@ -235,18 +220,21 @@ snmp_str_size(const char *str)
} }
/** /**
* snmp_oid_size - measure size of oid in bytes * snmp_oid_size - measure size of OID in bytes
* @o: object identifier to use * @o: object identifier to use
*
* Work for both packet and cpu native byte orders.
*/ */
uint uint
snmp_oid_size(const struct oid *o) snmp_oid_size(const struct oid *o)
{ {
/* LOAD_U8() is in both cases basic mem read */
return 4 + (LOAD_U8(o->n_subid) * 4); return 4 + (LOAD_U8(o->n_subid) * 4);
} }
/** /*
* snmp_get_size - calculate size for allocation * snmp_oid_size_from_len - return size of OID with @n_subid subids in bytes
* @n_subid: number of ids in oid * @n_subid: number of subids in ids array
*/ */
inline size_t inline size_t
snmp_oid_size_from_len(uint n_subid) snmp_oid_size_from_len(uint n_subid)
@ -254,19 +242,6 @@ snmp_oid_size_from_len(uint n_subid)
return sizeof(struct oid) + n_subid * sizeof(u32); return sizeof(struct oid) + n_subid * sizeof(u32);
} }
/*
* snmp_varbind_hdr_size_from_oid - return in-buffer size of VarBind
* @oid: OID used as VarBind's name
*
* This function assume @oid to be not NULL.
*/
uint
snmp_varbind_hdr_size_from_oid(const struct oid *oid)
{
ASSUME(oid);
return snmp_oid_size(oid) + OFFSETOF(struct agentx_varbind, name);
}
/* /*
* snmp_set_varbind_type - set VarBind's type field * snmp_set_varbind_type - set VarBind's type field
* @vb: Varbind inside TX buffer * @vb: Varbind inside TX buffer
@ -308,54 +283,40 @@ snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t)
} }
} }
/* Internal wrapper */
static inline u16
snmp_load_varbind_type(const struct agentx_varbind *vb)
{
return LOAD_U16(vb->type);
}
/*
* snmp_get_varbind_type - loads a VarBind type
* @vb: VarBind pointer to TX buffer
*
* This function assumes VarBind with valid type, always call snmp_test_varbind
* for in TX buffer VarBinds.
*/
inline enum agentx_type
snmp_get_varbind_type(const struct agentx_varbind *vb)
{
ASSUME(snmp_test_varbind(vb));
return (enum agentx_type) snmp_load_varbind_type(vb);
}
static inline uint static inline uint
snmp_get_octet_size(const struct agentx_octet_str *str) snmp_get_octet_size(const struct agentx_octet_str *str)
{ {
return LOAD_U32(str->length); return str->length;
} }
/** /**
* snmp_varbind_header_size - measure size of VarBind without data in bytes * snmp_varbind_header_size - measure size of VarBind without data in bytes
* @vb: VarBind to use * @vb_name: VarBind OID name
* *
* Return size including whole OID as well as the VarBind header. * Return size including whole OID as well as the VarBind header.
*/ */
uint uint
snmp_varbind_header_size(const struct agentx_varbind *vb) snmp_varbind_header_size(const struct oid *vb_name)
{ {
return snmp_varbind_hdr_size_from_oid(&vb->name); ASSUME(vb_name);
return snmp_oid_size(vb_name) + OFFSETOF(struct agentx_varbind, name);
} }
/*
* Beware that for octet string, using this function may be a bit tricky due to
* the different byte orders cpu native/packet
*
*
*/
uint uint
snmp_varbind_size_unsafe(const struct agentx_varbind *vb) snmp_varbind_size_unsafe(const struct agentx_varbind *vb, int is_pkt_bo)
{ {
ASSUME(snmp_test_varbind(vb)); ASSUME(snmp_test_varbind(vb));
enum agentx_type type = snmp_get_varbind_type(vb); enum agentx_type type = (is_pkt_bo) ? LOAD_U16(vb->type) : vb->type;
int value_size = agentx_type_size(type); int value_size = agentx_type_size(type);
uint vb_header = snmp_varbind_header_size(vb); uint vb_header = snmp_varbind_header_size(&vb->name);
if (value_size == 0) if (value_size == 0)
return vb_header; return vb_header;
@ -377,6 +338,7 @@ snmp_varbind_size_unsafe(const struct agentx_varbind *vb)
default: default:
/* Shouldn't happen */ /* Shouldn't happen */
die("getting size of VarBind with unknown type (%u)", type);
return 0; return 0;
} }
} }
@ -392,7 +354,7 @@ snmp_varbind_size_unsafe(const struct agentx_varbind *vb)
uint uint
snmp_varbind_size(const struct agentx_varbind *vb, uint limit) snmp_varbind_size(const struct agentx_varbind *vb, uint limit)
{ {
ASSUME(snmp_test_varbind(vb)); //ASSUME(snmp_test_varbind(vb));
if (limit < sizeof(struct agentx_varbind)) if (limit < sizeof(struct agentx_varbind))
return 0; return 0;
@ -457,15 +419,12 @@ snmp_varbind_size_from_len(uint n_subid, enum agentx_type type, uint len)
} }
/* /*
* snmp_test_varbind - test validity of VarBind's type * snmp_test_varbind - test validity of VarBind type
* @vb: VarBind to test * @type: Type of VarBind
*/ */
int int
snmp_test_varbind(const struct agentx_varbind *vb) snmp_test_varbind(u16 type)
{ {
ASSUME(vb);
u16 type = snmp_load_varbind_type(vb);
if (type == AGENTX_INTEGER || if (type == AGENTX_INTEGER ||
type == AGENTX_OCTET_STRING || type == AGENTX_OCTET_STRING ||
type == AGENTX_NULL || type == AGENTX_NULL ||
@ -506,7 +465,6 @@ struct agentx_varbind *
snmp_create_varbind(byte *buf, struct oid *oid) snmp_create_varbind(byte *buf, struct oid *oid)
{ {
struct agentx_varbind *vb = (void *) buf; struct agentx_varbind *vb = (void *) buf;
STORE_U16(vb->reserved, 0);
snmp_oid_copy(&vb->name, oid); snmp_oid_copy(&vb->name, oid);
return vb; return vb;
} }
@ -519,7 +477,7 @@ snmp_create_varbind(byte *buf, struct oid *oid)
int int
snmp_valid_ip4_index(const struct oid *o, uint start) snmp_valid_ip4_index(const struct oid *o, uint start)
{ {
if (start + 3 < LOAD_U8(o->n_subid)) if (start + 3 < o->n_subid)
return snmp_valid_ip4_index_unsafe(o, start); return snmp_valid_ip4_index_unsafe(o, start);
else else
return 0; return 0;
@ -537,7 +495,7 @@ int
snmp_valid_ip4_index_unsafe(const struct oid *o, uint start) snmp_valid_ip4_index_unsafe(const struct oid *o, uint start)
{ {
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
if (LOAD_U32(o->ids[start + i]) >= 256) if (o->ids[start + i] >= 256)
return 0; return 0;
return 1; return 1;
@ -561,7 +519,7 @@ snmp_put_nstr(byte *buf, const char *str, uint len)
/* Insert zero padding in the gap at the end */ /* Insert zero padding in the gap at the end */
for (uint i = 0; i < alen - len; i++) for (uint i = 0; i < alen - len; i++)
STORE_U8(buf[i], '\0'); buf[i] = '\0';
return buf + (alen - len); return buf + (alen - len);
} }
@ -602,19 +560,6 @@ snmp_put_blank(byte *buf)
return buf + 4; return buf + 4;
} }
/**
* snmp_put_oid - put oid into SNMP PDU transcieve buffer
* @buf: pointer to first free buffer byte
* @oid: object identifier to use
*/
byte *
snmp_put_oid(byte *buf, struct oid *oid)
{
struct oid *oid_buf = (void *) buf;
snmp_oid_copy(oid_buf, oid);
return buf + snmp_oid_size(oid);
}
/** /**
* snmp_put_fbyte - put one padded byte to SNMP PDU transcieve buffer * snmp_put_fbyte - put one padded byte to SNMP PDU transcieve buffer
* @buf: pointer to free buffer byte * @buf: pointer to free buffer byte
@ -642,10 +587,10 @@ void
snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr) snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr)
{ {
u32 temp = ip4_to_u32(addr); u32 temp = ip4_to_u32(addr);
STORE_U32(o->ids[start], temp >> 24); o->ids[start] = temp >> 24;
STORE_U32(o->ids[start + 1], (temp >> 16) & 0xFF); o->ids[start + 1] = (temp >> 16) & 0xFF;
STORE_U32(o->ids[start + 2], (temp >> 8) & 0xFF); o->ids[start + 2] = (temp >> 8) & 0xFF;
STORE_U32(o->ids[start + 3], temp & 0xFF); o->ids[start + 3] = temp & 0xFF;
} }
@ -662,11 +607,11 @@ snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr)
int int
snmp_oid_compare(const struct oid *left, const struct oid *right) snmp_oid_compare(const struct oid *left, const struct oid *right)
{ {
const u8 left_subids = LOAD_U8(left->n_subid); const u8 left_subids = left->n_subid;
u8 right_subids = LOAD_U8(right->n_subid); /* see hack for more info */ u8 right_subids = right->n_subid; /* see hack for more info */
const u8 left_prefix = LOAD_U8(left->prefix); const u8 left_prefix = left->prefix;
const u8 right_prefix = LOAD_U8(right->prefix); const u8 right_prefix = right->prefix;
if (left_prefix == 0 && right_prefix == 0) if (left_prefix == 0 && right_prefix == 0)
goto test_ids; goto test_ids;
@ -679,7 +624,7 @@ snmp_oid_compare(const struct oid *left, const struct oid *right)
uint bound = MIN((uint) left_subids, (uint) ARRAY_SIZE(snmp_internet)); uint bound = MIN((uint) left_subids, (uint) ARRAY_SIZE(snmp_internet));
for (uint idx = 0; idx < bound; idx++) for (uint idx = 0; idx < bound; idx++)
{ {
u32 id = LOAD_U32(left->ids[idx]); u32 id = left->ids[idx];
if (id < snmp_internet[idx]) if (id < snmp_internet[idx])
return -1; return -1;
else if (id > snmp_internet[idx]) else if (id > snmp_internet[idx])
@ -690,9 +635,9 @@ snmp_oid_compare(const struct oid *left, const struct oid *right)
return -1; return -1;
/* check prefix */ /* check prefix */
if (LOAD_U32(left->ids[4]) < (u32) right_prefix) if (left->ids[4] < (u32) right_prefix)
return -1; return -1;
else if (LOAD_U32(left->ids[4]) > (u32) right_prefix) else if (left->ids[4] > (u32) right_prefix)
return 1; return 1;
/* the right prefix is already checked (+1) */ /* the right prefix is already checked (+1) */
@ -700,8 +645,8 @@ snmp_oid_compare(const struct oid *left, const struct oid *right)
(int) right_subids); (int) right_subids);
for (int i = 0; i < limit; i++) for (int i = 0; i < limit; i++)
{ {
u32 left_id = LOAD_U32(left->ids[i + ARRAY_SIZE(snmp_internet) + 1]); u32 left_id = left->ids[i + ARRAY_SIZE(snmp_internet + 1)];
u32 right_id = LOAD_U32(right->ids[i]); u32 right_id = right->ids[i];
if (left_id < right_id) if (left_id < right_id)
return -1; return -1;
else if (left_id > right_id) else if (left_id > right_id)
@ -723,8 +668,8 @@ snmp_oid_compare(const struct oid *left, const struct oid *right)
test_ids: test_ids:
for (int i = 0; i < MIN(left->n_subid, right->n_subid); i++) for (int i = 0; i < MIN(left->n_subid, right->n_subid); i++)
{ {
u32 left_id = LOAD_U32(left->ids[i]); u32 left_id = left->ids[i];
u32 right_id = LOAD_U32(right->ids[i]); u32 right_id = right->ids[i];
if (left_id < right_id) if (left_id < right_id)
return -1; return -1;
else if (left_id > right_id) else if (left_id > right_id)
@ -857,6 +802,7 @@ snmp_varbind_ip4(struct snmp_pdu *c, ip4_addr addr)
c->buffer = snmp_put_ip4(snmp_varbind_data(c->sr_vb_start), addr); c->buffer = snmp_put_ip4(snmp_varbind_data(c->sr_vb_start), addr);
} }
#if 0
inline byte * inline byte *
snmp_varbind_nstr2(struct snmp_pdu *c, uint size, const char *str, uint len) snmp_varbind_nstr2(struct snmp_pdu *c, uint size, const char *str, uint len)
{ {
@ -866,6 +812,7 @@ snmp_varbind_nstr2(struct snmp_pdu *c, uint size, const char *str, uint len)
snmp_set_varbind_type(c->sr_vb_start, AGENTX_OCTET_STRING); snmp_set_varbind_type(c->sr_vb_start, AGENTX_OCTET_STRING);
return snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len); return snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len);
} }
#endif
/* /*
* snmp_varbind_nstr - fill varbind context with octet string * snmp_varbind_nstr - fill varbind context with octet string
@ -885,6 +832,19 @@ snmp_varbind_nstr(struct snmp_pdu *c, const char *str, uint len)
c->buffer = snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len); c->buffer = snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len);
} }
/*
* snmp_varbind_oid - fill VarBind data with OID @oid_val
* @oid_val - Object Identifier in cpu native byte order
*
* Function puts the @oid_val to the packet byte order.
*/
void
snmp_varbind_oid(struct snmp_pdu *c, const struct oid *oid_val)
{
snmp_set_varbind_type(c->sr_vb_start, AGENTX_OBJECT_IDENTIFIER);
snmp_oid_to_buf(snmp_varbind_data(c->sr_vb_start), oid_val);
}
inline enum agentx_type inline enum agentx_type
snmp_search_res_to_type(enum snmp_search_res r) snmp_search_res_to_type(enum snmp_search_res r)
{ {
@ -983,65 +943,65 @@ snmp_oid_common_ancestor(const struct oid *left, const struct oid *right, struct
{ {
ASSERT(left && right && out); ASSERT(left && right && out);
STORE_U8(out->include, 0); out->include, 0;
STORE_U8(out->reserved, 0); out->reserved = 0;
STORE_U8(out->prefix, 0); out->prefix = 0;
u32 offset = 0; u32 offset = 0;
u8 left_ids = LOAD_U8(left->n_subid), right_ids = LOAD_U8(right->n_subid); u8 left_ids = left->n_subid, right_ids = right->n_subid;
int l = snmp_oid_is_prefixed(left), r = snmp_oid_is_prefixed(right); int l = snmp_oid_is_prefixed(left), r = snmp_oid_is_prefixed(right);
if (l && r) if (l && r)
{ {
if (LOAD_U8(left->prefix) != LOAD_U8(right->prefix)) if (left->prefix != right->prefix)
{ {
STORE_U8(out->n_subid, 4); out->n_subid = 4;
for (uint id = 0; id < ARRAY_SIZE(snmp_internet); id++) for (uint id = 0; id < ARRAY_SIZE(snmp_internet); id++)
STORE_U32(out->ids[id], snmp_internet[id]); out->ids[id] = snmp_internet[id];
return; return;
} }
STORE_U8(out->prefix, LOAD_U8(left->prefix)); out->prefix = left->prefix;
} }
else if (!l && r) else if (!l && r)
{ {
if (left_ids == 0) if (left_ids == 0)
{ {
/* finish creating NULL OID */ /* finish creating NULL OID */
STORE_U8(out->n_subid, 0); out->n_subid = 0;
return; return;
} }
for (uint id = 0; id < MIN(ARRAY_SIZE(snmp_internet), left_ids); id++) for (uint id = 0; id < MIN(ARRAY_SIZE(snmp_internet), left_ids); id++)
{ {
if (LOAD_U32(left->ids[id]) != snmp_internet[id]) if (left->ids[id] != snmp_internet[id])
{ {
STORE_U8(out->n_subid, id); out->n_subid = id;
return; return;
} }
STORE_U32(out->ids[id], snmp_internet[id]); out->ids[id] = snmp_internet[id];
} }
if (left_ids <= ARRAY_SIZE(snmp_internet)) if (left_ids <= ARRAY_SIZE(snmp_internet))
{ {
STORE_U8(out->n_subid, left_ids); out->n_subid = left_ids;
return; return;
} }
/* index 4 is conresponding to the prefix in prefixed OID */ /* index 4 is conresponding to the prefix in prefixed OID */
if (LOAD_U32(left->ids[4]) != (u32) LOAD_U8(right->prefix)) if (left->ids[4] != (u32) right->prefix)
{ {
STORE_U8(out->n_subid, ARRAY_SIZE(snmp_internet)); out->n_subid = ARRAY_SIZE(snmp_internet);
return; return;
} }
/* delete snmp_internet from out->ids and store OID prefix */ /* delete snmp_internet from out->ids and store OID prefix */
offset = ARRAY_SIZE(snmp_internet) + 1; offset = ARRAY_SIZE(snmp_internet) + 1;
STORE_U8(out->n_subid, LOAD_U8(out->n_subid) - ARRAY_SIZE(snmp_internet)); out->n_subid = out->n_subid - ARRAY_SIZE(snmp_internet);
STORE_U8(out->prefix, LOAD_U8(right->prefix)); out->prefix = right->prefix;
} }
else if (l && !r) else if (l && !r)
{ {
@ -1057,12 +1017,12 @@ snmp_oid_common_ancestor(const struct oid *left, const struct oid *right, struct
if (left->ids[offset + id] == right->ids[id]) if (left->ids[offset + id] == right->ids[id])
{ {
subids++; subids++;
STORE_U32(out->ids[id], LOAD_U32(right->ids[id])); out->ids[id] = right->ids[id];
} }
else else
break; break;
} }
STORE_U8(out->n_subid, subids); out->n_subid = subids;
} }
/* /*
@ -1115,15 +1075,15 @@ snmp_walk_next(struct mib_tree *tree, struct mib_walk_state *walk, struct snmp_p
found = !leaf->call_next(walk, c); found = !leaf->call_next(walk, c);
} }
else if (mib_node_is_leaf(node) && LOAD_U8(c->sr_vb_start->name.include)) else if (mib_node_is_leaf(node) && c->sr_vb_start->name.include)
{ {
found = 1; found = 1;
STORE_U8(c->sr_vb_start->name.include, 0); c->sr_vb_start->name.include = 0;
} }
const struct oid *oid = &c->sr_vb_start->name; const struct oid *oid = &c->sr_vb_start->name;
u32 skip = (walk->id_pos < LOAD_U8(oid->n_subid)) ? u32 skip = (walk->id_pos < oid->n_subid) ?
LOAD_U32(oid->ids[walk->id_pos]) : 0; oid->ids[walk->id_pos] : 0;
while (!found && (leaf = mib_tree_walk_next_leaf(tree, walk, skip)) != NULL) while (!found && (leaf = mib_tree_walk_next_leaf(tree, walk, skip)) != NULL)
{ {
/* mib_tree_walk_next() forces VarBind's name OID overwriting */ /* mib_tree_walk_next() forces VarBind's name OID overwriting */
@ -1141,8 +1101,8 @@ snmp_walk_next(struct mib_tree *tree, struct mib_walk_state *walk, struct snmp_p
found = 1; found = 1;
oid = &c->sr_vb_start->name; oid = &c->sr_vb_start->name;
skip = (walk->id_pos < LOAD_U8(oid->n_subid)) ? skip = (walk->id_pos < oid->n_subid) ?
LOAD_U32(oid->ids[walk->id_pos]) : 0; oid->ids[walk->id_pos] : 0;
} }
if (!found) if (!found)
@ -1186,10 +1146,9 @@ snmp_walk_fill(struct mib_leaf *leaf, struct mib_walk_state *walk, struct snmp_p
if (res != SNMP_SEARCH_OK) if (res != SNMP_SEARCH_OK)
snmp_set_varbind_type(vb, snmp_search_res_to_type(res)); snmp_set_varbind_type(vb, snmp_search_res_to_type(res));
u16 type = snmp_load_varbind_type(vb); u16 type = vb->type;
ASSUME(type == leaf->type || type == AGENTX_END_OF_MIB_VIEW || type == AGENTX_NO_SUCH_OBJECT || ASSUME(type == leaf->type || type == AGENTX_END_OF_MIB_VIEW || type == AGENTX_NO_SUCH_OBJECT ||
type == AGENTX_NO_SUCH_INSTANCE); type == AGENTX_NO_SUCH_INSTANCE);
return res; return res;
} }

View File

@ -16,7 +16,6 @@ uint snmp_pkt_len(const byte *start, const byte *end);
* AgentX - Variable Binding (VarBind) type utils * AgentX - Variable Binding (VarBind) type utils
*/ */
enum snmp_search_res snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t); enum snmp_search_res 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); int agentx_type_size(enum agentx_type t);
/* type Octet String */ /* type Octet String */
@ -32,6 +31,8 @@ void snmp_oid_copy(struct oid *dest, const struct oid *src);
void snmp_oid_copy2(struct oid *dest, const struct oid *src); void snmp_oid_copy2(struct oid *dest, const struct oid *src);
int snmp_oid_compare(const struct oid *first, const struct oid *second); int snmp_oid_compare(const struct oid *first, const struct oid *second);
void snmp_oid_common_ancestor(const struct oid *left, const struct oid *right, struct oid *result); void snmp_oid_common_ancestor(const struct oid *left, const struct oid *right, struct oid *result);
void snmp_oid_from_buf(struct oid *dest, const struct oid *src);
void snmp_oid_to_buf(struct oid *dest, const struct oid *src);
static inline int static inline int
snmp_oid_is_prefixed(const struct oid *oid) snmp_oid_is_prefixed(const struct oid *oid)
@ -47,8 +48,7 @@ void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr);
/* /*
* AgentX - Variable Binding (VarBind) manupulation * AgentX - Variable Binding (VarBind) manupulation
*/ */
uint snmp_varbind_hdr_size_from_oid(const struct oid *oid); uint snmp_varbind_header_size(const struct oid *vb_name);
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(const struct agentx_varbind *vb, uint limit);
uint snmp_varbind_size_unsafe(const struct agentx_varbind *vb); 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); size_t snmp_varbind_size_from_len(uint n_subid, enum agentx_type t, uint len);
@ -81,6 +81,7 @@ void snmp_varbind_gauge32(struct snmp_pdu *c, s64 time);
void snmp_varbind_ticks(struct snmp_pdu *c, u32 val); void snmp_varbind_ticks(struct snmp_pdu *c, u32 val);
void snmp_varbind_ip4(struct snmp_pdu *c, ip4_addr addr); void snmp_varbind_ip4(struct snmp_pdu *c, ip4_addr addr);
void snmp_varbind_nstr(struct snmp_pdu *c, const char *str, uint len); void 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);
/* Raw */ /* Raw */
byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid); byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid);
@ -88,7 +89,6 @@ byte *snmp_no_such_instance(byte *buf, struct agentx_varbind *vb, struct oid *oi
byte *snmp_put_str(byte *buf, const char *str); byte *snmp_put_str(byte *buf, const char *str);
byte *snmp_put_nstr(byte *buf, const char *str, uint len); byte *snmp_put_nstr(byte *buf, const char *str, uint len);
byte *snmp_put_blank(byte *buf); 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_ip4(byte *buf, ip4_addr ip4);
byte *snmp_put_fbyte(byte *buf, u8 data); byte *snmp_put_fbyte(byte *buf, u8 data);

View File

@ -77,7 +77,7 @@ snmp_blank_header(struct agentx_header *h, enum agentx_pdu_types type)
* snmp_register_ack - handle registration response * snmp_register_ack - handle registration response
* @p: SNMP protocol instance * @p: SNMP protocol instance
* @res: header of agentx-Response-PDU * @res: header of agentx-Response-PDU
* @oid: MIB subtree Object Identifier * @oid: MIB subtree Object Identifier in cpu native byte order
*/ */
void void
snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, const struct oid *oid) snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, const struct oid *oid)
@ -93,9 +93,9 @@ snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, const struc
p->registrations_to_ack--; p->registrations_to_ack--;
if (res->error == AGENTX_RES_NO_ERROR) if (res->error == AGENTX_RES_NO_ERROR)
reg->reg_hook_ok(p, (const struct agentx_response *) res, reg); reg->reg_hook_ok(p, res, reg);
else else
reg->reg_hook_fail(p, (const struct agentx_response *) res, reg); reg->reg_hook_fail(p, res, reg);
mb_free(reg->oid); mb_free(reg->oid);
mb_free(reg); mb_free(reg);
@ -172,7 +172,8 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
else /* p->timeout > 255 TO_US */ else /* p->timeout > 255 TO_US */
c.buffer = snmp_put_fbyte(c.buffer, (u8) 255); c.buffer = snmp_put_fbyte(c.buffer, (u8) 255);
c.buffer = snmp_put_oid(c.buffer, oid); snmp_oid_to_buf((struct oid *) c.buffer, oid);
c.buffer += snmp_oid_size(oid);
c.buffer = snmp_put_str(c.buffer, cf->description); c.buffer = snmp_put_str(c.buffer, cf->description);
s = update_packet_size(h, c.buffer); s = update_packet_size(h, c.buffer);
@ -184,12 +185,12 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
* send_notify_pdu - send an agentx-Notify-PDU * send_notify_pdu - send an agentx-Notify-PDU
* @p: SNMP protocol instance * @p: SNMP protocol instance
* @oid: PDU notification Varbind name (OID) * @oid: PDU notification Varbind name (OID)
* @data: PDU Varbind payload * @data: PDU VarBind payload in packet byte order
* @size: PDU Varbind payload size * @size: PDU VarBind payload size
* @include_uptime: flag enabling inclusion of sysUpTime.0 OID * @include_up_time: flag enabling inclusion of sysUpTime.0 OID
*/ */
void void
snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, int include_uptime) snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, int include_up_time)
{ {
if (!snmp_is_active(p)) if (!snmp_is_active(p))
return; return;
@ -205,7 +206,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
uint sz = AGENTX_HEADER_SIZE + TRAP0_HEADER_SIZE + snmp_oid_size(oid) \ uint sz = AGENTX_HEADER_SIZE + TRAP0_HEADER_SIZE + snmp_oid_size(oid) \
+ size; + size;
if (include_uptime) if (include_up_time)
sz += UPTIME_SIZE; sz += UPTIME_SIZE;
/* Make sure that we have enough space in TX buffer */ /* Make sure that we have enough space in TX buffer */
@ -217,7 +218,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
p->packet_id++; /* New packet id */ p->packet_id++; /* New packet id */
snmp_session(p, h); snmp_session(p, h);
if (include_uptime) if (include_up_time)
{ {
/* sysUpTime.0 oid */ /* sysUpTime.0 oid */
STATIC_OID(4) sys_up_time_0 = { STATIC_OID(4) sys_up_time_0 = {
@ -227,17 +228,19 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
.reserved = 0, .reserved = 0,
.ids = { SNMP_MIB_2, SNMP_SYSTEM, SNMP_SYS_UP_TIME, 0 }, .ids = { SNMP_MIB_2, SNMP_SYSTEM, SNMP_SYS_UP_TIME, 0 },
}; };
struct oid *uptime_0 = (struct oid *) &sys_up_time_0; struct oid *up_time_0 = (struct oid *) &sys_up_time_0;
struct agentx_varbind *vb = snmp_create_varbind(c.buffer, uptime_0); struct agentx_varbind *vb = (struct agentx_varbind *) c.buffer;
for (uint i = 0; i < uptime_0->n_subid; i++) snmp_oid_to_buf(&vb->name, up_time_0);
STORE_U32(vb->name.ids[i], uptime_0->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; btime uptime = current_time() - boot_time;
snmp_varbind_ticks(&c, (uptime TO_S) / 100); snmp_varbind_ticks(&c, (uptime TO_S) / 100);
ASSUME(snmp_test_varbind(vb));
ADVANCE(c.buffer, c.size, snmp_varbind_size_unsafe(vb)); ADVANCE(c.buffer, c.size, snmp_varbind_size_unsafe(vb));
STORE_U16(vb->type, vb->type);
/* We do not need to call the snmp_varbind_leave() because we used
* the packet byte order in the first place.
*/
} }
/* snmpTrapOID.0 oid */ /* snmpTrapOID.0 oid */
@ -250,12 +253,15 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
}; };
struct oid *trap_0 = (struct oid *) &snmp_trap_oid_0; struct oid *trap_0 = (struct oid *) &snmp_trap_oid_0;
struct agentx_varbind *trap_vb = snmp_create_varbind(c.buffer, trap_0); struct agentx_varbind *trap_vb = (struct agentx_varbind *) c.buffer;
for (uint i = 0; i < trap_0->n_subid; i++) snmp_oid_to_buf(&trap_vb->name, trap_0);
STORE_U32(trap_vb->name.ids[i], trap_0->ids[i]); /* snmp_oid_size() works for both byte orders same */
trap_vb->type = AGENTX_OBJECT_ID; snmp_varbind_oid(trap_vb, oid);
snmp_put_oid(snmp_varbind_data(trap_vb), oid);
ADVANCE(c.buffer, c.size, snmp_varbind_size_unsafe(trap_vb)); ADVANCE(c.buffer, c.size, snmp_varbind_size_unsafe(trap_vb));
STORE_U16(trap_vb, trap_vb);
/* We do not need to call the snmp_varbind_leave() because we used the packet
* byte order in the first place.
*/
memcpy(c.buffer, data, size); memcpy(c.buffer, data, size);
ADVANCE(c.buffer, c.size, size); ADVANCE(c.buffer, c.size, size);
@ -298,7 +304,6 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, en
snmp_pdu_context(&c, p, sk); snmp_pdu_context(&c, p, sk);
#define BOUND_SIZE sizeof(u32) #define BOUND_SIZE sizeof(u32)
/* conditional +4 for upper-bound (optinal field) */
uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) + uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) +
((bound > 1) ? BOUND_SIZE : 0); ((bound > 1) ? BOUND_SIZE : 0);
@ -321,7 +326,7 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, en
STORE_U8(ur->reserved, 0); STORE_U8(ur->reserved, 0);
ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_hdr)); ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_hdr));
(void) snmp_put_oid(c.buffer, oid); snmp_oid_to_buf((struct oid *) c.buffer, oid);
ADVANCE(c.buffer, c.size, snmp_oid_size(oid)); ADVANCE(c.buffer, c.size, snmp_oid_size(oid));
/* place upper-bound if needed */ /* place upper-bound if needed */
@ -389,8 +394,8 @@ close_pdu(struct snmp_proto *p, enum agentx_close_reasons reason)
p->packet_id++; p->packet_id++;
snmp_session(p, h); snmp_session(p, h);
snmp_put_fbyte(c.buffer, (u8) reason); (void) snmp_put_fbyte(c.buffer, (u8) reason);
ADVANCE(c.buffer, c.size, 4); ADVANCE(c.buffer, c.size, REASON_SIZE);
uint s = update_packet_size(h, c.buffer); uint s = update_packet_size(h, c.buffer);
sk_send(sk, s); sk_send(sk, s);
@ -466,6 +471,7 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start)
uint s; /* final packat size */ uint s; /* final packat size */
struct agentx_response *res; /* pointer to reponse in TX buffer */ struct agentx_response *res; /* pointer to reponse in TX buffer */
/* Presence of full header is guaranteed by parse_pkt() caller */
struct agentx_header *h = (void *) pkt; struct agentx_header *h = (void *) pkt;
pkt += AGENTX_HEADER_SIZE; pkt += AGENTX_HEADER_SIZE;
@ -492,11 +498,13 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start)
} }
else if (all_possible) 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(p, res, AGENTX_RES_NO_ERROR, 0);
} }
else else
{ {
TRACE(D_PACKETS, "SNMP SET action failed (not writable)"); // 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 */ /* 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(p, res, AGENTX_RES_NOT_WRITABLE, c.index + 1);
} }
@ -517,6 +525,7 @@ static uint
parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, 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; byte *pkt = pkt_start;
/* Presence of full header is guaranteed by parse_pkt() caller */
struct agentx_header *h = (void *) pkt; struct agentx_header *h = (void *) pkt;
pkt += AGENTX_HEADER_SIZE; pkt += AGENTX_HEADER_SIZE;
uint pkt_size = LOAD_U32(h->payload); uint pkt_size = LOAD_U32(h->payload);
@ -525,8 +534,8 @@ parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, enum agentx_respons
{ {
TRACE(D_PACKETS, "SNMP received malformed set PDU (size)"); TRACE(D_PACKETS, "SNMP received malformed set PDU (size)");
snmp_simple_response(p, AGENTX_RES_PARSE_ERROR, 0); snmp_simple_response(p, AGENTX_RES_PARSE_ERROR, 0);
// TODO best solution for possibly malicious pkt_size snmp_reset(p);
return AGENTX_HEADER_SIZE; return 0;
} }
struct snmp_pdu c; struct snmp_pdu c;
@ -546,7 +555,10 @@ parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, enum agentx_respons
/* Reset the connection on unrecoverable error */ /* Reset the connection on unrecoverable error */
if (c.error != AGENTX_RES_NO_ERROR && c.error != err) if (c.error != AGENTX_RES_NO_ERROR && c.error != err)
{
snmp_reset(p); /* error */ snmp_reset(p); /* error */
return 0;
}
return pkt - pkt_start; return pkt - pkt_start;
} }
@ -593,11 +605,6 @@ parse_undo_set_pdu(struct snmp_proto *p, byte *pkt)
static uint static uint
parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start) 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()
//mb_free(p->tr);
byte *pkt = pkt_start; byte *pkt = pkt_start;
struct agentx_header *h = (void *) pkt; struct agentx_header *h = (void *) pkt;
uint pkt_size = LOAD_U32(h->payload); uint pkt_size = LOAD_U32(h->payload);
@ -605,11 +612,16 @@ parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start)
/* errors are dropped silently, we must not send any agentx-Response-PDU */ /* errors are dropped silently, we must not send any agentx-Response-PDU */
if (pkt_size != 0) if (pkt_size != 0)
{ {
// TODO should we free even for malformed packets ??
// TODO -> check that data is not freed
return AGENTX_HEADER_SIZE; return AGENTX_HEADER_SIZE;
TRACE(D_PACKET, "SNMP received malformed agentx-CleanupSet-PDU");
snmp_reset(p);
return 0;
} }
TRACE(D_PACKETS, "SNMP received agentx-CleanupSet-PDU");
(void)p;
// TODO don't forget to free resources allocated by parse_test_set_pdu()
//mb_free(p->tr);
/* No agentx-Response-PDU is sent in response to agentx-CleanupSet-PDU */ /* No agentx-Response-PDU is sent in response to agentx-CleanupSet-PDU */
return pkt_size; return pkt_size;
} }
@ -734,7 +746,7 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
default: default:
/* We reset the connection for malformed packet (Unknown packet type) */ /* We reset the connection for malformed packet (Unknown packet type) */
TRACE(D_PACKETS, "SNMP received unknown packet with type %u", LOAD_U8(h->type)); TRACE(D_PACKETS, "SNMP received unknown packet type (%u)", LOAD_U8(h->type));
snmp_reset(p); snmp_reset(p);
return 0; return 0;
} }
@ -770,7 +782,10 @@ parse_response(struct snmp_proto *p, byte *res)
// TODO more direct path to mib-specific code // TODO more direct path to mib-specific code
TRACE(D_PACKETS, "SNMP received agentx-Response-PDU with error %u", r->error); TRACE(D_PACKETS, "SNMP received agentx-Response-PDU with error %u", r->error);
byte *pkt = res + sizeof(struct agentx_response); byte *pkt = res + sizeof(struct agentx_response);
struct oid *failed = (struct oid *) pkt; const struct oid *failed_buf = (struct oid *) pkt;
uint failed_size = snmp_oid_size(failed_buf);
struct oid *failed = tmp_alloc(failed_size);
snmp_oid_from_buf(failed, failed_buf);
snmp_register_ack(p, r, failed); snmp_register_ack(p, r, failed);
break; break;
@ -841,7 +856,10 @@ do_response(struct snmp_proto *p, byte *pkt)
case SNMP_REGISTER:; case SNMP_REGISTER:;
pkt += AGENTX_HEADER_SIZE; pkt += AGENTX_HEADER_SIZE;
const struct oid *oid = (struct oid *) pkt; const struct oid *oid_buf = (struct oid *) pkt;
uint oid_size = snmp_oid_size(oid_buf);
struct oid *oid = tmp_alloc(oid_size);
snmp_oid_from_buf(oid, oid_buf);
snmp_register_ack(p, r, oid); snmp_register_ack(p, r, oid);
if (p->registrations_to_ack == 0) if (p->registrations_to_ack == 0)
@ -859,33 +877,44 @@ do_response(struct snmp_proto *p, byte *pkt)
} }
} }
static inline struct oid * /*
* snmp_oid_prefixize_unsafe - normalize OID to prefixed form
* @dest: destination for normalized OID in native byte order
* @src: source OID in packet byte order
*
* Note that again, snmp_oid_prefixize_unsafe is intended to copy Object
* Identifier from RX buffer to TX buffer but also optionally swap the byte
* order from packet b.o. to cpu native b.o. This is done to simplify the code
* dealing with OIDs.
*/
static inline void
snmp_oid_prefixize_unsafe(struct oid *dest, const struct oid *src) snmp_oid_prefixize_unsafe(struct oid *dest, const struct oid *src)
{ {
u8 subids = LOAD_U8(src->n_subid) - 5; dest->n_subid = LOAD_U8(src->n_subid) - 5;
dest->n_subid = subids; dest->prefix = (u8) LOAD_U32(src->ids[ARRAY_SIZE(snmp_internet)]);
STORE_U8(dest->prefix, (u8) LOAD_U32(src->ids[ARRAY_SIZE(snmp_internet)])); dest->include = (LOAD_U8(src->include)) ? 1 : 0;
STORE_U8(dest->include, (LOAD_U8(src->include)) ? 1 : 0); dest->reserved = 0;
STORE_U8(dest->reserved, 0);
/* The LOAD_U32() and STORE_U32() cancel out */ /* The LOAD_U32() and STORE_U32() cancel out */
memcpy(&dest->ids[0], &src->ids[5], subids * sizeof(u32)); for (i = 0; i < dest->n_subid; i++)
dest->ids[i] = LOAD_U32(src->ids[i + 5]);
return dest; return dest;
} }
/* /*
* snmp_vb_to_tx - create varbind from RX buffer OID * snmp_vb_to_tx - create VarBind in TX buffer from RX buffer OID
* @c: PDU context * @c: PDU context
* @oid: object identifier located in RX buffer * @oid: Object Identifier located in RX buffer with packet byte order
* *
* Create NULL initialized VarBind inside TX buffer (from @c) whose vb->name is * Create a NULL initialized VarBind inside TX buffer (from @c) whose name
* @oid. The @oid prefixed if possible. The result is stored in @c->sr_vb_start. * 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 void
snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid) snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid)
{ {
uint vb_hdr_size = snmp_varbind_hdr_size_from_oid(oid); uint vb_hdr_size = snmp_varbind_header_size(oid);
(void) snmp_tbuf_reserve(c, vb_hdr_size); (void) snmp_tbuf_reserve(c, vb_hdr_size);
ASSERT(c->size >= vb_hdr_size); ASSERT(c->size >= vb_hdr_size);
@ -898,32 +927,43 @@ snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid)
{ {
u8 subids = LOAD_U8(oid->n_subid) - 5; u8 subids = LOAD_U8(oid->n_subid) - 5;
ADVANCE(c->buffer, c->size, snmp_oid_size_from_len(subids)); ADVANCE(c->buffer, c->size, snmp_oid_size_from_len(subids));
(void) snmp_oid_prefixize_unsafe(&vb->name, oid); snmp_oid_prefixize_unsafe(&vb->name, oid);
c->sr_vb_start = vb; c->sr_vb_start = vb;
return; return;
} }
ADVANCE(c->buffer, c->size, snmp_oid_size(oid)); ADVANCE(c->buffer, c->size, snmp_oid_size(oid));
snmp_oid_copy2(&vb->name, oid); snmp_oid_from_buf(&vb->name, oid);
c->sr_vb_start = vb; c->sr_vb_start = vb;
} }
/* /*
* snmp_fix_vb - fix VarBind's name OID byte order * snmp_varbind_leave - transform VarBind to packet byte order
* @vb: VarBind to use * @vb: prepared VarBind in cpu native byte order
*/ */
void void
snmp_fix_vb(struct agentx_varbind *vb) snmp_varbind_leave(struct agentx_varbind *vb)
{ {
snmp_oid_copy(&vb->name, &vb->name); STORE_U16(vb->type, vb->type);
/* Does nothing */
STORE_U16(vb->reserved, 0);
struct oid *oid = &vb->name;
STORE_U8(oid->n_subid, oid->n_subid);
STORE_U8(oid->prefix, oid->prefix);
STORE_U8(oid->include, oid->include);
STORE_U8(oid->reserved, 0);
for (u8 i = 0; i < oid->n_subid; i++)
STORE_U32(oid->ids[i], oid->ids[i]);
} }
/* /*
* update_packet_size - set PDU size * update_packet_size - set PDU size
* @start - pointer to PDU data start (excluding header size) * @start: pointer to PDU data start (excluding header size)
* @end - pointer after the last PDU byte * @end: pointer after the last PDU byte
* *
* Return number of bytes in TX buffer (including header size). * Return number of bytes in TX buffer (including header size).
*/ */
@ -952,17 +992,17 @@ response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_
// TODO deal with auto-incrementing of snmp_pdu context c.ind // TODO deal with auto-incrementing of snmp_pdu context c.ind
if (err != AGENTX_RES_NO_ERROR && err != AGENTX_RES_GEN_ERROR) if (err != AGENTX_RES_NO_ERROR && err != AGENTX_RES_GEN_ERROR)
{ {
TRACE(D_PACKETS, "Last PDU resulted in error %u", err); //TRACE(D_PACKETS, "Last PDU resulted in error %u", err);
STORE_U16(res->index, ind); STORE_U16(res->index, ind);
TRACE(D_PACKETS, "Storing packet size %u (was %u)", sizeof(struct agentx_response) - AGENTX_HEADER_SIZE, LOAD_U32(res->h.payload)); /* Reset VarBindList to null */
STORE_U32(res->h.payload, STORE_U32(res->h.payload,
sizeof(struct agentx_response) - AGENTX_HEADER_SIZE); sizeof(struct agentx_response) - AGENTX_HEADER_SIZE);
} }
else if (err == AGENTX_RES_GEN_ERROR) else if (err == AGENTX_RES_GEN_ERROR)
{ {
TRACE(D_PACKETS, "Last PDU resulted in error %u genErr", err); //TRACE(D_PACKETS, "Last PDU resulted in error %u genErr", err);
STORE_U16(res->index, 0); STORE_U16(res->index, 0);
TRACE(D_PACKETS, "Storing packet size %u (was %u)", sizeof(struct agentx_response) - AGENTX_HEADER_SIZE, LOAD_U32(res->h.payload)); /* Reset VarBindList to null */
STORE_U32(res->h.payload, STORE_U32(res->h.payload,
sizeof(struct agentx_response) - AGENTX_HEADER_SIZE); sizeof(struct agentx_response) - AGENTX_HEADER_SIZE);
} }

View File

@ -138,26 +138,6 @@ enum agentx_flags {
#define LOAD_PTR(src) get_u32(ptr) #define LOAD_PTR(src) get_u32(ptr)
#endif #endif
#define LOAD_STR(/* byte * */buf, str, length) ({ \
length = LOAD_PTR(buf); \
length > 0 ? (str = buf + 4) : (str = NULL); })
#define COPY_STR(proto, buf, str, length) ({ \
length = LOAD_PTR(buf); \
str = mb_alloc(proto->pool, length + 1); \
memcpy(str, buf+4, length); \
str[length] = '\0'; /* set term. char */ \
buf += 4 + snmp_str_size_from_len(length); })
#define SNMP_PUT_OID(buf, size, oid) \
({ \
struct agentx_varbind *vb = (void *) buf; \
SNMP_FILL_VARBIND(vb, oid); \
})
#define SNMP_FILL_VARBIND(vb, oid) \
snmp_oid_copy(&(vb)->name, (oid)), snmp_oid_size((oid))
struct agentx_header { struct agentx_header {
u8 version; u8 version;
u8 type; u8 type;
@ -189,25 +169,31 @@ struct oid {
u32 ids[sbids]; \ u32 ids[sbids]; \
} }
#define VALUE_U32_HELPER(x) VALUE_U32(x),
#define STATIC_OID_INITIALIZER(sbids, pref, ...) \ #define STATIC_OID_INITIALIZER(sbids, pref, ...) \
{ \ { \
.n_subid = VALUE_U8(sbids), \ .n_subid = sbids, \
.prefix = VALUE_U8(pref), \ .prefix = pref, \
.include = VALUE_U8(0), \ .include = 0, \
.reserved = VALUE_U8(0), \ .reserved = 0, \
.ids = { MACRO_FOREACH(VALUE_U32_HELPER, __VA_ARGS__) }, \ .ids = { __VA_ARGS__ }, \
} }
/* enforced by MIB tree, see mib_tree.h for more info */ /* enforced by MIB tree, see mib_tree.h for more info */
#define OID_MAX_LEN 32 #define OID_MAX_LEN 32
/*
* AgentX VarBind -- Variable Binding
* During the processing of the VarBind, the fields @type and @name are in cpu
* native byte order. This should be fixed by running snmp_varbind_leave()
* before VarBind control pointer abondonment or before packet transmission.
* The data following the structure should always follow the packet byte order.
*/
struct agentx_varbind { struct agentx_varbind {
u16 type; u16 type;
u16 reserved; /* always zero filled */ u16 reserved; /* always zero filled */
/* oid part */ /* oid part */
struct oid name; struct oid name;
/* AgentX variable binding data optionaly here */ /* AgentX variable binding data optionally here */
}; };
struct agentx_search_range { struct agentx_search_range {