0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 17:51:53 +00:00

fixup! SNMP: tmp -- fix byte order handling

This commit is contained in:
Vojtech Vilimek 2024-08-13 17:47:15 +02:00
parent dd8d706e1b
commit 538bbadae2
6 changed files with 136 additions and 160 deletions

View File

@ -393,6 +393,9 @@ snmp_cleanup(struct snmp_proto *p)
rfree(p->lp); rfree(p->lp);
p->bgp_trie = NULL; p->bgp_trie = NULL;
rfree(p->end_oids);
p->end_oids = NULL;
p->state = SNMP_DOWN; p->state = SNMP_DOWN;
} }
@ -539,6 +542,7 @@ snmp_start(struct proto *P)
p->lp = lp_new(p->pool); p->lp = lp_new(p->pool);
p->mib_tree = mb_alloc(p->pool, sizeof(struct mib_tree)); p->mib_tree = mb_alloc(p->pool, sizeof(struct mib_tree));
p->bgp_trie = f_new_trie(p->lp, 0); 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->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); 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) snmp_shutdown(struct proto *P)
{ {
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P); struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
return snmp_set_state(p, SNMP_DOWN);
return snmp_reset(p); return snmp_reset(p);
} }

View File

@ -98,6 +98,7 @@ struct snmp_proto {
struct object_lock *lock; struct object_lock *lock;
pool *pool; /* a shortcut to the procotol mem. pool */ pool *pool; /* a shortcut to the procotol mem. pool */
linpool *lp; /* linpool for bgp_trie nodes */ linpool *lp; /* linpool for bgp_trie nodes */
linpool *end_oids;
enum snmp_proto_state state; enum snmp_proto_state state;

View File

@ -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->name); 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);
@ -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 * snmp_oid_from_buf - copy OID from RX buffer to dest in native byte order
* @dst: destination to use * @dst: destination to use (native byte order)
* @src: OID to be copied from * @src: OID to be copied from (packet byte order)
*/ */
void void
snmp_oid_from_buf(struct oid *dst, const struct oid *src) 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]); 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 * snmp_oid_duplicate - duplicate an OID from memory pool
* @pool: pool to use * @pool: pool to use
@ -242,47 +259,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_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 static inline uint
snmp_get_octet_size(const struct agentx_octet_str *str) snmp_get_octet_size(const struct agentx_octet_str *str)
{ {
@ -309,13 +285,10 @@ snmp_varbind_header_size(const struct oid *vb_name)
* *
*/ */
uint 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)); ASSUME(snmp_test_varbind_type(vb->type));
int value_size = agentx_type_size(vb->type);
enum agentx_type type = (is_pkt_bo) ? LOAD_U16(vb->type) : vb->type;
int value_size = agentx_type_size(type);
uint vb_header = snmp_varbind_header_size(&vb->name); uint vb_header = snmp_varbind_header_size(&vb->name);
if (value_size == 0) 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) if (value_size > 0)
return vb_header + value_size; return vb_header + value_size;
switch (type) switch (vb->type)
{ {
case AGENTX_OBJECT_ID:; case AGENTX_OBJECT_ID:;
struct oid *oid = snmp_varbind_data(vb); 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: default:
/* Shouldn't happen */ /* 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; return 0;
} }
} }
/** /**
* snmp_varbind_size - get size of in-buffer VarBind * 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 * @limit: upper limit of bytes that can be used
* *
* This functions assumes valid VarBind type. * This functions assumes valid VarBind type.
* Return 0 for Varbinds longer than limit, Varbind's size otherwise. * Return 0 for Varbinds longer than limit, Varbind's size otherwise.
*/ */
uint uint UNUSED
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));
if (limit < sizeof(struct agentx_varbind)) if (limit < sizeof(struct agentx_varbind))
return 0; 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); 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) if (limit < vb_header)
return 0; return 0;
@ -374,17 +348,27 @@ snmp_varbind_size(const struct agentx_varbind *vb, uint limit)
else if (s > 0) else if (s > 0)
return 0; return 0;
uint sz;
switch (type) switch (type)
{ {
case AGENTX_OBJECT_ID:; case AGENTX_OBJECT_ID:;
struct oid *oid = snmp_varbind_data(vb); struct oid *oid = snmp_varbind_data(vb);
/* 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); return vb_header + snmp_oid_size(oid);
case AGENTX_OCTET_STRING: case AGENTX_OCTET_STRING:
case AGENTX_IP_ADDRESS: case AGENTX_IP_ADDRESS:
case AGENTX_OPAQUE:; case AGENTX_OPAQUE:;
struct agentx_octet_str *os = snmp_varbind_data(vb); 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: default:
/* This should not happen */ /* 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 * snmp_test_varbind - test validity of VarBind type
* @type: Type of VarBind * @type: Type of VarBind in cpu native byte order
*/ */
int int
snmp_test_varbind(u16 type) snmp_test_varbind_type(u16 type)
{ {
if (type == AGENTX_INTEGER || if (type == AGENTX_INTEGER ||
type == AGENTX_OCTET_STRING || type == AGENTX_OCTET_STRING ||
@ -443,31 +427,6 @@ snmp_test_varbind(u16 type)
return 0; 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 * 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); (int) right_subids);
for (int i = 0; i < limit; i++) 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]; u32 right_id = right->ids[i];
if (left_id < right_id) if (left_id < right_id)
return -1; 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 */ 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); u32 *data = snmp_varbind_data(vb);
STORE_PTR(data, val); STORE_PTR(data, val);
data++; data++;
@ -798,7 +757,7 @@ snmp_varbind_gauge32(struct snmp_pdu *c, s64 time)
inline void inline void
snmp_varbind_ip4(struct snmp_pdu *c, ip4_addr addr) 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); 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)) if (size < snmp_str_size_from_len(len))
return NULL; 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); return snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len);
} }
#endif #endif
@ -828,7 +787,7 @@ snmp_varbind_nstr2(struct snmp_pdu *c, uint size, const char *str, uint len)
void void
snmp_varbind_nstr(struct snmp_pdu *c, const char *str, uint len) 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); 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 void
snmp_varbind_oid(struct snmp_pdu *c, const struct oid *oid_val) 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); 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); ASSERT(left && right && out);
out->include, 0; out->include = 0;
out->reserved = 0; out->reserved = 0;
out->prefix = 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); 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); mib_node_u *node = mib_tree_find(tree, walk, &c->sr_vb_start->name);
// TODO hide me in mib_tree code // 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; 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) if (!leaf)
return SNMP_SEARCH_NO_OBJECT; return SNMP_SEARCH_NO_OBJECT;
uint size = 0; uint size = 0;
enum agentx_type type = AGENTX_NULL;
if (leaf->size >= 0) if (leaf->size >= 0)
{ {
if (leaf->type == AGENTX_OCTET_STRING || leaf->type == AGENTX_OPAQUE || if (leaf->type == AGENTX_OCTET_STRING || leaf->type == AGENTX_OPAQUE ||
leaf->type == AGENTX_OBJECT_ID) leaf->type == AGENTX_OBJECT_ID)
{ {
snmp_set_varbind_type(vb, leaf->type); type = leaf->type;
size = leaf->size; size = leaf->size;
} }
else if (leaf->type != AGENTX_INVALID) else if (leaf->type != AGENTX_INVALID)
{ {
snmp_set_varbind_type(vb, leaf->type); type = leaf->type;
size = agentx_type_size(leaf->type); size = agentx_type_size(leaf->type);
} }
else 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); (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; vb = c->sr_vb_start;
if (res != SNMP_SEARCH_OK) 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(vb->type == leaf->type || vb->type == AGENTX_END_OF_MIB_VIEW ||
ASSUME(type == leaf->type || type == AGENTX_END_OF_MIB_VIEW || type == AGENTX_NO_SUCH_OBJECT || vb->type == AGENTX_NO_SUCH_OBJECT || vb->type == AGENTX_NO_SUCH_INSTANCE);
type == AGENTX_NO_SUCH_INSTANCE);
return res; return res;
} }

View File

@ -15,7 +15,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);
int agentx_type_size(enum agentx_type t); int agentx_type_size(enum agentx_type t);
/* type Octet String */ /* 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(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);
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); 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); 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); 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 */ /* 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_int(struct snmp_pdu *c, u32 val);
void snmp_varbind_counter32(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); void snmp_varbind_gauge32(struct snmp_pdu *c, s64 time);

View 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 void do_response(struct snmp_proto *p, byte *buf);
static uint parse_gets_pdu(struct snmp_proto *p, byte *pkt); 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 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); static uint update_packet_size(struct agentx_header *start, byte *end);
/* standard SNMP internet prefix (.1.3.6.1) */ /* 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->version, AGENTX_VERSION);
STORE_U8(h->type, type); 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_U8(h->reserved, 0);
STORE_U32(h->payload, 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)); ASSUME(c.size >= sizeof(struct agentx_response));
struct agentx_response *res = prepare_response(p, &c); 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)); 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; struct agentx_varbind *trap_vb = (struct agentx_varbind *) c.buffer;
snmp_oid_to_buf(&trap_vb->name, trap_0); snmp_oid_to_buf(&trap_vb->name, trap_0);
/* snmp_oid_size() works for both byte orders same */ /* 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)); 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 /* We do not need to call the snmp_varbind_leave() because we used the packet
* byte order in the first place. * 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) 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); snmp_reset(p);
} }
else if (all_possible) else if (all_possible)
{ {
/* All values in the agentx-TestSet-PDU are OK, realy to commit them */ /* 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 else
{ {
// Currently the only reachable branch // Currently the only reachable branch
//TRACE(D_PACKETS, "SNMP SET action failed (not writable)"); //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(res, AGENTX_RES_NOT_WRITABLE, c.index + 1);
} }
sk_send(sk, s); 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; c.error = err;
TRACE(D_PACKETS, "SNMP received set PDU with error %u", c.error); 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); sk_send(p->sock, AGENTX_HEADER_SIZE);
/* Reset the connection on unrecoverable error */ /* 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) if (pkt_size != 0)
{ {
return AGENTX_HEADER_SIZE; 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); snmp_reset(p);
return 0; return 0;
} }
@ -657,9 +658,10 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
return 0; return 0;
struct agentx_header *h = (struct agentx_header *) pkt; 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"); TRACE(D_PACKETS, "SNMP received PDU with unexpected byte order");
if (h->type != AGENTX_RESPONSE_PDU)
snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0); snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
snmp_reset(p); snmp_reset(p);
return 0; return 0;
@ -671,6 +673,7 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
if (pkt_size > SNMP_PKT_SIZE_MAX) if (pkt_size > SNMP_PKT_SIZE_MAX)
{ {
TRACE(D_PACKETS, "SNMP received PDU is too long"); TRACE(D_PACKETS, "SNMP received PDU is too long");
if (h->type != AGENTX_RESPONSE_PDU)
snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0); snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
snmp_reset(p); snmp_reset(p);
return 0; return 0;
@ -802,7 +805,6 @@ parse_response(struct snmp_proto *p, byte *res)
case AGENTX_RES_PROCESSING_ERR: case AGENTX_RES_PROCESSING_ERR:
default: default:
TRACE(D_PACKETS, "SNMP agentx-Response-PDU with unexepected error %u", r->error); TRACE(D_PACKETS, "SNMP agentx-Response-PDU with unexepected error %u", r->error);
//snmp_stop(p);
snmp_reset(p); snmp_reset(p);
break; break;
} }
@ -896,10 +898,8 @@ snmp_oid_prefixize_unsafe(struct oid *dest, const struct oid *src)
dest->reserved = 0; dest->reserved = 0;
/* The LOAD_U32() and STORE_U32() cancel out */ /* 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]); 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 * 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. * 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) snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid)
{ {
uint vb_hdr_size = snmp_varbind_header_size(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; struct agentx_varbind *vb = (struct agentx_varbind *) c->buffer;
ADVANCE(c->buffer, c->size, sizeof(struct agentx_varbind) - sizeof(struct oid)); ADVANCE(c->buffer, c->size, sizeof(struct agentx_varbind) - sizeof(struct oid));
/* Move the c->buffer so that is points at &vb->name */ /* 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)) 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)); ADVANCE(c->buffer, c->size, snmp_oid_size_from_len(subids));
snmp_oid_prefixize_unsafe(&vb->name, oid); snmp_oid_prefixize_unsafe(&vb->name, oid);
c->sr_vb_start = vb; return vb;
return;
} }
ADVANCE(c->buffer, c->size, snmp_oid_size(oid)); ADVANCE(c->buffer, c->size, snmp_oid_size(oid));
snmp_oid_from_buf(&vb->name, 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 * response_err_ind - update response error and index
* @p: SNMP protocol instance
* @res: response PDU header * @res: response PDU header
* @err: error status * @err: error status
* @ind: index of error, ignored for noAgentXError * @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. * error is not noError, also set the corrent response PDU payload size.
*/ */
static inline void 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); STORE_U16(res->error, (u16) err);
// TODO deal with auto-incrementing of snmp_pdu context c.ind // 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) 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; 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; enum snmp_search_res res;
res = snmp_walk_fill(leaf, walk, c); res = snmp_walk_fill(leaf, walk, c);
if (res != SNMP_SEARCH_OK) 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 */ /* agentx-GetNext-PDU */
int int
snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk) 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); struct mib_leaf *leaf = snmp_walk_next(p->mib_tree, walk, c);
enum snmp_search_res res; enum snmp_search_res res;
res = snmp_walk_fill(leaf, walk, c); res = snmp_walk_fill(leaf, walk, c);
if (res != SNMP_SEARCH_OK) 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; 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); 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) snmp_load_oids(byte **pkt_ptr, uint *pkt_sz, struct snmp_pdu *c)
{ {
byte *pkt = *pkt_ptr; byte *pkt = *pkt_ptr;
uint pkt_size = *pkt_sz; uint pkt_size = *pkt_sz;
uint sz; uint sz;
const struct oid *start = (const struct oid *) pkt; /* in packet byte order */
const struct oid *start_buf = (const struct oid *) pkt;
if ((sz = snmp_oid_size(start)) > pkt_size) if ((sz = snmp_oid_size(start_buf)) > pkt_size ||
LOAD_U8(start_buf->n_subid) >= OID_MAX_LEN)
{ {
c->error = AGENTX_RES_PARSE_ERROR; c->error = AGENTX_RES_PARSE_ERROR;
*pkt_ptr = pkt; *pkt_ptr = pkt;
*pkt_sz = pkt_size; *pkt_sz = pkt_size;
return NULL; return 0;
} }
ADVANCE(pkt, pkt_size, sz); ADVANCE(pkt, pkt_size, sz);
const struct oid *end = (const struct oid *) pkt; /* in packet byte order */
if ((sz = snmp_oid_size(end)) > pkt_size) 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; c->error = AGENTX_RES_PARSE_ERROR;
*pkt_ptr = pkt; *pkt_ptr = pkt;
*pkt_sz = pkt_size; *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); ADVANCE(pkt, pkt_size, sz);
// TODO: this does not work if (!snmp_is_oid_empty(end_oid) &&
if (!snmp_is_oid_empty(end) && snmp_oid_compare(&start_vb->name, end_oid) > 0)
snmp_oid_compare(start, end) > 0)
{ {
c->error = AGENTX_RES_GEN_ERROR; c->error = AGENTX_RES_GEN_ERROR;
*pkt_ptr = pkt; *pkt_ptr = pkt;
*pkt_sz = pkt_size; *pkt_sz = pkt_size;
return NULL; return 0;
} }
ASSERT(start != NULL); ASSERT(start_vb != NULL);
ASSERT(end != 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_ptr = pkt;
*pkt_sz = pkt_size; *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); lp_restore(tmp_linpool, &tmps);
const struct oid *start_rx; if (!snmp_load_oids(&pkt, &pkt_size, &c))
if (!(start_rx = snmp_load_oids(&pkt, &pkt_size, &c)))
{ {
snmp_simple_response(p, c.error, snmp_simple_response(p, c.error,
(c.index > UINT16_MAX) ? UINT16_MAX : c.index); (c.index > UINT16_MAX) ? UINT16_MAX : c.index);
snmp_reset(p); snmp_reset(p);
return pkt_size + AGENTX_HEADER_SIZE; return 0;
} }
switch (h->type) switch (h->type)
@ -1196,6 +1203,8 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
die("implementation failure"); die("implementation failure");
} }
snmp_varbind_leave(c.sr_vb_start);
c.sr_vb_start = NULL; c.sr_vb_start = NULL;
c.sr_o_end = NULL; c.sr_o_end = NULL;
@ -1213,7 +1222,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
#endif #endif
/* We update the error, index pair on the beginning of the packet. */ /* 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); uint s = update_packet_size(&response_header->h, c.buffer);
/* We send the message in TX buffer. */ /* We send the message in TX buffer. */

View File

@ -87,7 +87,7 @@ enum agentx_flags {
| AGENTX_NETWORK_BYTE_ORDER) | AGENTX_NETWORK_BYTE_ORDER)
// TODO - make me compile time option // TODO - make me compile time option
#define SNMP_NATIVE #define SNMP_NETWORK_BYTE_ORDER
#if !(defined(SNMP_NATIVE) || defined(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." # error "SNMP: currently support only native byte order or network byte order."
@ -99,9 +99,9 @@ enum agentx_flags {
#endif #endif
#if (defined(SNMP_NATIVE) && defined(CPU_BIG_ENDIAN)) || defined(SNMP_NETWORK_BYTE_ORDER) #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 #else
#define SNMP_ORDER 0 #define SNMP_BYTE_ORDER 0
#endif #endif
/* We recommend using STORE_U32 over VALUE_U32 when possible */ /* 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; 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); u8 snmp_get_mib_class(const struct oid *oid);
void snmp_register_mibs(struct snmp_proto *p); void snmp_register_mibs(struct snmp_proto *p);