0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +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);
p->bgp_trie = NULL;
rfree(p->end_oids);
p->end_oids = NULL;
p->state = SNMP_DOWN;
}
@ -539,6 +542,7 @@ snmp_start(struct proto *P)
p->lp = lp_new(p->pool);
p->mib_tree = mb_alloc(p->pool, sizeof(struct mib_tree));
p->bgp_trie = f_new_trie(p->lp, 0);
p->end_oids = lp_new(p->pool);
p->startup_timer = tm_new_init(p->pool, snmp_startup_timeout, p, 0, 0);
p->ping_timer = tm_new_init(p->pool, snmp_ping_timeout, p, p->timeout, 0);
@ -675,7 +679,6 @@ static int
snmp_shutdown(struct proto *P)
{
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
return snmp_set_state(p, SNMP_DOWN);
return snmp_reset(p);
}

View File

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

View File

@ -78,7 +78,7 @@ void
snmp_varbind_duplicate_hdr(struct snmp_pdu *c, struct agentx_varbind **vb)
{
ASSUME(vb != NULL && *vb != NULL);
uint hdr_size = snmp_varbind_header_size(*vb->name);
uint hdr_size = snmp_varbind_header_size(&(*vb)->name);
(void) snmp_tbuf_reserve(c, hdr_size);
ASSERT(c->size >= hdr_size);
@ -158,8 +158,8 @@ snmp_oid_copy(struct oid *dest, const struct oid *src)
/*
* snmp_oid_from_buf - copy OID from RX buffer to dest in native byte order
* @dst: destination to use
* @src: OID to be copied from
* @dst: destination to use (native byte order)
* @src: OID to be copied from (packet byte order)
*/
void
snmp_oid_from_buf(struct oid *dst, const struct oid *src)
@ -173,6 +173,23 @@ snmp_oid_from_buf(struct oid *dst, const struct oid *src)
dst->ids[i] = LOAD_U32(src->ids[i]);
}
/*
* snmp_oid_to_buf - copy OID to TX buffer with packet byte order
* @dst: destination to use (packet byte order)
* @src: OID to be copied from (native byte order)
*/
void
snmp_oid_to_buf(struct oid *dst, const struct oid *src)
{
STORE_U8(dst->n_subid, src->n_subid);
STORE_U8(dst->prefix, src->prefix);
STORE_U8(dst->include, (src->include) ? 1 : 0);
STORE_U8(dst->reserved, 0);
for (uint i = 0; i < src->n_subid; i++)
STORE_U32(dst->ids[i], src->ids[i]);
}
/*
* snmp_oid_duplicate - duplicate an OID from memory pool
* @pool: pool to use
@ -242,47 +259,6 @@ snmp_oid_size_from_len(uint n_subid)
return sizeof(struct oid) + n_subid * sizeof(u32);
}
/*
* snmp_set_varbind_type - set VarBind's type field
* @vb: Varbind inside TX buffer
* @t: a valid type to be set
*
* This function assumes valid @t.
*/
inline enum snmp_search_res
snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t)
{
ASSUME(t != AGENTX_INVALID);
STORE_U16(vb->type, t);
STORE_U16(vb->reserved, 0);
switch (t)
{
case AGENTX_END_OF_MIB_VIEW:
return SNMP_SEARCH_END_OF_VIEW;
case AGENTX_NO_SUCH_OBJECT:
return SNMP_SEARCH_NO_OBJECT;
case AGENTX_NO_SUCH_INSTANCE:
return SNMP_SEARCH_NO_INSTANCE;
/* valid varbind types */
case AGENTX_INTEGER:
case AGENTX_OCTET_STRING:
case AGENTX_NULL:
case AGENTX_OBJECT_ID:
case AGENTX_IP_ADDRESS:
case AGENTX_COUNTER_32:
case AGENTX_GAUGE_32:
case AGENTX_TIME_TICKS:
case AGENTX_OPAQUE:
case AGENTX_COUNTER_64:
return SNMP_SEARCH_OK;
default:
die("invalid varbind type %d", (int) t);
}
}
static inline uint
snmp_get_octet_size(const struct agentx_octet_str *str)
{
@ -309,13 +285,10 @@ snmp_varbind_header_size(const struct oid *vb_name)
*
*/
uint
snmp_varbind_size_unsafe(const struct agentx_varbind *vb, int is_pkt_bo)
snmp_varbind_size_unsafe(const struct agentx_varbind *vb)
{
ASSUME(snmp_test_varbind(vb));
enum agentx_type type = (is_pkt_bo) ? LOAD_U16(vb->type) : vb->type;
int value_size = agentx_type_size(type);
ASSUME(snmp_test_varbind_type(vb->type));
int value_size = agentx_type_size(vb->type);
uint vb_header = snmp_varbind_header_size(&vb->name);
if (value_size == 0)
@ -324,7 +297,7 @@ snmp_varbind_size_unsafe(const struct agentx_varbind *vb, int is_pkt_bo)
if (value_size > 0)
return vb_header + value_size;
switch (type)
switch (vb->type)
{
case AGENTX_OBJECT_ID:;
struct oid *oid = snmp_varbind_data(vb);
@ -338,30 +311,31 @@ snmp_varbind_size_unsafe(const struct agentx_varbind *vb, int is_pkt_bo)
default:
/* Shouldn't happen */
die("getting size of VarBind with unknown type (%u)", type);
die("getting size of VarBind with unknown type (%u)", vb->type);
return 0;
}
}
/**
* snmp_varbind_size - get size of in-buffer VarBind
* @vb: VarBind to measure
* @vb: VarBind in cpu native byte order to measure
* @limit: upper limit of bytes that can be used
*
* This functions assumes valid VarBind type.
* Return 0 for Varbinds longer than limit, Varbind's size otherwise.
*/
uint
uint UNUSED
snmp_varbind_size(const struct agentx_varbind *vb, uint limit)
{
//ASSUME(snmp_test_varbind(vb));
if (limit < sizeof(struct agentx_varbind))
return 0;
enum agentx_type type = agentx_type_size(snmp_get_varbind_type(vb));
if (!snmp_test_varbind_type(vb->type))
return 0;
enum agentx_type type = vb->type;
int s = agentx_type_size(type);
uint vb_header = snmp_varbind_header_size(vb);
uint vb_header = snmp_varbind_header_size(&vb->name);
if (limit < vb_header)
return 0;
@ -374,17 +348,27 @@ snmp_varbind_size(const struct agentx_varbind *vb, uint limit)
else if (s > 0)
return 0;
uint sz;
switch (type)
{
case AGENTX_OBJECT_ID:;
struct oid *oid = snmp_varbind_data(vb);
return vb_header + snmp_oid_size(oid);
/* snmp_oid_size works for both native and packet byte order */
sz = snmp_oid_size(oid);
if (limit < vb_header + sz)
return 0;
else
return vb_header + snmp_oid_size(oid);
case AGENTX_OCTET_STRING:
case AGENTX_IP_ADDRESS:
case AGENTX_OPAQUE:;
struct agentx_octet_str *os = snmp_varbind_data(vb);
return vb_header + snmp_get_octet_size(os);
sz = snmp_get_octet_size(os);
if (limit < vb_header + sz)
return 0;
else
return vb_header + sz;
default:
/* This should not happen */
@ -420,10 +404,10 @@ snmp_varbind_size_from_len(uint n_subid, enum agentx_type type, uint len)
/*
* snmp_test_varbind - test validity of VarBind type
* @type: Type of VarBind
* @type: Type of VarBind in cpu native byte order
*/
int
snmp_test_varbind(u16 type)
snmp_test_varbind_type(u16 type)
{
if (type == AGENTX_INTEGER ||
type == AGENTX_OCTET_STRING ||
@ -443,31 +427,6 @@ snmp_test_varbind(u16 type)
return 0;
}
/*
* snmp_create_varbind - create a null-typed VarBind in buffer
* @buf: buffer to use
*/
struct agentx_varbind *
snmp_create_varbind_null(byte *buf)
{
struct oid o = { 0 };
struct agentx_varbind *vb = snmp_create_varbind(buf, &o);
snmp_set_varbind_type(vb, AGENTX_NULL);
return vb;
}
/*
* snmp_create_varbind - initialize in-buffer non-typed VarBind
* @buf: pointer to first unused buffer byte
* @oid: OID to use as VarBind name
*/
struct agentx_varbind *
snmp_create_varbind(byte *buf, struct oid *oid)
{
struct agentx_varbind *vb = (void *) buf;
snmp_oid_copy(&vb->name, oid);
return vb;
}
/**
* snmp_oid_ip4_index - check IPv4 address validity in oid
@ -645,7 +604,7 @@ snmp_oid_compare(const struct oid *left, const struct oid *right)
(int) right_subids);
for (int i = 0; i < limit; i++)
{
u32 left_id = left->ids[i + ARRAY_SIZE(snmp_internet + 1)];
u32 left_id = left->ids[i + ARRAY_SIZE(snmp_internet) + 1];
u32 right_id = right->ids[i];
if (left_id < right_id)
return -1;
@ -763,7 +722,7 @@ snmp_varbind_type32(struct agentx_varbind *vb, struct snmp_pdu *c, enum agentx_t
{
ASSUME(agentx_type_size(type) == 4); /* type as 4B representation */
snmp_set_varbind_type(vb, type);
vb->type = type;
u32 *data = snmp_varbind_data(vb);
STORE_PTR(data, val);
data++;
@ -798,7 +757,7 @@ snmp_varbind_gauge32(struct snmp_pdu *c, s64 time)
inline void
snmp_varbind_ip4(struct snmp_pdu *c, ip4_addr addr)
{
snmp_set_varbind_type(c->sr_vb_start, AGENTX_IP_ADDRESS);
c->sr_vb_start->type = AGENTX_IP_ADDRESS;
c->buffer = snmp_put_ip4(snmp_varbind_data(c->sr_vb_start), addr);
}
@ -809,7 +768,7 @@ snmp_varbind_nstr2(struct snmp_pdu *c, uint size, const char *str, uint len)
if (size < snmp_str_size_from_len(len))
return NULL;
snmp_set_varbind_type(c->sr_vb_start, AGENTX_OCTET_STRING);
c->sr_vb_start = AGENTX_OCTET_STRING;
return snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len);
}
#endif
@ -828,7 +787,7 @@ snmp_varbind_nstr2(struct snmp_pdu *c, uint size, const char *str, uint len)
void
snmp_varbind_nstr(struct snmp_pdu *c, const char *str, uint len)
{
snmp_set_varbind_type(c->sr_vb_start, AGENTX_OCTET_STRING);
c->sr_vb_start->type = AGENTX_OCTET_STRING;
c->buffer = snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len);
}
@ -841,7 +800,7 @@ snmp_varbind_nstr(struct snmp_pdu *c, const char *str, uint len)
void
snmp_varbind_oid(struct snmp_pdu *c, const struct oid *oid_val)
{
snmp_set_varbind_type(c->sr_vb_start, AGENTX_OBJECT_IDENTIFIER);
c->sr_vb_start->type = AGENTX_OBJECT_ID;
snmp_oid_to_buf(snmp_varbind_data(c->sr_vb_start), oid_val);
}
@ -943,7 +902,7 @@ snmp_oid_common_ancestor(const struct oid *left, const struct oid *right, struct
{
ASSERT(left && right && out);
out->include, 0;
out->include = 0;
out->reserved = 0;
out->prefix = 0;
@ -1033,8 +992,6 @@ snmp_walk_init(struct mib_tree *tree, struct mib_walk_state *walk, const struct
{
mib_tree_walk_init(walk, tree);
snmp_vb_to_tx(c, oid);
mib_node_u *node = mib_tree_find(tree, walk, &c->sr_vb_start->name);
// TODO hide me in mib_tree code
@ -1116,21 +1073,30 @@ snmp_walk_fill(struct mib_leaf *leaf, struct mib_walk_state *walk, struct snmp_p
{
struct agentx_varbind *vb = c->sr_vb_start;
enum agentx_search_res res;
if (snmp_oid_compare(&c->sr_vb_start->name, c->sr_o_end) >= 0)
{
res = AGENTX_END_OF_MIB_VIEW;
vb->type = snmp_search_res_to_type(res);
return res;
}
if (!leaf)
return SNMP_SEARCH_NO_OBJECT;
uint size = 0;
enum agentx_type type = AGENTX_NULL;
if (leaf->size >= 0)
{
if (leaf->type == AGENTX_OCTET_STRING || leaf->type == AGENTX_OPAQUE ||
leaf->type == AGENTX_OBJECT_ID)
{
snmp_set_varbind_type(vb, leaf->type);
type = leaf->type;
size = leaf->size;
}
else if (leaf->type != AGENTX_INVALID)
{
snmp_set_varbind_type(vb, leaf->type);
type = leaf->type;
size = agentx_type_size(leaf->type);
}
else
@ -1138,17 +1104,17 @@ snmp_walk_fill(struct mib_leaf *leaf, struct mib_walk_state *walk, struct snmp_p
}
(void) snmp_tbuf_reserve(c, size);
vb->type = (u16) type;
enum snmp_search_res res = leaf->filler(walk, c);
res = leaf->filler(walk, c);
vb = c->sr_vb_start;
if (res != SNMP_SEARCH_OK)
snmp_set_varbind_type(vb, snmp_search_res_to_type(res));
vb->type = snmp_search_res_to_type(res);
u16 type = vb->type;
ASSUME(type == leaf->type || type == AGENTX_END_OF_MIB_VIEW || type == AGENTX_NO_SUCH_OBJECT ||
type == AGENTX_NO_SUCH_INSTANCE);
ASSUME(vb->type == leaf->type || vb->type == AGENTX_END_OF_MIB_VIEW ||
vb->type == AGENTX_NO_SUCH_OBJECT || vb->type == AGENTX_NO_SUCH_INSTANCE);
return res;
}

View File

@ -15,7 +15,6 @@ uint snmp_pkt_len(const byte *start, const byte *end);
/*
* AgentX - Variable Binding (VarBind) type utils
*/
enum snmp_search_res snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t);
int agentx_type_size(enum agentx_type t);
/* type Octet String */
@ -52,7 +51,7 @@ uint snmp_varbind_header_size(const struct oid *vb_name);
uint snmp_varbind_size(const struct agentx_varbind *vb, uint limit);
uint snmp_varbind_size_unsafe(const struct agentx_varbind *vb);
size_t snmp_varbind_size_from_len(uint n_subid, enum agentx_type t, uint len);
int snmp_test_varbind(const struct agentx_varbind *vb);
int snmp_test_varbind_type(u16 type);
void *snmp_varbind_data(const struct agentx_varbind *vb);
struct oid *snmp_varbind_set_name_len(struct snmp_pdu *c, struct agentx_varbind **vb, u8 len);
void snmp_varbind_duplicate_hdr(struct snmp_pdu *c, struct agentx_varbind **vb);
@ -73,8 +72,6 @@ int snmp_test_close_reason(byte value);
*/
/* Functions filling buffer a typed value */
struct agentx_varbind *snmp_create_varbind(byte *buf, struct oid *oid);
struct agentx_varbind *snmp_create_varbind_null(byte *buf);
void snmp_varbind_int(struct snmp_pdu *c, u32 val);
void snmp_varbind_counter32(struct snmp_pdu *c, u32 val);
void snmp_varbind_gauge32(struct snmp_pdu *c, s64 time);

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 uint parse_gets_pdu(struct snmp_proto *p, byte *pkt);
static struct agentx_response *prepare_response(struct snmp_proto *p, struct snmp_pdu *c);
static void response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_response_errs err, u16 ind);
static void response_err_ind(struct agentx_response *res, enum agentx_response_errs err, u16 ind);
static uint update_packet_size(struct agentx_header *start, byte *end);
/* standard SNMP internet prefix (.1.3.6.1) */
@ -55,7 +55,7 @@ snmp_header(struct agentx_header *h, enum agentx_pdu_types type, u8 flags)
{
STORE_U8(h->version, AGENTX_VERSION);
STORE_U8(h->type, type);
STORE_U8(h->flags, flags | SNMP_ORDER);
STORE_U8(h->flags, flags | SNMP_BYTE_ORDER);
STORE_U8(h->reserved, 0);
STORE_U32(h->payload, 0);
}
@ -123,7 +123,7 @@ snmp_simple_response(struct snmp_proto *p, enum agentx_response_errs error, u16
ASSUME(c.size >= sizeof(struct agentx_response));
struct agentx_response *res = prepare_response(p, &c);
response_err_ind(p, res, error, index);
response_err_ind(res, error, index);
sk_send(sk, sizeof(struct agentx_response));
}
@ -256,9 +256,10 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
struct agentx_varbind *trap_vb = (struct agentx_varbind *) c.buffer;
snmp_oid_to_buf(&trap_vb->name, trap_0);
/* snmp_oid_size() works for both byte orders same */
snmp_varbind_oid(trap_vb, oid);
c.sr_vb_start = trap_vb;
snmp_varbind_oid(&c, oid);
ADVANCE(c.buffer, c.size, snmp_varbind_size_unsafe(trap_vb));
STORE_U16(trap_vb, trap_vb);
STORE_U16(trap_vb->type, trap_vb->type);
/* We do not need to call the snmp_varbind_leave() because we used the packet
* byte order in the first place.
*/
@ -493,20 +494,20 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start)
if (c.error != AGENTX_RES_NO_ERROR)
{
response_err_ind(p, res, c.error, c.index + 1);
response_err_ind(res, c.error, c.index + 1);
snmp_reset(p);
}
else if (all_possible)
{
/* All values in the agentx-TestSet-PDU are OK, realy to commit them */
response_err_ind(p, res, AGENTX_RES_NO_ERROR, 0);
response_err_ind(res, AGENTX_RES_NO_ERROR, 0);
}
else
{
// Currently the only reachable branch
//TRACE(D_PACKETS, "SNMP SET action failed (not writable)");
/* This is a recoverable error, we do not need to reset the connection */
response_err_ind(p, res, AGENTX_RES_NOT_WRITABLE, c.index + 1);
response_err_ind(res, AGENTX_RES_NOT_WRITABLE, c.index + 1);
}
sk_send(sk, s);
@ -550,7 +551,7 @@ parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, enum agentx_respons
c.error = err;
TRACE(D_PACKETS, "SNMP received set PDU with error %u", c.error);
response_err_ind(p, r, c.error, 0);
response_err_ind(r, c.error, 0);
sk_send(p->sock, AGENTX_HEADER_SIZE);
/* Reset the connection on unrecoverable error */
@ -613,7 +614,7 @@ parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start)
if (pkt_size != 0)
{
return AGENTX_HEADER_SIZE;
TRACE(D_PACKET, "SNMP received malformed agentx-CleanupSet-PDU");
TRACE(D_PACKETS, "SNMP received malformed agentx-CleanupSet-PDU");
snmp_reset(p);
return 0;
}
@ -657,10 +658,11 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
return 0;
struct agentx_header *h = (struct agentx_header *) pkt;
if (h->flags & AGENTX_NETWORK_BYTE_ORDER)
if (h->flags & AGENTX_NETWORK_BYTE_ORDER != SNMP_BYTE_ORDER)
{
TRACE(D_PACKETS, "SNMP received PDU with unexpected byte order");
snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
if (h->type != AGENTX_RESPONSE_PDU)
snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
snmp_reset(p);
return 0;
}
@ -671,7 +673,8 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
if (pkt_size > SNMP_PKT_SIZE_MAX)
{
TRACE(D_PACKETS, "SNMP received PDU is too long");
snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
if (h->type != AGENTX_RESPONSE_PDU)
snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
snmp_reset(p);
return 0;
}
@ -802,7 +805,6 @@ parse_response(struct snmp_proto *p, byte *res)
case AGENTX_RES_PROCESSING_ERR:
default:
TRACE(D_PACKETS, "SNMP agentx-Response-PDU with unexepected error %u", r->error);
//snmp_stop(p);
snmp_reset(p);
break;
}
@ -896,10 +898,8 @@ snmp_oid_prefixize_unsafe(struct oid *dest, const struct oid *src)
dest->reserved = 0;
/* The LOAD_U32() and STORE_U32() cancel out */
for (i = 0; i < dest->n_subid; i++)
for (u8 i = 0; i < dest->n_subid; i++)
dest->ids[i] = LOAD_U32(src->ids[i + 5]);
return dest;
}
/*
@ -911,7 +911,7 @@ snmp_oid_prefixize_unsafe(struct oid *dest, const struct oid *src)
* is @oid. Because we want to simplify code dealing with OIDs, the byte order
* of the name is optionally swapped to match cpu native byte order.
*/
void
struct agentx_varbind *
snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid)
{
uint vb_hdr_size = snmp_varbind_header_size(oid);
@ -921,7 +921,7 @@ snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid)
struct agentx_varbind *vb = (struct agentx_varbind *) c->buffer;
ADVANCE(c->buffer, c->size, sizeof(struct agentx_varbind) - sizeof(struct oid));
/* Move the c->buffer so that is points at &vb->name */
snmp_set_varbind_type(vb, AGENTX_NULL);
vb->type = AGENTX_NULL;
if (snmp_oid_is_prefixable(oid) && !snmp_oid_is_prefixed(oid))
{
@ -929,14 +929,13 @@ snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid)
ADVANCE(c->buffer, c->size, snmp_oid_size_from_len(subids));
snmp_oid_prefixize_unsafe(&vb->name, oid);
c->sr_vb_start = vb;
return;
return vb;
}
ADVANCE(c->buffer, c->size, snmp_oid_size(oid));
snmp_oid_from_buf(&vb->name, oid);
c->sr_vb_start = vb;
return vb;
}
/*
@ -977,7 +976,6 @@ update_packet_size(struct agentx_header *start, byte *end)
/*
* response_err_ind - update response error and index
* @p: SNMP protocol instance
* @res: response PDU header
* @err: error status
* @ind: index of error, ignored for noAgentXError
@ -986,7 +984,7 @@ update_packet_size(struct agentx_header *start, byte *end)
* error is not noError, also set the corrent response PDU payload size.
*/
static inline void
response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_response_errs err, u16 ind)
response_err_ind(struct agentx_response *res, enum agentx_response_errs err, u16 ind)
{
STORE_U16(res->error, (u16) err);
// TODO deal with auto-incrementing of snmp_pdu context c.ind
@ -1019,27 +1017,27 @@ void
snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk)
{
struct mib_leaf *leaf;
leaf = snmp_walk_init(p->mib_tree, walk, o_start, c);
leaf = snmp_walk_init(p->mib_tree, walk, &c->sr_vb_start->name, c);
enum snmp_search_res res;
res = snmp_walk_fill(leaf, walk, c);
if (res != SNMP_SEARCH_OK)
snmp_set_varbind_type(c->sr_vb_start, snmp_search_res_to_type(res));
c->sr_vb_start->type = snmp_search_res_to_type(res);
}
/* agentx-GetNext-PDU */
int
snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk)
{
(void) snmp_walk_init(p->mib_tree, walk, o_start, c);
(void) snmp_walk_init(p->mib_tree, walk, &c->sr_vb_start->name, c);
struct mib_leaf *leaf = snmp_walk_next(p->mib_tree, walk, c);
enum snmp_search_res res;
res = snmp_walk_fill(leaf, walk, c);
if (res != SNMP_SEARCH_OK)
snmp_set_varbind_type(c->sr_vb_start, AGENTX_END_OF_MIB_VIEW);
c->sr_vb_start->type = AGENTX_END_OF_MIB_VIEW;
return res == SNMP_SEARCH_OK;
}
@ -1056,53 +1054,63 @@ snmp_get_bulk_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_
bulk->has_any |= snmp_get_next_pdu(p, c, o_start, walk);
}
static inline const struct oid *
int
snmp_load_oids(byte **pkt_ptr, uint *pkt_sz, struct snmp_pdu *c)
{
byte *pkt = *pkt_ptr;
uint pkt_size = *pkt_sz;
uint sz;
const struct oid *start = (const struct oid *) pkt;
if ((sz = snmp_oid_size(start)) > pkt_size)
/* in packet byte order */
const struct oid *start_buf = (const struct oid *) pkt;
if ((sz = snmp_oid_size(start_buf)) > pkt_size ||
LOAD_U8(start_buf->n_subid) >= OID_MAX_LEN)
{
c->error = AGENTX_RES_PARSE_ERROR;
*pkt_ptr = pkt;
*pkt_sz = pkt_size;
return NULL;
return 0;
}
ADVANCE(pkt, pkt_size, sz);
const struct oid *end = (const struct oid *) pkt;
if ((sz = snmp_oid_size(end)) > pkt_size)
/* in packet byte order */
const struct oid *end_buf = (const struct oid *) pkt;
if ((sz = snmp_oid_size(end_buf)) > pkt_size ||
LOAD_U8(end_buf->n_subid) >= OID_MAX_LEN)
{
c->error = AGENTX_RES_PARSE_ERROR;
*pkt_ptr = pkt;
*pkt_sz = pkt_size;
return NULL;
return 0;
}
/* in cpu native byte order */
struct agentx_varbind *start_vb = snmp_vb_to_tx(c, start_buf);
/* in cpu native byte order */
struct oid *end_oid = tmp_alloc(sz);
snmp_oid_from_buf(end_oid, end_buf);
ADVANCE(pkt, pkt_size, sz);
// TODO: this does not work
if (!snmp_is_oid_empty(end) &&
snmp_oid_compare(start, end) > 0)
if (!snmp_is_oid_empty(end_oid) &&
snmp_oid_compare(&start_vb->name, end_oid) > 0)
{
c->error = AGENTX_RES_GEN_ERROR;
*pkt_ptr = pkt;
*pkt_sz = pkt_size;
return NULL;
return 0;
}
ASSERT(start != NULL);
ASSERT(end != NULL);
ASSERT(start_vb != NULL);
ASSERT(end_oid != NULL);
c->sr_o_end = end;
c->sr_vb_start = start_vb;
c->sr_o_end = end_oid;
*pkt_ptr = pkt;
*pkt_sz = pkt_size;
return start;
return 1; /* ok */
}
/*
@ -1169,13 +1177,12 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
{
lp_restore(tmp_linpool, &tmps);
const struct oid *start_rx;
if (!(start_rx = snmp_load_oids(&pkt, &pkt_size, &c)))
if (!snmp_load_oids(&pkt, &pkt_size, &c))
{
snmp_simple_response(p, c.error,
(c.index > UINT16_MAX) ? UINT16_MAX : c.index);
snmp_reset(p);
return pkt_size + AGENTX_HEADER_SIZE;
return 0;
}
switch (h->type)
@ -1196,6 +1203,8 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
die("implementation failure");
}
snmp_varbind_leave(c.sr_vb_start);
c.sr_vb_start = NULL;
c.sr_o_end = NULL;
@ -1213,7 +1222,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
#endif
/* We update the error, index pair on the beginning of the packet. */
response_err_ind(p, response_header, c.error, c.index + 1);
response_err_ind(response_header, c.error, c.index + 1);
uint s = update_packet_size(&response_header->h, c.buffer);
/* We send the message in TX buffer. */

View File

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