diff --git a/proto/snmp/snmp.c b/proto/snmp/snmp.c index c37f4394..72040aaa 100644 --- a/proto/snmp/snmp.c +++ b/proto/snmp/snmp.c @@ -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); } diff --git a/proto/snmp/snmp.h b/proto/snmp/snmp.h index b8c057d2..7e796841 100644 --- a/proto/snmp/snmp.h +++ b/proto/snmp/snmp.h @@ -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; diff --git a/proto/snmp/snmp_utils.c b/proto/snmp/snmp_utils.c index a64b820e..6187eaba 100644 --- a/proto/snmp/snmp_utils.c +++ b/proto/snmp/snmp_utils.c @@ -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; } diff --git a/proto/snmp/snmp_utils.h b/proto/snmp/snmp_utils.h index 4ac86aa2..41ec42c4 100644 --- a/proto/snmp/snmp_utils.h +++ b/proto/snmp/snmp_utils.h @@ -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); diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index 56f5420a..f1a54a7b 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -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. */ diff --git a/proto/snmp/subagent.h b/proto/snmp/subagent.h index a2c0807a..3e922d92 100644 --- a/proto/snmp/subagent.h +++ b/proto/snmp/subagent.h @@ -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);