-src := snmp.c subagent.c bgp_mib.c
+src := snmp.c snmp_utils.c subagent.c bgp_mib.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
/* BGP_MIB states see enum BGP_INTERNAL_STATES */
#include "snmp.h"
+#include "snmp_utils.h"
#include "subagent.h"
#include "bgp_mib.h"
int
snmp_bgp_valid_ip4(struct oid *o)
{
- return snmp_valid_ip4_index_safe(o, 6);
+ return snmp_valid_ip4_index(o, 5);
}
static u8
/* else oid->n_subid >= 2 */
/* fall through */
- /* between ids[6] and ids[9] should be IP address
+ /* between ids[5] and ids[8] (n_subid == 9) should be IP address
* validity is checked later in execution because
- * this field also could mean a boundry (upper or lower)
+ * this field also could mean a query boundry (upper or lower)
*/
case 9:
case 8:
return state;
}
-inline int
+static inline int
is_dynamic(u8 state)
{
return (state >= BGP_INTERNAL_IDENTIFIER &&
static inline int
snmp_bgp_has_value(u8 state)
{
- /* bitmap would be faster */
if (state <= BGP_INTERNAL_BGP ||
state == BGP_INTERNAL_PEER_TABLE ||
- state == BGP_INTERNAL_PEER_ENTRY)
+ state == BGP_INTERNAL_PEER_ENTRY ||
+
+ /* unsupported fields */
+ state == BGP_INTERNAL_FSM_ESTABLISHED_TIME ||
+ state == BGP_INTERNAL_ORIGINATION_INTERVAL ||
+ state == BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT ||
+ state == BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME)
return 0; /* hasn't value */
else
- {
-
- }
return 1; /* has value */
}
o->n_subid = 9;
memcpy(o, o_start, snmp_oid_size(o_start));
- snmp_oid_ip4_index(o, net4_prefix(net));
+ snmp_oid_ip4_index(o, 5, net4_prefix(net));
mb_free(net);
mb_free(ws);
return NULL;
}
-byte *
-snmp_bgp_fill(struct snmp_proto *p UNUSED, struct oid *oid, byte *buf UNUSED,
-uint size UNUSED, uint contid UNUSED, int byte_ord UNUSED)
+static struct oid *
+search_bgp_dynamic(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid
+UNUSED, u8 next_state)
{
- u8 state = snmp_bgp_state(oid);
- (void)state;
- return NULL;
+ /* TODO can be remove after implementing all BGP4-MIB::bgpPeerTable columns */
+ struct oid *copy = o_start;
+ do {
+ o_start = copy = update_bgp_oid(copy, next_state);
+
+ o_start = bgp_find_dynamic_oid(p, o_start, o_end, next_state);
+
+ next_state = snmp_bgp_next_state(next_state);
+
+ } while (o_start == NULL && next_state < BGP_INTERNAL_END);
+
+ return o_start;
}
/* o_start could be o_curr, but has basically same meaning for searching */
return o_start;
else
- {
- struct oid *copy = o_start;
- do {
- /* update_bgp_oid can reallocate the underlaying struct */
- o_start = copy = update_bgp_oid(copy, next_state);
+ /* no need to check that retval < o_end -- done by bgp_find_dynamic_oid() */
+ return search_bgp_dynamic(p, o_start, o_end, 0, next_state);
+ }
- o_start = bgp_find_dynamic_oid(p, o_start, o_end, next_state);
+ /* no need to check that retval < o_end -- done by bgp_find_dynamic_oid() */
+ return search_bgp_dynamic(p, o_start, o_end, 0, start_state);
+}
- next_state = snmp_bgp_next_state(next_state);
+static byte *
+bgp_fill_dynamic(struct snmp_proto *p, struct oid *oid, byte *pkt, uint size
+UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
+{
+ struct agentx_varbind *vb = (void *) pkt;
+ *pkt += snmp_vb_size(vb);
+
+ ip_addr addr;
+ if (snmp_bgp_valid_ip4(oid))
+ addr = ipa_from_ip4(ip4_from_oid(oid));
+ else
+ return snmp_no_such_object(pkt, vb);
- } while (o_start != NULL && next_state < BGP_INTERNAL_END);
+ // TODO XXX deal with possible change of (remote) ip
+ struct snmp_bgp_peer *pe = HASH_FIND(p->bgp_hash, SNMP_HASH, addr);
- return o_start;
+ struct bgp_proto *bgp_proto = NULL;
+ struct proto *proto = NULL;
+ if (pe)
+ {
+ proto = ((struct proto_config *) pe->config)->proto;
+ if (proto->proto == &proto_bgp &&
+ ipa_equal(addr, ((struct bgp_proto *) proto)->remote_ip))
+ {
+ bgp_proto = (struct bgp_proto *) proto;
}
- }
- /* else - is_dynamic(start_state) */
- /* ... (same as do ... while above) */
+ /* binded bgp protocol not found */
+ else
+ {
+ die("Binded bgp protocol not found!");
+ return snmp_no_such_object(pkt, vb);
+ }
+ }
+ struct bgp_conn *bgp_conn = bgp_proto->conn;
+ struct bgp_conn *bgp_in = &bgp_proto->incoming_conn;
+ struct bgp_conn *bgp_out = &bgp_proto->outgoing_conn;
- return NULL;
- /* TODO not implemented yet */
+ struct bgp_stats *bgp_stats = &bgp_proto->stats;
+ const struct bgp_config *bgp_conf = bgp_proto->cf;
- /* older implementation - untested */
- /* if o_curr is in invalid state, o_curr->include does't make any
- * difference; invalid state ~ no value to put in response packet
- */
- /* indent \v/ */
- u8 state_curr = snmp_bgp_getnext_valid(state_curr);
+ uint bgp_state;
- struct oid *o_curr = update_bgp_oid(o_curr, state_curr);
+ if (bgp_conn)
+ bgp_state = bgp_conn->state;
+ else if (MAX(bgp_in->state, bgp_out->state) == BS_CLOSE &&
+ MIN(bgp_in->state, bgp_out->state) != BS_CLOSE)
+ bgp_state = MIN(bgp_in->state, bgp_out->state);
+ else if (MIN(bgp_in->state, bgp_out->state) == BS_CLOSE)
+ bgp_state = BS_IDLE;
+ else
+ bgp_state = MAX(bgp_in->state, bgp_out->state);
- /* static part of BGP4-MIB tree, not depending on BGP connections */
- if (state_curr <= 5)
+ switch (state)
{
- return o_curr;
+
+ case BGP_INTERNAL_IDENTIFIER:
+ if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED)
+ {
+ STORE_PTR(pkt, ipa_to_u32(bgp_proto->remote_ip));
+ BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+ }
+ else
+ {
+ snmp_put_blank(pkt); /* stores 4B of zeroes */
+ BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+ }
+ break;
+
+ case BGP_INTERNAL_STATE:
+ STORE_PTR(pkt, bgp_state);
+ BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ break;
+
+ case BGP_INTERNAL_ADMIN_STATUS:
+ /* struct proto ~ (struct proto *) bgp_proto */
+ if (proto->disabled)
+ STORE_PTR(pkt, AGENTX_ADMIN_STOP);
+ else
+ STORE_PTR(pkt, AGENTX_ADMIN_START);
+
+ BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ break;
+
+ case BGP_INTERNAL_NEGOTIATED_VERSION:
+ if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED)
+ STORE_PTR(pkt, 4); // TODO replace with MACRO
+ else
+ STORE_PTR(pkt, 0); /* zero dictated by rfc */
+
+ BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ break;
+
+ case BGP_INTERNAL_LOCAL_ADDR:
+ // TODO XXX bgp_proto->link_addr & zero local_ip
+ STORE_PTR(pkt, ipa_to_u32(bgp_proto->local_ip));
+ BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+ break;
+
+ case BGP_INTERNAL_LOCAL_PORT:
+ STORE_PTR(pkt, bgp_conf->local_port);
+ BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ break;
+
+ case BGP_INTERNAL_REMOTE_ADDR:
+ STORE_PTR(pkt, ipa_to_u32(bgp_proto->remote_ip));
+ BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+ break;
+
+ case BGP_INTERNAL_REMOTE_PORT:
+ STORE_PTR(pkt, bgp_conf->remote_port);
+ BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ break;
+
+ case BGP_INTERNAL_REMOTE_AS:
+ STORE_PTR(pkt, bgp_proto->remote_as);
+ BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ break;
+
+ /* IN UPDATES */
+ case BGP_INTERNAL_RX_UPDATES:
+ STORE_PTR(pkt, bgp_stats->rx_updates);
+ BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+ break;
+
+ /* OUT UPDATES */
+ case BGP_INTERNAL_TX_UPDATES:
+ STORE_PTR(pkt, bgp_stats->tx_updates);
+ BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+ break;
+
+ /* IN MESSAGES */
+ case BGP_INTERNAL_RX_MESSAGES:
+ STORE_PTR(pkt, bgp_stats->rx_messages);
+ BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+ break;
+
+ /* OUT MESSAGES */
+ case BGP_INTERNAL_TX_MESSAGES:
+ STORE_PTR(pkt, bgp_stats->tx_messages);
+ BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+ break;
+
+ case BGP_INTERNAL_LAST_ERROR:
+ STORE_PTR(pkt, 2);
+ pkt += 4;
+
+ if (bgp_proto->last_error_code)
+ {
+ /* force network order */
+ put_u32(pkt, bgp_proto->last_error_code & 0x00FF0000 << 8 |
+ bgp_proto->last_error_code & 0x000000FF << 24);
+ }
+ else
+ snmp_put_blank(pkt);
+
+ BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
+ break;
+
+ case BGP_INTERNAL_FSM_TRANSITIONS:
+ break;
+ case BGP_INTERNAL_FSM_ESTABLISHED_TIME:
+ break;
+ case BGP_INTERNAL_RETRY_INTERVAL:
+ break;
+ case BGP_INTERNAL_HOLD_TIME:
+ break;
+ case BGP_INTERNAL_KEEPALIVE:
+ break;
+ case BGP_INTERNAL_HOLD_TIME_CONFIGURED:
+ break;
+ case BGP_INTERNAL_KEEPALIVE_CONFIGURED:
+ break;
+ case BGP_INTERNAL_ORIGINATION_INTERVAL:
+ break;
+ case BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT:
+ break;
+ case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
+ break;
+ case BGP_INTERNAL_END:
+ break;
+
+ case BGP_INTERNAL_INVALID:
+ break;
+
+ case BGP_INTERNAL_BGP:
+ break;
+ case BGP_INTERNAL_PEER_TABLE:
+ break;
+ case BGP_INTERNAL_PEER_ENTRY:
+ break;
+ case BGP_INTERNAL_NO_VALUE:
+ break;
}
- /* dynamic part of BGP4-MIB tree, depending on BGP connections */
- else /* state_curr > 5 */
- {
- ip4_addr ip4 = ip4_from_oid(o_curr);
- ip4_addr dest = ip4_from_oid(o_end);
- net_addr *net = mb_allocz(p->p.pool, sizeof(struct net_addr));
- net_fill_ip4(net, ip4, IP4_MAX_PREFIX_LENGTH);
+ return NULL;
+}
- log(L_INFO "dynamic part of BGP mib");
+static byte *
+bgp_fill_static(struct snmp_proto *p, struct oid *oid, byte *buf, uint size
+UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
+{
+ log(L_INFO "snmp bgp_fill_static ()\n");
- struct f_trie_walk_state *ws = mb_allocz(p->p.pool,
- sizeof(struct f_trie_walk_state));
+ struct agentx_varbind *vb = (void *) buf;
+ byte *pkt = buf + snmp_vb_size(vb);
- struct oid *o = mb_allocz(p->p.pool, sizeof(struct oid) + 8 * sizeof(u32));
- o->n_subid = 9;
- trie_walk_init(ws, p->bgp_trie, NULL);
+ /* snmp_bgp_state() check only prefix. To be sure on oid equivalence we need to
+ * compare the oid->n_subid length. All BGP static fields have same n_subid.
+ */
+ if (oid->n_subid != 3)
+ return snmp_no_such_object(buf, vb);
- if (trie_walk_next(ws, net) && ip4_less(net4_prefix(net), dest))
- {
- memcpy(o, o_curr, snmp_oid_size(o_curr));
- snmp_oid_ip4_index(o, net4_prefix(net));
+ switch (state)
+ {
+ case BGP_INTERNAL_VERSION:
+ STORE_PTR(pkt, 1); /* store string len */
+ pkt += 4;
+ STORE_PTR(pkt, BGP4_VERSIONS);
- mb_free(net);
- mb_free(ws);
+ /* real size is 8 but we already shifted the pkt by 4 */
+ BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
+ break;
- return o;
- }
+ case BGP_INTERNAL_LOCAL_AS:
+ // XXX local as to use
- else
- {
- mb_free(net);
- mb_free(ws);
+ STORE_PTR(pkt, p->local_as);
+ BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ break;
+ }
- return NULL;
- }
+ log(L_INFO "snmp ended with non empty pkt\n");
+ return pkt;
+}
+
+byte *
+snmp_bgp_fill(struct snmp_proto *p UNUSED, struct oid *oid, byte *buf UNUSED,
+uint size UNUSED, uint contid UNUSED, int byte_ord UNUSED)
+{
+ u8 state = snmp_bgp_state(oid);
+
+ if (!is_dynamic(state))
+ return bgp_fill_static(p, oid, buf, size, contid, byte_ord, state);
+
+ if (is_dynamic(state) && snmp_bgp_has_value(state))
+ return bgp_fill_dynamic(p, oid, buf, size, contid, byte_ord, state);
+
+ else
+ {
+ // TODO XXX fix here
+ return snmp_no_such_object(buf, NULL);
}
}
struct oid;
void snmp_bgp_register(void);
-int snmp_bgp_is_supported(struct oid *o);
+// - int snmp_bgp_is_supported(struct oid *o);
int snmp_bgp_valid_ip4(struct oid *o);
u8 snmp_bgp_state(struct oid *o);
uint errs;
};
-/* fixes bugs when making tests */
-//struct protocol proto_snmp;
-
#endif
#include "bgp_mib.h"
#include "subagent.h"
#include "snmp.h"
+#include "snmp_utils.h"
+#include "snmp_internal.h"
#define SNMP_EXPECTED(actual, expected) \
bt_debug("%s expected: %3u actual: %3u\n", \
#expected, expected, actual);
+#ifdef CPU_BIG_ENDIAN
+ #define BYTE_ORD 1
+#else
+ #define BYTE_ORD 0
+#endif
+
void
dump_oid(struct oid *oid)
{
}
void
-dump_bgp_state_values(void)
+test_fill(struct snmp_proto *p)
{
- // TODO XXX here
+ ((struct proto *) p)->pool = &root_pool;
}
-
static void
test_oid(struct oid *oid, uint base_size)
{
bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME);
}
+static int
+t_s_is_oid_empty(void)
+{
+ bt_assert(snmp_is_oid_empty(NULL) == 0);
+
+ struct oid *blank = mb_alloc(&root_pool, sizeof(struct oid));
+ blank->n_subid = 0;
+ blank->prefix = 0;
+ blank->include = 0;
+
+ bt_assert(snmp_is_oid_empty(blank) == 1);
+
+ struct oid *prefixed = mb_alloc(&root_pool, sizeof(struct oid) + 3 * sizeof(u32));
+ prefixed->n_subid = 3;
+ prefixed->prefix = 100;
+ prefixed->include = 1;
+
+ u32 prefixed_arr[] = { ~((u32) 0), 0, 256 };
+ memcpy(&prefixed->ids, prefixed_arr, sizeof(prefixed_arr) /
+ sizeof(prefixed_arr[0]));
+
+ bt_assert(snmp_is_oid_empty(prefixed) == 0);
+
+ struct oid *to_prefix = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32));
+ to_prefix->n_subid = 8;
+ to_prefix->prefix = 0;
+ to_prefix->include = 1;
+
+ u32 to_prefix_arr[] = {1, 3, 6, 1, 100, ~((u32) 0), 0, 256 };
+ memcpy(&to_prefix->n_subid, to_prefix_arr, sizeof(to_prefix_arr) /
+ sizeof(to_prefix_arr[0]));
+
+ bt_assert(snmp_is_oid_empty(to_prefix) == 0);
+
+ struct oid *unprefixable = mb_alloc(&root_pool, sizeof(struct oid) + 2 * sizeof(u32));
+ unprefixable->n_subid = 2;
+ unprefixable->prefix = 0;
+ unprefixable->include = 0;
+
+ u32 unpref[] = { 65535, 4 };
+ memcpy(&unprefixable->ids, unpref, sizeof(unpref) / sizeof(unpref[0]));
+
+ bt_assert(snmp_is_oid_empty(unprefixable) == 0);
+
+ struct oid *unprefixable2 = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32));
+ unprefixable2->n_subid = 8;
+ unprefixable2->prefix = 0;
+ unprefixable2->include = 1;
+
+ u32 unpref2[] = { 1, 3, 6, 2, 1, 2, 15, 6 };
+ memcpy(&unprefixable2->ids, unpref2, sizeof(unpref2) / sizeof(unpref2[0]));
+
+ bt_assert(snmp_is_oid_empty(unprefixable2) == 0);
+
+ return 1;
+}
+
+static int
+t_s_prefixize(void)
+{
+ struct oid *nulled = NULL;
+
+ struct snmp_proto snmp_proto;
+
+ test_fill(&snmp_proto);
+
+ bt_debug("before seg fault\n");
+ struct oid *tmp = snmp_prefixize(&snmp_proto, nulled, BYTE_ORD);
+ bt_debug("after snmp_prefixize() call\n");
+ bt_assert( NULL == tmp );
+
+ bt_debug("after assert\n");
+ struct oid *blank = mb_allocz(&root_pool, sizeof(struct oid));
+
+ /* here the byte order should not matter */
+ bt_assert(snmp_is_oid_empty(snmp_prefixize(&snmp_proto, blank, 1 - BYTE_ORD)) == 1);
+
+ struct oid *prefixed = mb_alloc(&root_pool, sizeof(struct oid) + 3 * sizeof(u32));
+ prefixed->n_subid = 3;
+ prefixed->prefix = 100;
+ prefixed->include = 1;
+
+ u32 prefixed_arr[] = { ~((u32) 0), 0, 256 };
+ memcpy(&prefixed->ids, prefixed_arr, sizeof(prefixed_arr) /
+ sizeof(prefixed_arr[0]));
+
+ bt_assert(memcmp(snmp_prefixize(&snmp_proto, prefixed, BYTE_ORD), prefixed, snmp_oid_size(prefixed)) == 0);
+
+ struct oid *to_prefix = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32));
+ to_prefix->n_subid = 8;
+ to_prefix->prefix = 0;
+ to_prefix->include = 1;
+
+ u32 to_prefix_arr[] = {1, 3, 6, 1, 100, ~((u32) 0), 0, 256 };
+ memcpy(&to_prefix->n_subid, to_prefix_arr, sizeof(to_prefix_arr) /
+ sizeof(to_prefix_arr[0]));
+
+ bt_assert(memcmp(snmp_prefixize(&snmp_proto, to_prefix, BYTE_ORD), prefixed, snmp_oid_size(prefixed)) == 0);
+
+ struct oid *unprefixable = mb_alloc(&root_pool, sizeof(struct oid) + 2 * sizeof(u32));
+ unprefixable->n_subid = 2;
+ unprefixable->prefix = 0;
+ unprefixable->include = 0;
+
+ u32 unpref[] = { 65535, 4 };
+ memcpy(&unprefixable->ids, unpref, sizeof(unpref) / sizeof(unpref[0]));
+
+ bt_assert(snmp_prefixize(&snmp_proto, unprefixable, BYTE_ORD) == NULL);
+
+ struct oid *unprefixable2 = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32));
+ unprefixable2->n_subid = 8;
+ unprefixable2->prefix = 0;
+ unprefixable2->include = 1;
+
+ u32 unpref2[] = { 1, 3, 6, 2, 1, 2, 15, 6 };
+ memcpy(&unprefixable2->ids, unpref2, sizeof(unpref2) / sizeof(unpref2[0]));
+
+ bt_assert(snmp_prefixize(&snmp_proto, unprefixable2, BYTE_ORD) == NULL);
+
+ return 1;
+}
+
static int
t_s_bgp_state(void)
{
- struct oid *oid = alloca(sizeof(struct oid) + 10 * sizeof(32));
+ struct oid *oid = mb_alloc(&root_pool, sizeof(struct oid) + 10 * sizeof(u32));
/* oid header */
oid->n_subid = 0;
oid->ids[8] = 0xFFFF;
test_oid(oid, 4);
- bt_debug("testing too long oids\n");
- bt_debug("not implemented\n");
- bt_debug("exiting\n");
return 1;
}
bt_test_suite(t_s_bgp_state, "Function snmp_bgp_state()");
+ bt_test_suite(t_s_is_oid_empty, "Function snmp_is_oid_empty()");
+
+ bt_test_suite(t_s_prefixize, "Function snmp_prefixize()");
+
return bt_exit_value();
}
#include "lib/unaligned.h"
#include "subagent.h"
+#include "snmp_utils.h"
#include "bgp_mib.h"
+#include "snmp_internal.h"
+
/* =============================================================
* Problems
* ------------------------------------------------------------
*/
static int parse_response(struct snmp_proto *p, byte *buf, uint size);
-static inline uint vb_size(struct agentx_varbind *vb);
static int snmp_stop_ack(sock *sk, uint size);
static void do_response(struct snmp_proto *p, byte *buf, uint size);
static uint parse_get_pdu(struct snmp_proto *p, byte *buf, uint size);
static byte *prepare_response(struct snmp_proto *p, byte *buf, uint size);
static void response_err_ind(byte *buf, uint err, uint ind);
static struct oid *search_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr, uint contid);
-static struct oid *prefixize(struct snmp_proto *p, struct oid *o, int byte_ord);
static inline byte *find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid, int byte_ord);
-static byte *no_such_object(byte *buf, struct agentx_varbind *vb);
static const char * const snmp_errs[] = {
#define SNMP_ERR_SHIFT 256
[AGENTX_RES_PROCESSING_ERR - SNMP_ERR_SHIFT] = "Processing error",
};
-/* payload length in bytes */
-static inline size_t
-pkt_len(byte *buf, byte *pkt)
-{
- return (pkt - buf) - AGENTX_HEADER_SIZE;
-}
-
-static inline size_t
-str_size(const char *str)
-{
- return 4 + BIRD_ALIGN(strlen(str), 4);
-}
-
-int
-snmp_valid_ip4_index(struct oid *o, uint start)
-{
- for (int i = 0; i < 4; i++)
- if (o->ids[start + i] >= 256)
- return 0; // false
-
- return 1; // true
-}
-
-int
-snmp_valid_ip4_index_safe(struct oid *o, uint start)
-{
- if (start + 3 < o->n_subid)
- return snmp_valid_ip4_index(o, start);
- else
- return 0; // false
-}
-
-static byte *
-put_str(byte *buf, const char *str)
-{
- uint len = strlen(str);
- uint slen = BIRD_ALIGN(len, 4);
-
- if (len > MAX_STR)
- return NULL;
-
- STORE_PTR(buf, len);
-
- memcpy(buf + 4, str, len);
-
- for (uint i = 0; i < slen - len; i++)
- buf[len + i] = 0x00; // PADDING
-
- return buf + str_size(str);
-}
-
-static byte *
-put_blank(byte *buf)
-{
- STORE_PTR(buf, 0);
- return buf + 4;
-}
-
-static byte *
-put_oid(byte *buf, struct oid *oid)
-{
- log(L_INFO "testing oid");
- for (uint i = 0; i < oid->n_subid; i++)
- log(L_INFO "oid id %d: %u", i, oid->ids[i]);
- log(L_INFO "put_oid()");
- put_u8(buf, oid->n_subid);
- log(L_INFO "data %p: %02X", buf, *buf);
- put_u8(++buf, oid->prefix);
- log(L_INFO "data %p: %02X", buf, *buf);
- put_u8(++buf, oid->include);
- log(L_INFO "data %p: %02X", buf, *buf);
- put_u8(++buf, 0); // PADDING
- /* last increment */
- ++buf;
- log(L_INFO "oid head end %p", buf);
-
- /* copy OID data */
-#ifdef SNMP_NATIVE
- for (uint i = 0; i < oid->n_subid; i++)
- *(((u32 *) buf) + i) = oid->ids[i];
-#else
- put_u32s(buf, oid->ids, oid->n_subid << 2);
-#endif
-/*
- for (uint i = 0; i <= (oid->n_subid << 2) +4 ; i += 4)
- log(L_INFO "OID % 3u: %02X %02X %02X %02X", i,
- *(buf - 4 + i),
- *(buf - 4 + i + 1),
- *(buf - 4 + i + 2),
- *(buf - 4 + i + 3)
- );
-*/
-
- return buf + (oid->n_subid << 2);
-}
-
-void
-snmp_oid_ip4_index(struct oid *o, ip4_addr addr)
-{
- u32 temp = ip4_to_u32(addr);
- STORE(o->ids[5], temp >> 24);
- STORE(o->ids[6], (temp & 0x00FF0000) >> 16);
- STORE(o->ids[7], (temp & 0x0000FF00) >> 8);
- STORE(o->ids[8], temp & 0x000000FF);
-}
-
-/* paste data at first byte in message
- * with 3B of padding
- */
-static byte *
-paste_fbyte(byte *buf, u8 data)
-{
- log(L_INFO "paste_fbyte()");
- put_u8(buf, data);
- put_u24(++buf, 0); // PADDING
- return buf + 3;
-}
-
static void
open_pdu(struct snmp_proto *p, struct oid *oid)
{
//uint pkt_size = 0;
- if (size > AGENTX_HEADER_SIZE + snmp_oid_size(oid) + str_size(str))
+ if (size > AGENTX_HEADER_SIZE + snmp_oid_size(oid) + snmp_str_size(str))
{
log(L_INFO "open_pdu()");
STORE(h->transaction_id, 1);
STORE(h->packet_id, 1);
- pkt = paste_fbyte(pkt, p->timeout);
- pkt = put_oid(pkt, oid);
- pkt = put_str(pkt, str);
+ pkt = snmp_put_fbyte(pkt, p->timeout);
+ pkt = snmp_put_oid(pkt, oid);
+ pkt = snmp_put_str(pkt, str);
- SNMP_UPDATE(h, pkt_len(buf, pkt));
+ SNMP_UPDATE(h, snmp_pkt_len(buf, pkt));
int ret = sk_send(sk, pkt - buf);
else
log(L_INFO "open_pdu() insufficient size, %u <= %u ",
- size, AGENTX_HEADER_SIZE + snmp_oid_size(oid) + str_size(str));
+ size, AGENTX_HEADER_SIZE + snmp_oid_size(oid) + snmp_str_size(str));
}
/* index allocate / deallocate pdu * /
STORE(ur->priority, AGENTX_PRIORITY);
STORE(ur->range_subid, (len > 1) ? index : 0);
- pkt = put_oid(pkt, oid);
+ pkt = snmp_put_oid(pkt, oid);
log(L_INFO "pkt - buf : %lu sizeof %u", pkt -buf, AGENTX_HEADER_SIZE);
/* place upper-bound if needed */
pkt += 4;
}
- log("size of pkt: %u", pkt_len(buf,pkt));
- SNMP_UPDATE(h, pkt_len(buf, pkt));
+ log("size of pkt: %u", snmp_pkt_len(buf,pkt));
+ SNMP_UPDATE(h, snmp_pkt_len(buf, pkt));
for (uint i = 0; i < pkt - buf; i++)
log(L_INFO "%p: %02X", buf+i, *(buf + i));
SNMP_SESSION(h, p)
- pkt = paste_fbyte(pkt, reason);
+ pkt = snmp_put_fbyte(pkt, reason);
- SNMP_UPDATE(h, pkt_len(buf, pkt));
+ SNMP_UPDATE(h, snmp_pkt_len(buf, pkt));
log(L_INFO "preparing to sk_send()");
int ret = sk_send(sk, pkt - buf);
log(L_INFO "before hash walk");
HASH_WALK(p->bgp_hash, next, peer)
{
- snmp_oid_ip4_index(o2, ipa_to_ip4(peer->peer_ip));
+ snmp_oid_ip4_index(o2, 5, ipa_to_ip4(peer->peer_ip));
log(L_INFO "");
log(L_INFO "o2 n_subid %u prefix %u include %u", o2->n_subid,
}
struct agentx_header *rh = (void *) res;
- SNMP_UPDATE(rh, pkt_len(res, res_pkt));
+ SNMP_UPDATE(rh, snmp_pkt_len(res, res_pkt));
if (err)
response_err_ind(res, err, ind);
SNMP_LOAD_CONTEXT(p, h, req, context, clen);
res_pkt = prepare_response(p, res, rsize);
+
uint ind = 1;
int err = 0;
while (!err && pkt - req < pkt_size)
{
+ /* oids from message buffer */
struct oid *o_start_b, *o_end_b;
o_start_b = (struct oid *) pkt;
pkt += snmp_oid_size(o_start_b);
continue;
}
+ snmp_oid_dump(o_start_b);
+ snmp_oid_dump(o_end_b);
/* object identifier (oid) normalization */
- struct oid *o_start = prefixize(p, o_start_b, byte_ord);
- struct oid *o_end = prefixize(p, o_end_b, byte_ord);
+
+ struct oid *o_start = snmp_prefixize(p, o_start_b, byte_ord);
+ struct oid *o_end = snmp_prefixize(p, o_end_b, byte_ord);
+
+ snmp_oid_dump(o_start);
+ snmp_oid_dump(o_end);
u8 mib_class = get_mib_class(o_start);
+
+ log(L_INFO "get mib_class () -> next pdu parsing ... ");
+
switch (h->type)
{
case AGENTX_GET_PDU:
log(L_INFO " pasting size");
struct agentx_header *rh = (void *) res;
- SNMP_UPDATE(rh, pkt_len(res, res_pkt));
+ SNMP_UPDATE(rh, snmp_pkt_len(res, res_pkt));
log(L_INFO "%p %lu", p->sock->ttx, res_pkt - res);
log(L_INFO "%p %p", res_pkt, res);
}
}
-/* return number of bytes used by @o */
-uint
-snmp_oid_size(struct oid *o)
-{
- /* faster multipication by 4 */
- return 4 + (o->n_subid << 2);
-}
-
static inline int
oid_prefix(struct oid *o, u32 *prefix, uint len)
{
return 1; // true
}
-/* return number of bytes used by @vb */
-static inline uint
-vb_size(struct agentx_varbind *vb)
-{
- /* +4B for type and pad */
- return snmp_oid_size(&vb->name) + 4;
-}
-
int
snmp_rx(sock *sk, uint size)
{
b_state = MAX(b_in->state, b_out->state);
struct agentx_varbind *vb = (void *) pkt;
- pkt += vb_size(vb);
+ pkt += snmp_vb_size(vb);
switch (o->ids[4])
{
}
else
{
- put_blank(pkt); /* store 4B of zeroes */
+ snmp_put_blank(pkt); /* store 4B of zeroes */
BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
}
break;
case SNMP_BGP_FSM_ESTABLISHED_TIME:
case SNMP_BGP_IN_UPDATE_ELAPSED_TIME:
- return no_such_object(pkt, vb);
+ return snmp_no_such_object(pkt, vb);
/* no default */
}
snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
{
struct agentx_varbind *vb = (void *) buf;
- byte *pkt = buf + vb_size(vb);
+ byte *pkt = buf + snmp_vb_size(vb);
switch (o->ids[2])
{
/* end part of .1.3.6.1.2.1.15.3.1.x.a.b.c.d */
if (o->n_subid < 9 || o->ids[3] != SNMP_BGP_PEER_ENTRY
|| o->ids[4] == 0 || o->ids[4] > 24)
- return no_such_object(pkt, vb);
+ return snmp_no_such_object(pkt, vb);
// TODO enumerate range requests
ip_addr addr = ipa_build4(o->ids[5], o->ids[6], o->ids[7], o->ids[8]);
if (!bp)
/* pkt += 0; no data */
- return no_such_object(pkt, vb);
+ return snmp_no_such_object(pkt, vb);
return find_bgp_one(bp, o, buf, size, contid);
break;
default:
/* pkt += 0; no data */
- return no_such_object(pkt, vb);
+ return snmp_no_such_object(pkt, vb);
}
return pkt;
}
*/
-static byte *
-no_such_object(byte *buf, struct agentx_varbind *vb)
-{
- vb->type = AGENTX_NO_SUCH_OBJECT;
- return buf;
-}
-
-static UNUSED byte *
-no_such_instance(byte *buf, struct agentx_varbind *vb)
-{
- vb->type = AGENTX_NO_SUCH_INSTANCE;
- return buf;
-}
-
static inline byte *
find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
{
/* SNMPv2 mgmt mib-2 */
if (o->n_subid < 2 || (o->prefix != 2 && o->ids[0] != 1))
- no_such_object(buf + vb_size(vb), vb);
+ snmp_no_such_object(buf + snmp_vb_size(vb), vb);
switch (o->ids[1])
{
return snmp_bgp_record(p, o, buf, size, contid);
case SNMP_OSPFv3_MIB:
- return no_such_object(buf, vb);
+ return snmp_no_such_object(buf, vb);
//return find_ospf_record(p, o, buf, size);
default:
- return no_such_object(buf, vb);
+ return snmp_no_such_object(buf, vb);
}
}
/**
- * prefixize - return prefixed oid copy if possible
+ * snmp_prefixize - return prefixed oid copy if possible
* @proto: allocation pool holder
* @oid: from packet loaded object identifier
* @byte_ord: byte order of @oid
* possible. NULL otherwise. Returned pointer is always allocated from @proto's
* pool not a pointer to recieve buffer (from which is most likely @oid).
*/
-static struct oid *
-prefixize(struct snmp_proto *proto, struct oid *oid, int byte_ord)
+struct oid *
+snmp_prefixize(struct snmp_proto *proto, struct oid *oid, int byte_ord)
{
const u32 prefix[] = {1, 3, 6, 1};
+ if (snmp_is_oid_empty(oid))
+ {
+ /* allocate new zeroed oid */
+ struct oid *new = mb_allocz(proto->p.pool, sizeof(struct oid));
+ return new;
+ }
+ else if (LOAD(oid->n_subid, byte_ord) != 0)
+ {
+ struct oid *new = mb_allocz(proto->p.pool, snmp_oid_size(oid));
+ memcpy(new, oid, snmp_oid_size(oid));
+ return new;
+ }
+
if (oid->n_subid < 5)
return NULL;
find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid, int byte_ord)
{
struct oid *new;
- if (!o->prefix && (new = prefixize(p, o, byte_ord)) != NULL)
+ if (!o->prefix && (new = snmp_prefixize(p, o, byte_ord)) != NULL)
return find_prefixed(p, new, buf, size, contid);
else if (o->prefix)
return find_prefixed(p, o, buf, size, contid);
/**
* snmp_mib_fill -
*/
-static byte *
-snmp_mib_fill(struct snmp_proto *p, struct oid *oid, u8 mib_class, byte *buf,
-uint size, uint contid, int byte_ord)
+static byte *snmp_mib_fill(struct snmp_proto *p, struct oid *oid, u8 mib_class, byte *buf, uint size, uint contid, int byte_ord)
{
+ log(L_INFO "snmp_mib_fill()");
struct agentx_varbind *vb = (void *) buf;
memcpy(&vb->name, oid, snmp_oid_size(oid));
/* SNMPv2 mgmt mib-2 */
if (oid->n_subid < 2 || (oid->prefix != 2 && oid->ids[0] != 1))
- return no_such_object(buf + vb_size(vb), vb);
+ return snmp_no_such_object(buf + snmp_vb_size(vb), vb);
switch (mib_class)
{
case SNMP_CLASS_BGP:
buf = snmp_bgp_fill(p, oid, buf, size, contid, byte_ord);
- break;
+ break;
}
- return buf;
+ return buf;
}
static byte *
log(L_INFO "LOAD_STR(), %p %u", p->p.pool, l + 1); \
s = mb_allocz(p->p.pool, l + 1); \
memcpy(s, b, l); \
- b += str_size(s);
+ b += snmp_str_size(s);
#define SNMP_LOAD_CONTEXT(p, h, b, s, l) \
if (h->flags & AGENTX_NON_DEFAULT_CONTEXT) \
LOAD_STR(p, b, s, l, h->flags & AGENTX_NETWORK_BYTE_ORDER); }
#define SNMP_COPY_OID(b, o) \
- memcpy(b, o, oid_size(o)); \
- b += oid_size(o);
+ memcpy(b, o, snmp_oid_size(o)); \
+ b += snmp_oid_size(o);
#define SNMP_COPY_VB(b, s, e) \
memcpy(b, s, 4); \
SNMP_COPY_OID(b, &s->name) \
SNMP_COPY_OID(b, e)
-#define BGP_DATA_(v, d, p, o) \
- (v)->type = d; \
- p += o;
+#define BGP_DATA_(varbind, type_, packet, offset) \
+ (varbind)->type = type_; \
+ packet += offset;
-#define BGP_DATA(v, d, p) BGP_DATA_(v, d, p, 4)
+#define BGP_DATA(varbind, type_, packet) BGP_DATA_(varbind, type_, packet, 4)
struct agentx_header {
u8 version;
struct oid end;
};
+struct agentx_getbulk {
+ u16 non_repeaters;
+ u16 max_repetitions;
+};
+
struct agentx_response {
struct agentx_header h;
u32 uptime;
} PACKED;
int snmp_rx(sock *sk, uint size);
-int snmp_valid_ip4_index_safe(struct oid *o, uint start);
-int snmp_valid_ip4_index(struct oid *o, uint start);
-void snmp_oid_ip4_index(struct oid *o, ip4_addr addr);
-
-uint snmp_oid_size(struct oid *o);
static byte *snmp_mib_fill(struct snmp_proto *p, struct oid *oid, u8 mib_class, byte *buf, uint size, uint contid, int byte_ord);
#endif