Solved segmentation faults.
#include "subagent.h"
#include "bgp_mib.h"
-STATIC_ASSERT(BGP_MIB_IDLE == BS_IDLE + 1);
-STATIC_ASSERT(BGP_MIB_CONNECT == BS_CONNECT + 1);
-STATIC_ASSERT(BGP_MIB_ACTIVE == BS_ACTIVE + 1);
-STATIC_ASSERT(BGP_MIB_OPENSENT == BS_OPENSENT + 1);
-STATIC_ASSERT(BGP_MIB_OPENCONFIRM == BS_OPENCONFIRM + 1);
-STATIC_ASSERT(BGP_MIB_ESTABLISHED == BS_ESTABLISHED + 1);
-
/* hash table macros */
#define SNMP_HASH_KEY(n) n->peer_ip
#define SNMP_HASH_NEXT(n) n->next
bgp_get_candidate(u32 field)
{
const u8 translation_table[] = {
- [SNMP_BGP_PEER_IDENTIFIER] = BGP_INTERNAL_PEER_IDENTIFIER,
- [SNMP_BGP_STATE] = BGP_INTERNAL_STATE,
- [SNMP_BGP_ADMIN_STATUS] = BGP_INTERNAL_ADMIN_STATUS,
- [SNMP_BGP_NEGOTIATED_VERSION] = BGP_INTERNAL_NEGOTIATED_VERSION,
- [SNMP_BGP_LOCAL_ADDR] = BGP_INTERNAL_LOCAL_ADDR,
- [SNMP_BGP_LOCAL_PORT] = BGP_INTERNAL_LOCAL_PORT,
- [SNMP_BGP_REMOTE_ADDR] = BGP_INTERNAL_REMOTE_ADDR,
- [SNMP_BGP_REMOTE_PORT] = BGP_INTERNAL_REMOTE_PORT,
- [SNMP_BGP_REMOTE_AS] = BGP_INTERNAL_REMOTE_AS,
- [SNMP_BGP_RX_UPDATES] = BGP_INTERNAL_RX_UPDATES,
- [SNMP_BGP_TX_UPDATES] = BGP_INTERNAL_TX_UPDATES,
- [SNMP_BGP_RX_MESSAGES] = BGP_INTERNAL_RX_MESSAGES,
- [SNMP_BGP_TX_MESSAGES] = BGP_INTERNAL_TX_MESSAGES,
- [SNMP_BGP_LAST_ERROR] = BGP_INTERNAL_LAST_ERROR,
- [SNMP_BGP_FSM_TRANSITIONS] = BGP_INTERNAL_FSM_TRANSITIONS,
- [SNMP_BGP_FSM_ESTABLISHED_TIME] = BGP_INTERNAL_FSM_ESTABLISHED_TIME,
- [SNMP_BGP_RETRY_INTERVAL] = BGP_INTERNAL_RETRY_INTERVAL,
- [SNMP_BGP_HOLD_TIME] = BGP_INTERNAL_HOLD_TIME,
- [SNMP_BGP_KEEPALIVE] = BGP_INTERNAL_KEEPALIVE,
- [SNMP_BGP_HOLD_TIME_CONFIGURED] = BGP_INTERNAL_HOLD_TIME_CONFIGURED,
- [SNMP_BGP_KEEPALIVE_CONFIGURED] = BGP_INTERNAL_KEEPALIVE_CONFIGURED,
- [SNMP_BGP_ORIGINATION_INTERVAL] = BGP_INTERNAL_ORIGINATION_INTERVAL,
- [SNMP_BGP_MIN_ROUTE_ADVERTISEMENT] = BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT,
- [SNMP_BGP_IN_UPDATE_ELAPSED_TIME] = BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME,
+ [BGP4_MIB_PEER_IDENTIFIER] = BGP4_MIB_S_PEER_IDENTIFIER,
+ [BGP4_MIB_STATE] = BGP4_MIB_S_STATE,
+ [BGP4_MIB_ADMIN_STATUS] = BGP4_MIB_S_ADMIN_STATUS,
+ [BGP4_MIB_NEGOTIATED_VERSION] = BGP4_MIB_S_NEGOTIATED_VERSION,
+ [BGP4_MIB_LOCAL_ADDR] = BGP4_MIB_S_LOCAL_ADDR,
+ [BGP4_MIB_LOCAL_PORT] = BGP4_MIB_S_LOCAL_PORT,
+ [BGP4_MIB_REMOTE_ADDR] = BGP4_MIB_S_REMOTE_ADDR,
+ [BGP4_MIB_REMOTE_PORT] = BGP4_MIB_S_REMOTE_PORT,
+ [BGP4_MIB_REMOTE_AS] = BGP4_MIB_S_REMOTE_AS,
+ [BGP4_MIB_RX_UPDATES] = BGP4_MIB_S_RX_UPDATES,
+ [BGP4_MIB_TX_UPDATES] = BGP4_MIB_S_TX_UPDATES,
+ [BGP4_MIB_RX_MESSAGES] = BGP4_MIB_S_RX_MESSAGES,
+ [BGP4_MIB_TX_MESSAGES] = BGP4_MIB_S_TX_MESSAGES,
+ [BGP4_MIB_LAST_ERROR] = BGP4_MIB_S_LAST_ERROR,
+ [BGP4_MIB_FSM_TRANSITIONS] = BGP4_MIB_S_FSM_TRANSITIONS,
+ [BGP4_MIB_FSM_ESTABLISHED_TIME] = BGP4_MIB_S_FSM_ESTABLISHED_TIME,
+ [BGP4_MIB_RETRY_INTERVAL] = BGP4_MIB_S_RETRY_INTERVAL,
+ [BGP4_MIB_HOLD_TIME] = BGP4_MIB_S_HOLD_TIME,
+ [BGP4_MIB_KEEPALIVE] = BGP4_MIB_S_KEEPALIVE,
+ [BGP4_MIB_HOLD_TIME_CONFIGURED] = BGP4_MIB_S_HOLD_TIME_CONFIGURED,
+ [BGP4_MIB_KEEPALIVE_CONFIGURED] = BGP4_MIB_S_KEEPALIVE_CONFIGURED,
+ [BGP4_MIB_ORIGINATION_INTERVAL] = BGP4_MIB_S_ORIGINATION_INTERVAL,
+ [BGP4_MIB_MIN_ROUTE_ADVERTISEMENT] = BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT,
+ [BGP4_MIB_IN_UPDATE_ELAPSED_TIME] = BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME,
};
/*
*/
if (field > 0 && field <= ARRAY_SIZE(translation_table)- 1)
return translation_table[field];
- if (field == 0)
- return BGP_INTERNAL_PEER_ENTRY;
+ else if (field == 0)
+ return BGP4_MIB_S_PEER_ENTRY;
else
- return BGP_INTERNAL_PEER_TABLE_END;
+ return BGP4_MIB_S_PEER_TABLE_END;
}
/**
*/
if (snmp_is_oid_empty(oid))
- return BGP_INTERNAL_END;
+ return BGP4_MIB_S_END;
- u8 state = BGP_INTERNAL_NO_VALUE;
+ u8 state = BGP4_MIB_S_NO_VALUE;
u8 candidate;
switch (oid->n_subid)
default:
if (oid->n_subid < 2)
{
- state = BGP_INTERNAL_INVALID;
+ state = BGP4_MIB_S_INVALID;
break;
}
/* fall through */
case 4:
- if (oid->ids[3] == SNMP_BGP_PEER_ENTRY)
- state = (state == BGP_INTERNAL_NO_VALUE) ?
- BGP_INTERNAL_PEER_ENTRY : state;
+ if (oid->ids[3] == BGP4_MIB_PEER_ENTRY)
+ state = (state == BGP4_MIB_S_NO_VALUE) ?
+ BGP4_MIB_S_PEER_ENTRY : state;
else
- state = BGP_INTERNAL_NO_VALUE;
+ state = BGP4_MIB_S_NO_VALUE;
/* fall through */
switch (oid->ids[2])
{
- case SNMP_BGP_VERSION:
- state = BGP_INTERNAL_VERSION;
+ case BGP4_MIB_VERSION:
+ state = BGP4_MIB_S_VERSION;
break;
- case SNMP_BGP_LOCAL_AS:
- state = BGP_INTERNAL_LOCAL_AS;
+ case BGP4_MIB_LOCAL_AS:
+ state = BGP4_MIB_S_LOCAL_AS;
break;
- case SNMP_BGP_PEER_TABLE:
+ case BGP4_MIB_PEER_TABLE:
/* We use candidate to avoid overriding more specific state */
- candidate = BGP_INTERNAL_PEER_TABLE;
+ candidate = BGP4_MIB_S_PEER_TABLE;
break;
- case SNMP_BGP_IDENTIFIER:
- state = BGP_INTERNAL_IDENTIFIER;
+ case BGP4_MIB_IDENTIFIER:
+ state = BGP4_MIB_S_IDENTIFIER;
break;
default: /* test fails */
/* We force state invalidation */
- if (oid->ids[2] < SNMP_BGP_VERSION)
+ if (oid->ids[2] < BGP4_MIB_VERSION)
{
- state = BGP_INTERNAL_NO_VALUE;
- candidate = BGP_INTERNAL_NO_VALUE;
+ state = BGP4_MIB_S_NO_VALUE;
+ candidate = BGP4_MIB_S_NO_VALUE;
}
- else /* oid->ids[2] > SNMP_BGP_PEER_TABLE */
- state = BGP_INTERNAL_END;
+ else /* oid->ids[2] > BGP4_MIB_PEER_TABLE */
+ state = BGP4_MIB_S_END;
}
- state = (state == BGP_INTERNAL_NO_VALUE) ?
+ state = (state == BGP4_MIB_S_NO_VALUE) ?
candidate : state;
/* fall through */
case 2: /* We found bare BGP4-MIB::bgp ObjectId */
- if (state == BGP_INTERNAL_NO_VALUE ||
- state == BGP_INTERNAL_INVALID)
- state = BGP_INTERNAL_BGP;
+ if (state == BGP4_MIB_S_NO_VALUE ||
+ state == BGP4_MIB_S_INVALID)
+ state = BGP4_MIB_S_BGP;
}
return state;
/*
* snmp_bgp_notify_common - common functionaly for BGP4-MIB notifications
* @p: SNMP protocol instance
- * @type
- *
+ * @type: type of notification send - either established or backward transition
+ * @ip4: IPv4 remote addr
+ * @last_error: 2 bytes of BGP last error
+ * @state_val: BGP peer state as defined in MIB
*/
static void
snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_error[], uint state_val)
{
-#define SNMP_OID_SIZE_FROM_LEN(x) (sizeof(struct oid) + (x) * sizeof(u32))
-
- /* OIDs, VB type headers, octet string, ip4 address, integer */
- uint sz = 3 * SNMP_OID_SIZE_FROM_LEN(9) + 3 * 4 + 8 + 8 + 4;
-
- /* trap OID bgpEstablishedNotification (.1.3.6.1.2.1.0.1) */
- struct oid *head = mb_alloc(p->pool, SNMP_OID_SIZE_FROM_LEN(3)) + sz;
- head->n_subid = 3;
- head->prefix = 2;
- head->include = head->pad = 0;
+ uint sz = (uint) (snmp_varbind_size_from_len(9, AGENTX_IP_ADDRESS, 0)
+ + snmp_varbind_size_from_len(9, AGENTX_OCTET_STRING, 2)
+ + snmp_varbind_size_from_len(9, AGENTX_INTEGER, 0));
u32 trap_ids[] = { 1, 0, type };
- for (uint i = 0; i < head->n_subid; i++)
- head->ids[i] = trap_ids[i];
-
-
- void *data = (void *) head + sz;
+ STATIC_ASSERT(ARRAY_SIZE(trap_ids) == 3);
+ /* additional size for trap identification, here either
+ * bgpEstablishedNotification or bgpBackwardTransNotification (see below) */
+ void *data = tmp_alloc(snmp_oid_size_from_len(ARRAY_SIZE(trap_ids)) + sz);
+ struct oid *head = data;
+
+ { /* trap id BGP4-MIB::bgpEstablishedNotification (.1.3.6.1.2.15.0.1)
+ * or BGP4-MIB::bgpBackwardTransNotification (.1.3.6.1.2.15.0.2) */
+ head->n_subid = ARRAY_SIZE(trap_ids);
+ head->prefix = SNMP_MGMT;
+ head->include = head->reserved = 0;
+
+ for (uint i = 0; i < head->n_subid; i++)
+ head->ids[i] = trap_ids[i];
+ }
+ data += sz;
struct agentx_varbind *addr_vb = data;
- // TODO remove magic constants; use measuring functions instead
- /* +4 for varbind header, +8 for octet string */
- struct agentx_varbind *error_vb = data + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8;
- struct agentx_varbind *state_vb = (void *) error_vb + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8;
-
- addr_vb->pad = error_vb->pad = state_vb->pad = 0;
-
- struct oid *addr = &addr_vb->name;
- struct oid *error = &error_vb->name;
- struct oid *state = &state_vb->name;
-
- addr->n_subid = error->n_subid = state->n_subid = 9;
- addr->prefix = error->prefix = state->prefix = 2;
- addr->include = error->include = state->include = 0;
- addr->pad = error->pad = state->pad = 0;
+ struct agentx_varbind *error_vb = \
+ data + snmp_varbind_size_from_len(9, AGENTX_IP_ADDRESS, 0);
+ struct agentx_varbind *state_vb = \
+ (void *) error_vb + snmp_varbind_size_from_len(9, AGENTX_OCTET_STRING, 2);
u32 oid_ids[] = {
- SNMP_MIB_2, SNMP_BGP4_MIB, SNMP_BGP_PEER_TABLE, SNMP_BGP_PEER_ENTRY
+ SNMP_MIB_2, BGP4_MIB, BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY
};
- for (uint i = 0; i < sizeof(oid_ids) / sizeof(oid_ids[0]); i++)
- addr->ids[i] = error->ids[i] = state->ids[i] = oid_ids[i];
-
- addr->ids[4] = SNMP_BGP_REMOTE_ADDR;
- error->ids[4] = SNMP_BGP_LAST_ERROR;
- state->ids[4] = SNMP_BGP_STATE;
-
- for (uint i = 0; i < 4; i++)
- addr->ids[5 + i] = error->ids[5 + i] = state->ids[5 + i] \
- = (ip4_to_u32(ip4) >> (8 * (3-i))) & 0xFF;
-
- snmp_varbind_ip4(addr_vb, 100, ip4);
-
- snmp_varbind_nstr(error_vb, 100, last_error, 2);
-
- snmp_varbind_int(state_vb, 100, state_val);
+ /*
+ * The n_subid is 9 in all cases because all are rows entries of
+ * BGP4-MIB::bgpPeerTable
+ * BGP4-MIB::bgpPeerRemoteAddr = .1.3.6.1.[2].1.15.3.1.7.a.b.c.d
+ * where .1.3.6.1 is internet prefix, .[2] is SNMP_MGMT,
+ * .1.15.3.1.7.a.b.c.d has 9 elements (a.b.c.d are IP addr bytes)
+ * Here subidentifier 7 is entry type bgpPeerRemoteAddr.
+ */
+ #define PEER_TABLE_ENTRY 9
+ #define ENTRY_TYPE 4
+
+ { /* BGP4-MIB::bgpPeerRemoteAddr */
+ struct oid *addr = &addr_vb->name;
+ *addr = (struct oid) {
+ .n_subid = PEER_TABLE_ENTRY, .prefix = SNMP_MGMT, .include = 0,
+ .reserved = 0,
+ };
+ for (uint i = 0; i < ARRAY_SIZE(oid_ids); i++)
+ addr->ids[i] = oid_ids[i];
+ addr->ids[ENTRY_TYPE] = BGP4_MIB_REMOTE_ADDR;
+ ip4_to_oid(addr, ip4);
+ }
+ /* We have enough space inside the TX-buffer prepared */
+ #define UNLIMITED 100
+ snmp_varbind_ip4(addr_vb, UNLIMITED, ip4);
+
+ { /* BGP4-MIB::bgpPeerLastError */
+ struct oid *error = &error_vb->name;
+ *error = (struct oid) {
+ .n_subid = PEER_TABLE_ENTRY, .prefix = SNMP_MGMT, .include = 0,
+ .reserved = 0,
+ };
+ for (uint i = 0; i < ARRAY_SIZE(oid_ids); i++)
+ error->ids[i] = oid_ids[i];
+ error->ids[ENTRY_TYPE] = BGP4_MIB_LAST_ERROR;
+ ip4_to_oid(error, ip4);
+ }
+ snmp_varbind_nstr(error_vb, UNLIMITED, last_error, 2);
+
+ { /* BGP4-MIB::bgpPeerState */
+ struct oid *state = &state_vb->name;
+ *state = (struct oid) {
+ .n_subid = PEER_TABLE_ENTRY, .prefix = SNMP_MGMT, .include = 0,
+ .reserved = 0,
+ };
+ for (uint i = 0; i < ARRAY_SIZE(oid_ids); i++)
+ state->ids[i] = oid_ids[i];
+ state->ids[ENTRY_TYPE] = BGP4_MIB_STATE;
+ ip4_to_oid(state, ip4);
+ }
+ snmp_varbind_int(state_vb, UNLIMITED, state_val);
+ /* We do not send the systemUpTime.0 */
snmp_notify_pdu(p, head, data, sz, 0);
- mb_free(head);
- mb_free(data);
-#undef SNMP_OID_SIZE_FROM_LEN
+ #undef OID_N_SUBID
+ #undef UNLIMITED
}
/*
if (MAX(bgp_in->state, bgp_out->state) == BS_CLOSE &&
MIN(bgp_in->state, bgp_out->state) != BS_CLOSE)
- return MIN(bgp_in->state, bgp_out->state);
+ return MIN(bgp_in->state, bgp_out->state) + 1;
if (MIN(bgp_in->state, bgp_out->state) == BS_CLOSE)
return BS_IDLE;
-
- return MAX(bgp_in->state, bgp_out->state);
+
+ return MAX(bgp_in->state, bgp_out->state) + 1;
}
static void
snmp_bgp_notify_wrapper(struct snmp_proto *p, struct bgp_proto *bgp, uint type)
{
- // possibly dangerous
+ /* possibly incorrect cast */
ip4_addr ip4 = ipa_to_ip4(bgp->remote_ip);
char last_error[2];
snmp_bgp_last_error(bgp, last_error);
void
snmp_bgp_notify_established(struct snmp_proto *p, struct bgp_proto *bgp)
{
- /* .1.3.6.1.2.15.0.>1< i.e. BGP4-MIB::bgpEstablishedNotification */
- snmp_bgp_notify_wrapper(p, bgp, 1);
+ snmp_bgp_notify_wrapper(p, bgp, BGP4_MIB_ESTABLISHED_NOTIFICATION);
}
void
snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp)
{
- /* .1.3.6.1.2.15.0.>2< i.e. BGP4-MIB::bgpBackwardTransNotification */
- snmp_bgp_notify_wrapper(p, bgp, 2);
+ snmp_bgp_notify_wrapper(p, bgp, BGP4_MIB_BACKWARD_TRANS_NOTIFICATION);
}
void
snmp_bgp_register(struct snmp_proto *p)
{
- //u32 bgp_mib_prefix[] = {1, 15, 1};
u32 bgp_mib_prefix[] = { 1, 15 };
{
/* Register the whole BGP4-MIB::bgp root tree node */
struct snmp_registration *reg;
- reg = snmp_registration_create(p, SNMP_BGP4_MIB);
+ reg = snmp_registration_create(p, BGP4_MIB);
- struct oid *oid = mb_alloc(p->pool,
- snmp_oid_sizeof(ARRAY_SIZE(bgp_mib_prefix)));
+ struct oid *oid = mb_allocz(p->pool,
+ snmp_oid_size_from_len(ARRAY_SIZE(bgp_mib_prefix)));
STORE_U8(oid->n_subid, ARRAY_SIZE(bgp_mib_prefix));
STORE_U8(oid->prefix, SNMP_MGMT);
DBG(" incoming_conn state: %u", bgp_proto->incoming_conn.state + 1);
}
-static void
+static void UNUSED
print_bgp_record_all(struct snmp_proto *p)
{
DBG("dumping watched bgp status");
+/*
+ * is_dynamic - is state dependent on runtime BGP peer state
+ * @state: tested bgp4_mib state
+ *
+ * Used to distinguish states that depend on runtime BGP peer states.
+ *
+ * Return nonzero for states with value that may change at runtime.
+ */
static inline int
is_dynamic(u8 state)
{
- return (state >= BGP_INTERNAL_PEER_IDENTIFIER &&
- state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME);
+ return (state >= BGP4_MIB_S_PEER_IDENTIFIER &&
+ state <= BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME);
}
+/*
+ * is_static - logical inverse of is_dynamic() for states with value
+ * @state: tested bgp4_mib state
+ *
+ * Return nonzero for states with value that do not change at runtime.
+ */
static inline int
is_static(u8 state)
{
- return (state == BGP_INTERNAL_VERSION ||
- state == BGP_INTERNAL_LOCAL_AS ||
- state == BGP_INTERNAL_IDENTIFIER);
+ return (state == BGP4_MIB_S_VERSION ||
+ state == BGP4_MIB_S_LOCAL_AS ||
+ state == BGP4_MIB_S_IDENTIFIER);
}
static inline int
snmp_bgp_has_value(u8 state)
{
- if (state <= BGP_INTERNAL_BGP ||
- state == BGP_INTERNAL_PEER_TABLE ||
- state == BGP_INTERNAL_PEER_ENTRY ||
- state == BGP_INTERNAL_PEER_TABLE_END ||
- state >= BGP_INTERNAL_END)
+ if (state <= BGP4_MIB_S_BGP ||
+ state == BGP4_MIB_S_PEER_TABLE ||
+ state == BGP4_MIB_S_PEER_ENTRY ||
+ state == BGP4_MIB_S_PEER_TABLE_END ||
+ state >= BGP4_MIB_S_END)
return 0;
else
return 1;
u8
snmp_bgp_get_valid(u8 state)
{
- if (state == BGP_INTERNAL_INVALID ||
- state == BGP_INTERNAL_BGP ||
- state == BGP_INTERNAL_PEER_TABLE ||
- state == BGP_INTERNAL_PEER_ENTRY ||
- state == BGP_INTERNAL_PEER_TABLE_END ||
- state >= BGP_INTERNAL_END)
+ if (state == BGP4_MIB_S_INVALID ||
+ state == BGP4_MIB_S_BGP ||
+ state == BGP4_MIB_S_PEER_TABLE ||
+ state == BGP4_MIB_S_PEER_ENTRY ||
+ state == BGP4_MIB_S_PEER_TABLE_END ||
+ state >= BGP4_MIB_S_END)
return 0;
else
return state;
{
switch (state)
{
- case BGP_INTERNAL_LOCAL_AS:
- case BGP_INTERNAL_PEER_TABLE:
- case BGP_INTERNAL_PEER_ENTRY:
- return BGP_INTERNAL_PEER_IDENTIFIER;
+ case BGP4_MIB_S_LOCAL_AS:
+ case BGP4_MIB_S_PEER_TABLE:
+ case BGP4_MIB_S_PEER_ENTRY:
+ return BGP4_MIB_S_PEER_IDENTIFIER;
- case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
- case BGP_INTERNAL_PEER_TABLE_END:
- return BGP_INTERNAL_IDENTIFIER;
+ case BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME:
+ case BGP4_MIB_S_PEER_TABLE_END:
+ return BGP4_MIB_S_IDENTIFIER;
- case BGP_INTERNAL_IDENTIFIER:
- case BGP_INTERNAL_END:
- return BGP_INTERNAL_END;
+ case BGP4_MIB_S_IDENTIFIER:
+ case BGP4_MIB_S_END:
+ return BGP4_MIB_S_END;
default:
return state + 1;
}
}
-int
-snmp_bgp_is_supported(struct oid *o)
-{
- if (o->prefix == 2 && o->n_subid > 0 && o->ids[0] == 1)
- {
- if (o->n_subid == 2 && (o->ids[1] == SNMP_BGP4_MIB ||
- o->ids[1] == SNMP_BGP_LOCAL_AS))
- return 1;
- else if (o->n_subid > 2 && o->ids[1] == SNMP_BGP_PEER_TABLE &&
- o->ids[2] == SNMP_BGP_PEER_ENTRY)
- {
- if (o->n_subid == 3)
- return 1;
- if (o->n_subid == 8 && o->ids[3] > 0)
- return 1;
- }
- return 0;
- }
- return 0;
-}
-
static int
oid_state_compare(const struct oid *oid, u8 state)
{
ASSUME(oid != NULL);
- if (state >= BGP_INTERNAL_PEER_IDENTIFIER &&
- state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME)
+ if (state >= BGP4_MIB_S_PEER_IDENTIFIER &&
+ state <= BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME)
return (oid->n_subid > 9) - (oid->n_subid < 9);
- if ((state >= BGP_INTERNAL_VERSION && state <= BGP_INTERNAL_PEER_TABLE) ||
- (state == BGP_INTERNAL_IDENTIFIER))
+ if ((state >= BGP4_MIB_S_VERSION && state <= BGP4_MIB_S_PEER_TABLE) ||
+ (state == BGP4_MIB_S_IDENTIFIER))
return (oid->n_subid > 3) - (oid->n_subid < 3);
- if (state == BGP_INTERNAL_PEER_ENTRY)
+ if (state == BGP4_MIB_S_PEER_ENTRY)
return (oid->n_subid > 4) - (oid->n_subid < 4);
- if (state == BGP_INTERNAL_BGP)
+ if (state == BGP4_MIB_S_BGP)
return (oid->n_subid > 2) - (oid->n_subid < 2);
return -1;
static struct oid *
update_bgp_oid(struct oid *oid, u8 state)
{
- if (state == BGP_INTERNAL_END || state == BGP_INTERNAL_INVALID ||
- state == BGP_INTERNAL_NO_VALUE)
+ if (state == BGP4_MIB_S_END || state == BGP4_MIB_S_INVALID ||
+ state == BGP4_MIB_S_NO_VALUE)
return oid;
/* No need to reallocate anything if the OID has same lin. state */
if (snmp_bgp_state(oid) == state)
{
- if (state >= BGP_INTERNAL_PEER_IDENTIFIER &&
- state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME &&
+ if (state >= BGP4_MIB_S_PEER_IDENTIFIER &&
+ state <= BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME &&
oid->n_subid == 9)
return oid;
- if (state >= BGP_INTERNAL_VERSION &&
- state <= BGP_INTERNAL_PEER_TABLE && oid->n_subid == 3)
+ if (state >= BGP4_MIB_S_VERSION &&
+ state <= BGP4_MIB_S_PEER_TABLE && oid->n_subid == 3)
return oid;
- if (state == BGP_INTERNAL_PEER_ENTRY && oid->n_subid == 4)
+ if (state == BGP4_MIB_S_PEER_ENTRY && oid->n_subid == 4)
return oid;
- if (state == BGP_INTERNAL_BGP && oid->n_subid == 2)
+ if (state == BGP4_MIB_S_BGP && oid->n_subid == 2)
return oid;
}
switch (state)
{
- case BGP_INTERNAL_BGP:
+ case BGP4_MIB_S_BGP:
/* This could potentially destroy same old data */
if (oid->n_subid != 2)
- oid = mb_realloc(oid, snmp_oid_sizeof(2));
+ oid = mb_realloc(oid, snmp_oid_size_from_len(2));
oid->n_subid = 2;
oid->ids[0] = SNMP_MIB_2;
- oid->ids[1] = SNMP_BGP4_MIB;
+ oid->ids[1] = BGP4_MIB;
break;
- case BGP_INTERNAL_VERSION:
+ case BGP4_MIB_S_VERSION:
if (oid->n_subid != 3)
- oid = mb_realloc(oid, snmp_oid_sizeof(3));
+ oid = mb_realloc(oid, snmp_oid_size_from_len(3));
oid->n_subid = 3;
- oid->ids[2] = SNMP_BGP_VERSION;
+ oid->ids[2] = BGP4_MIB_VERSION;
break;
- case BGP_INTERNAL_LOCAL_AS:
+ case BGP4_MIB_S_LOCAL_AS:
if (oid->n_subid != 3)
- oid = mb_realloc(oid, snmp_oid_sizeof(3));
+ oid = mb_realloc(oid, snmp_oid_size_from_len(3));
oid->n_subid = 3;
- oid->ids[2] = SNMP_BGP_LOCAL_AS;
+ oid->ids[2] = BGP4_MIB_LOCAL_AS;
break;
- case BGP_INTERNAL_PEER_IDENTIFIER:
+ case BGP4_MIB_S_PEER_IDENTIFIER:
if (oid->n_subid != 9)
{
- oid = mb_realloc(oid, snmp_oid_sizeof(9));
+ oid = mb_realloc(oid, snmp_oid_size_from_len(9));
if (oid->n_subid < 6)
oid->ids[5] = 0;
oid->ids[8] = 0;
}
- oid->ids[2] = SNMP_BGP_PEER_TABLE;
- oid->ids[3] = SNMP_BGP_PEER_ENTRY;
+ oid->ids[2] = BGP4_MIB_PEER_TABLE;
+ oid->ids[3] = BGP4_MIB_PEER_ENTRY;
- oid->ids[4] = SNMP_BGP_PEER_IDENTIFIER;
+ oid->ids[4] = BGP4_MIB_PEER_IDENTIFIER;
oid->n_subid = 9;
break;
case num: \
if (oid->n_subid != 9) \
{ \
- oid = mb_realloc(oid, snmp_oid_sizeof(9)); \
+ oid = mb_realloc(oid, snmp_oid_size_from_len(9)); \
\
if (oid->n_subid < 6) \
oid->ids[5] = 0; \
oid->ids[4] = update; \
break;
- SNMP_UPDATE_CASE(BGP_INTERNAL_STATE, SNMP_BGP_STATE)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_STATE, BGP4_MIB_STATE)
- SNMP_UPDATE_CASE(BGP_INTERNAL_ADMIN_STATUS, SNMP_BGP_ADMIN_STATUS)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_ADMIN_STATUS, BGP4_MIB_ADMIN_STATUS)
- SNMP_UPDATE_CASE(BGP_INTERNAL_NEGOTIATED_VERSION, SNMP_BGP_NEGOTIATED_VERSION)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_NEGOTIATED_VERSION, BGP4_MIB_NEGOTIATED_VERSION)
- SNMP_UPDATE_CASE(BGP_INTERNAL_LOCAL_ADDR, SNMP_BGP_LOCAL_ADDR)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_LOCAL_ADDR, BGP4_MIB_LOCAL_ADDR)
- SNMP_UPDATE_CASE(BGP_INTERNAL_LOCAL_PORT, SNMP_BGP_LOCAL_PORT)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_LOCAL_PORT, BGP4_MIB_LOCAL_PORT)
- SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_ADDR, SNMP_BGP_REMOTE_ADDR)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_REMOTE_ADDR, BGP4_MIB_REMOTE_ADDR)
- SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_PORT, SNMP_BGP_REMOTE_PORT)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_REMOTE_PORT, BGP4_MIB_REMOTE_PORT)
- SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_AS, SNMP_BGP_REMOTE_AS)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_REMOTE_AS, BGP4_MIB_REMOTE_AS)
- SNMP_UPDATE_CASE(BGP_INTERNAL_RX_UPDATES, SNMP_BGP_RX_UPDATES)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_RX_UPDATES, BGP4_MIB_RX_UPDATES)
- SNMP_UPDATE_CASE(BGP_INTERNAL_TX_UPDATES, SNMP_BGP_TX_UPDATES)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_TX_UPDATES, BGP4_MIB_TX_UPDATES)
- SNMP_UPDATE_CASE(BGP_INTERNAL_RX_MESSAGES, SNMP_BGP_RX_MESSAGES)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_RX_MESSAGES, BGP4_MIB_RX_MESSAGES)
- SNMP_UPDATE_CASE(BGP_INTERNAL_TX_MESSAGES, SNMP_BGP_TX_MESSAGES)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_TX_MESSAGES, BGP4_MIB_TX_MESSAGES)
- SNMP_UPDATE_CASE(BGP_INTERNAL_LAST_ERROR, SNMP_BGP_LAST_ERROR)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_LAST_ERROR, BGP4_MIB_LAST_ERROR)
- SNMP_UPDATE_CASE(BGP_INTERNAL_FSM_TRANSITIONS, SNMP_BGP_FSM_TRANSITIONS)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_FSM_TRANSITIONS, BGP4_MIB_FSM_TRANSITIONS)
- SNMP_UPDATE_CASE(BGP_INTERNAL_FSM_ESTABLISHED_TIME, SNMP_BGP_FSM_ESTABLISHED_TIME)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_FSM_ESTABLISHED_TIME, BGP4_MIB_FSM_ESTABLISHED_TIME)
- SNMP_UPDATE_CASE(BGP_INTERNAL_RETRY_INTERVAL, SNMP_BGP_RETRY_INTERVAL)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_RETRY_INTERVAL, BGP4_MIB_RETRY_INTERVAL)
- SNMP_UPDATE_CASE(BGP_INTERNAL_HOLD_TIME, SNMP_BGP_HOLD_TIME)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_HOLD_TIME, BGP4_MIB_HOLD_TIME)
- SNMP_UPDATE_CASE(BGP_INTERNAL_KEEPALIVE, SNMP_BGP_KEEPALIVE)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_KEEPALIVE, BGP4_MIB_KEEPALIVE)
- SNMP_UPDATE_CASE(BGP_INTERNAL_HOLD_TIME_CONFIGURED, SNMP_BGP_HOLD_TIME_CONFIGURED)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_HOLD_TIME_CONFIGURED, BGP4_MIB_HOLD_TIME_CONFIGURED)
- SNMP_UPDATE_CASE(BGP_INTERNAL_KEEPALIVE_CONFIGURED, SNMP_BGP_KEEPALIVE_CONFIGURED)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_KEEPALIVE_CONFIGURED, BGP4_MIB_KEEPALIVE_CONFIGURED)
- SNMP_UPDATE_CASE(BGP_INTERNAL_ORIGINATION_INTERVAL, SNMP_BGP_ORIGINATION_INTERVAL)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_ORIGINATION_INTERVAL, BGP4_MIB_ORIGINATION_INTERVAL)
- SNMP_UPDATE_CASE(BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT, SNMP_BGP_MIN_ROUTE_ADVERTISEMENT)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT, BGP4_MIB_MIN_ROUTE_ADVERTISEMENT)
- SNMP_UPDATE_CASE(BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME, SNMP_BGP_IN_UPDATE_ELAPSED_TIME)
+ SNMP_UPDATE_CASE(BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME, BGP4_MIB_IN_UPDATE_ELAPSED_TIME)
- case BGP_INTERNAL_IDENTIFIER:
+ case BGP4_MIB_S_IDENTIFIER:
if (oid->n_subid != 3)
- oid = mb_realloc(oid, snmp_oid_sizeof(3));
+ oid = mb_realloc(oid, snmp_oid_size_from_len(3));
oid->n_subid = 3;
oid->ids[2] = 4;
default:
/* intentionally left blank */
break;
- //die("update unavailable");
}
return oid;
#undef SNMP_UPDATE_CASE
}
-static struct oid *
-bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, const struct oid *o_end, u8 start_state)
-{
- ASSUME(o_start != NULL);
- ASSUME(o_end != NULL);
-
- ip4_addr ip4 = ip4_from_oid(o_start);
- ip4_addr dest;
-
- if (o_start->n_subid < 9)
- o_start->include = 1;
-
- int check_dest = snmp_is_oid_empty(o_end);
- if (check_dest)
- {
- u8 end_state = snmp_bgp_state(o_end);
- dest = (start_state == end_state && o_end->n_subid > 5) ?
- ip4_from_oid(o_end) :
- ip4_from_u32(UINT32_MAX);
- }
-
- net_addr net;
- net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH);
-
- struct f_trie_walk_state ws;
-
- trie_walk_init(&ws, p->bgp_trie, NULL, 0);
-
- if (!trie_walk_next(&ws, &net))
- return NULL;
-
- /*
- * If the o_end is empty, then there are no conditions on the ip4 address.
- */
- int cmp = ip4_compare(net4_prefix(&net), dest);
- if (cmp < 0 || (cmp == 0 && snmp_is_oid_empty(o_end)))
- {
- // TODO repair
- struct oid *o = snmp_oid_duplicate(p->pool, o_start);
- snmp_oid_ip4_index(o, 5, net4_prefix(&net));
-
- return o;
- }
-
- return NULL;
-}
-
-static struct oid *
-search_bgp_dynamic(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid
-UNUSED, u8 next_state)
-{
- struct oid *o_copy = o_start;
- do
- {
- o_start = o_copy = update_bgp_oid(o_copy, next_state);
-
- o_start = bgp_find_dynamic_oid(p, o_start, o_end, next_state);
-
- next_state = snmp_bgp_next_state(next_state);
- /* The search in next state is done from beginning. */
- o_start->ids[5] = o_start->ids[6] = o_start->ids[7] = o_start->ids[8] = 0;
- o_start->include = 1;
-
- } while (o_start == NULL && next_state < BGP_INTERNAL_END);
-
- return o_start;
-}
-
/**
* snmp_bgp_find_next_oid - walk bgp peer addresses and update @o_start oid
*
snmp_bgp_find_next_oid(struct snmp_proto *p, struct oid *oid, uint UNUSED contid)
{
ip4_addr ip4 = ip4_from_oid(oid);
- //ip_add4 dest = ip4_from_u32(0xFFFFFFFF);
net_addr net;
net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH);
if (trie_walk_next(&ws, &net))
{
- u32 res = ipa_to_u32(net_prefix(&net));
-
ASSUME(oid->n_subid == 9);
- oid->ids[5] = (res & 0xFF000000) >> 24;
- oid->ids[6] = (res & 0x00FF0000) >> 16;
- oid->ids[7] = (res & 0x0000FF00) >> 8;
- oid->ids[8] = (res & 0x000000FF) >> 0;
+ ip4_addr res = ipa_to_ip4(net_prefix(&net));
+ ip4_to_oid(oid, res);
return 1;
}
snmp_bgp_search_dynamic(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint UNUSED contid, u8 next_state)
{
struct oid *oid = *searched;
- u8 end_state = MIN(snmp_bgp_state(o_end), BGP_INTERNAL_PEER_TABLE_END);
+ u8 end_state = MIN(snmp_bgp_state(o_end), BGP4_MIB_S_PEER_TABLE_END);
- ASSUME(end_state <= BGP_INTERNAL_END);
+ ASSUME(end_state <= BGP4_MIB_S_END);
ASSUME(oid != NULL);
oid = update_bgp_oid(oid, next_state);
while (!(found = snmp_bgp_find_next_oid(p, oid, contid)) && next_state <= end_state)
{
next_state = snmp_bgp_next_state(next_state);
- if (next_state == BGP_INTERNAL_IDENTIFIER)
+ if (next_state == BGP4_MIB_S_IDENTIFIER)
break;
oid = update_bgp_oid(oid, next_state);
/* In case of search for next bgp state, we want to start from beginning. */
oid->ids[5] = oid->ids[6] = oid->ids[7] = oid->ids[8] = 0;
}
- if (next_state < BGP_INTERNAL_PEER_TABLE_END && next_state <= end_state)
+ if (next_state < BGP4_MIB_S_PEER_TABLE_END && next_state <= end_state)
{
*searched = oid;
return SNMP_SEARCH_OK;
}
enum snmp_search_res
-snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid)
+snmp_bgp_search(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid)
{
enum snmp_search_res r = SNMP_SEARCH_END_OF_VIEW;
u8 bgp_state = snmp_bgp_state(*searched);
u8 state;
- if (bgp_state == BGP_INTERNAL_END)
+ if (bgp_state == BGP4_MIB_S_END)
{
return SNMP_SEARCH_NO_OBJECT;
}
}
state = snmp_bgp_next_state(bgp_state);
- if (state <= BGP_INTERNAL_IDENTIFIER)
+ if (state <= BGP4_MIB_S_IDENTIFIER)
{
*searched = update_bgp_oid(*searched, state);
return SNMP_SEARCH_OK;
return SNMP_SEARCH_END_OF_VIEW;
}
-struct oid *
-snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid UNUSED)
-{
- u8 start_state = snmp_bgp_state(o_start);
-
- // print debugging information
- print_bgp_record_all(p);
-
- if (o_start->include && snmp_bgp_has_value(start_state) &&
- !is_dynamic(start_state) && o_start->n_subid == 3)
- {
- /* We disable including for next time searching. */
- o_start->include = 0;
- return o_start;
- }
- else if (o_start->include && snmp_bgp_has_value(start_state) &&
- is_dynamic(start_state))
- return search_bgp_dynamic(p, o_start, o_end, contid, start_state);
-
- /* o_start is not inclusive */
-
- u8 next_state = snmp_bgp_next_state(start_state);
- // TODO more checks ?!?
- if (!is_dynamic(next_state))
- {
- o_start = update_bgp_oid(o_start, next_state);
- return o_start;
- }
-
- /* is_dynamic(next_state) == 1 */
-
- return search_bgp_dynamic(p, o_start, o_end, 0, next_state);
-}
-
static byte *
bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
struct snmp_pdu *c, u8 state)
snmp_bgp_last_error(bgp_proto, last_error);
switch (state)
{
- case BGP_INTERNAL_PEER_IDENTIFIER:
- if (fsm_state == BGP_MIB_OPENCONFIRM || fsm_state == BGP_MIB_ESTABLISHED)
+ case BGP4_MIB_S_PEER_IDENTIFIER:
+ if (fsm_state == BGP4_MIB_OPENCONFIRM || fsm_state == BGP4_MIB_ESTABLISHED)
pkt = snmp_varbind_ip4(vb, size, ip4_from_u32(bgp_proto->remote_id));
else
pkt = snmp_varbind_ip4(vb, size, IP4_NONE);
break;
- case BGP_INTERNAL_STATE:
+ case BGP4_MIB_S_STATE:
pkt = snmp_varbind_int(vb, size, fsm_state);
break;
- case BGP_INTERNAL_ADMIN_STATUS:
+ case BGP4_MIB_S_ADMIN_STATUS:
if (bgp_proto->p.disabled)
pkt = snmp_varbind_int(vb, size, AGENTX_ADMIN_STOP);
else
break;
- case BGP_INTERNAL_NEGOTIATED_VERSION:
- if (fsm_state == BGP_MIB_ESTABLISHED || fsm_state == BGP_MIB_ESTABLISHED)
- pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_VALUE);
+ case BGP4_MIB_S_NEGOTIATED_VERSION:
+ if (fsm_state == BGP4_MIB_ESTABLISHED || fsm_state == BGP4_MIB_ESTABLISHED)
+ pkt = snmp_varbind_int(vb, size, BGP4_MIB_NEGOTIATED_VER_VALUE);
else
- pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_NO_VALUE);
+ pkt = snmp_varbind_int(vb, size, BGP4_MIB_NEGOTIATED_VER_NO_VALUE);
break;
- case BGP_INTERNAL_LOCAL_ADDR:
+ case BGP4_MIB_S_LOCAL_ADDR:
pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->local_ip));
break;
- case BGP_INTERNAL_LOCAL_PORT:
+ case BGP4_MIB_S_LOCAL_PORT:
pkt = snmp_varbind_int(vb, size, bgp_conf->local_port);
break;
- case BGP_INTERNAL_REMOTE_ADDR:
+ case BGP4_MIB_S_REMOTE_ADDR:
pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->remote_ip));
break;
- case BGP_INTERNAL_REMOTE_PORT:
+ case BGP4_MIB_S_REMOTE_PORT:
pkt = snmp_varbind_int(vb, size, bgp_conf->remote_port);
break;
- case BGP_INTERNAL_REMOTE_AS:
+ case BGP4_MIB_S_REMOTE_AS:
pkt = snmp_varbind_int(vb, size, bgp_proto->remote_as);
break;
- /* IN UPDATES */
- case BGP_INTERNAL_RX_UPDATES:
+ case BGP4_MIB_S_RX_UPDATES: /* bgpPeerInUpdates */
pkt = snmp_varbind_counter32(vb, size, bgp_stats->rx_updates);
break;
- /* OUT UPDATES */
- case BGP_INTERNAL_TX_UPDATES:
+ case BGP4_MIB_S_TX_UPDATES: /* bgpPeerOutUpdate */
pkt = snmp_varbind_counter32(vb, size, bgp_stats->tx_updates);
break;
- /* IN MESSAGES */
- case BGP_INTERNAL_RX_MESSAGES:
+ case BGP4_MIB_S_RX_MESSAGES: /* bgpPeerInTotalMessages */
pkt = snmp_varbind_counter32(vb, size, bgp_stats->rx_messages);
break;
- /* OUT MESSAGES */
- case BGP_INTERNAL_TX_MESSAGES:
+ case BGP4_MIB_S_TX_MESSAGES: /* bgpPeerOutTotalMessages */
pkt = snmp_varbind_counter32(vb, size, bgp_stats->tx_messages);
break;
- case BGP_INTERNAL_LAST_ERROR:
+ case BGP4_MIB_S_LAST_ERROR:
pkt = snmp_varbind_nstr(vb, size, last_error, 2);
break;
- case BGP_INTERNAL_FSM_TRANSITIONS:
+ case BGP4_MIB_S_FSM_TRANSITIONS:
pkt = snmp_varbind_counter32(vb, size,
bgp_stats->fsm_established_transitions);
break;
- case BGP_INTERNAL_FSM_ESTABLISHED_TIME:
+ case BGP4_MIB_S_FSM_ESTABLISHED_TIME:
pkt = snmp_varbind_gauge32(vb, size,
(current_time() - bgp_proto->last_established) TO_S);
break;
- case BGP_INTERNAL_RETRY_INTERVAL:
- // retry interval != 0
+ case BGP4_MIB_S_RETRY_INTERVAL: /* retry inverval value should be != 0 */
pkt = snmp_varbind_int(vb, size, bgp_conf->connect_retry_time);
break;
- case BGP_INTERNAL_HOLD_TIME:
- // (0, 3..65535)
+ case BGP4_MIB_S_HOLD_TIME: /* hold time should be == 0 or in 3..65535 */
pkt = snmp_varbind_int(vb, size, (bgp_conn) ? bgp_conn->hold_time : 0);
break;
- case BGP_INTERNAL_KEEPALIVE:
+ case BGP4_MIB_S_KEEPALIVE:
if (!bgp_conf->hold_time)
pkt = snmp_varbind_int(vb, size, 0);
else
(bgp_conn) ? bgp_conn->keepalive_time : 0);
break;
- case BGP_INTERNAL_HOLD_TIME_CONFIGURED:
+ case BGP4_MIB_S_HOLD_TIME_CONFIGURED:
pkt = snmp_varbind_int(vb, size, bgp_conf->hold_time);
break;
- case BGP_INTERNAL_KEEPALIVE_CONFIGURED:
+ case BGP4_MIB_S_KEEPALIVE_CONFIGURED:
if (!bgp_conf->keepalive_time)
pkt = snmp_varbind_int(vb, size, 0);
else
(bgp_conn) ? bgp_conn->keepalive_time : 0);
break;
- case BGP_INTERNAL_ORIGINATION_INTERVAL:
- // (1..65535) but is not supported
+ case BGP4_MIB_S_ORIGINATION_INTERVAL:
+ /* value should be in 1..65535 but is not supported by bird */
pkt = snmp_varbind_int(vb, size, 0);
break;
- case BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT:
- // (1..65535) but is not supported
+ case BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT:
+ /* value should be in 1..65535 but is not supported by bird */
pkt = snmp_varbind_int(vb, size, 0);
break;
- case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
+ case BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME:
pkt = snmp_varbind_gauge32(vb, size,
(current_time() - bgp_proto->last_rx_update) TO_S
);
break;
- case BGP_INTERNAL_END:
+ case BGP4_MIB_S_END:
break;
- case BGP_INTERNAL_INVALID:
+ case BGP4_MIB_S_INVALID:
break;
- case BGP_INTERNAL_BGP:
+ case BGP4_MIB_S_BGP:
break;
- case BGP_INTERNAL_PEER_TABLE:
+ case BGP4_MIB_S_PEER_TABLE:
break;
- case BGP_INTERNAL_PEER_ENTRY:
+ case BGP4_MIB_S_PEER_ENTRY:
break;
- case BGP_INTERNAL_NO_VALUE:
+ case BGP4_MIB_S_NO_VALUE:
break;
}
* 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_state_compare(oid, state) < 0 || state == BGP_INTERNAL_END)
+ if (oid_state_compare(oid, state) < 0 || state == BGP4_MIB_S_END)
{
vb->type = AGENTX_NO_SUCH_OBJECT;
return pkt + snmp_varbind_header_size(vb);
switch (state)
{
- case BGP_INTERNAL_VERSION:
+ case BGP4_MIB_S_VERSION:
pkt = snmp_varbind_nstr(vb, size, BGP4_VERSIONS, 1);
break;
- case BGP_INTERNAL_LOCAL_AS:
+ case BGP4_MIB_S_LOCAL_AS:
pkt = snmp_varbind_int(vb, size, p->bgp_local_as);
break;
- case BGP_INTERNAL_IDENTIFIER:
+ case BGP4_MIB_S_IDENTIFIER:
pkt = snmp_varbind_ip4(vb, size, p->bgp_local_id);
break;
return;
}
- vb->type = AGENTX_NO_SUCH_OBJECT; // TODO
+ vb->type = AGENTX_NO_SUCH_OBJECT;
ADVANCE(c->buffer, c->size, snmp_varbind_header_size(vb));
}
-#if 0
-int
-snmp_bgp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, void *tr, struct oid *oid, uint pkt_size)
-{
- // TODO: check the type of varbind vb and it's value correctness, don't overflow the pkt_size
- return 0;
-}
-#endif
-
/*
* snmp_bgp_start - prepare BGP4-MIB
* @p - SNMP protocol instance holding memory pool
WALK_LIST(b, cf->bgp_entries)
{
const struct bgp_config *bgp_config = (struct bgp_config *) b->config;
- if (ipa_zero(bgp_config->remote_ip))
- die("unsupported dynamic BGP");
-
const struct bgp_proto *bgp = SKIP_BACK(struct bgp_proto, p,
bgp_config->c.proto);
#include "snmp.h"
#include "subagent.h"
+#define BGP4_MIB 15
+
/* peers attributes */
-enum BGP4_MIB_PEER_TABLE {
- SNMP_BGP_PEER_IDENTIFIER = 1,
- SNMP_BGP_STATE = 2,
- SNMP_BGP_ADMIN_STATUS = 3, /* in read-only mode */
- SNMP_BGP_NEGOTIATED_VERSION = 4,
- SNMP_BGP_LOCAL_ADDR = 5,
- SNMP_BGP_LOCAL_PORT = 6,
- SNMP_BGP_REMOTE_ADDR = 7,
- SNMP_BGP_REMOTE_PORT = 8,
- SNMP_BGP_REMOTE_AS = 9,
- SNMP_BGP_RX_UPDATES = 10, /* in updates */
- SNMP_BGP_TX_UPDATES = 11, /* out updates */
- SNMP_BGP_RX_MESSAGES = 12, /* in total messages */
- SNMP_BGP_TX_MESSAGES = 13, /* out total messages */
- SNMP_BGP_LAST_ERROR = 14,
- SNMP_BGP_FSM_TRANSITIONS = 15, /* FSM established transitions */
- SNMP_BGP_FSM_ESTABLISHED_TIME = 16,
- SNMP_BGP_RETRY_INTERVAL = 17,
- SNMP_BGP_HOLD_TIME = 18,
- SNMP_BGP_KEEPALIVE = 19,
- SNMP_BGP_HOLD_TIME_CONFIGURED = 20,
- SNMP_BGP_KEEPALIVE_CONFIGURED = 21,
- SNMP_BGP_ORIGINATION_INTERVAL = 22, /* UNSUPPORTED - 0 */
- SNMP_BGP_MIN_ROUTE_ADVERTISEMENT = 23, /* UNSUPPORTED - 0 */
- SNMP_BGP_IN_UPDATE_ELAPSED_TIME = 24,
+enum bgp4_mib_peer_entry_row {
+ BGP4_MIB_PEER_IDENTIFIER = 1,
+ BGP4_MIB_STATE = 2,
+ BGP4_MIB_ADMIN_STATUS = 3, /* in read-only mode */
+ BGP4_MIB_NEGOTIATED_VERSION = 4,
+ BGP4_MIB_LOCAL_ADDR = 5,
+ BGP4_MIB_LOCAL_PORT = 6,
+ BGP4_MIB_REMOTE_ADDR = 7,
+ BGP4_MIB_REMOTE_PORT = 8,
+ BGP4_MIB_REMOTE_AS = 9,
+ BGP4_MIB_RX_UPDATES = 10, /* in updates */
+ BGP4_MIB_TX_UPDATES = 11, /* out updates */
+ BGP4_MIB_RX_MESSAGES = 12, /* in total messages */
+ BGP4_MIB_TX_MESSAGES = 13, /* out total messages */
+ BGP4_MIB_LAST_ERROR = 14,
+ BGP4_MIB_FSM_TRANSITIONS = 15, /* FSM established transitions */
+ BGP4_MIB_FSM_ESTABLISHED_TIME = 16,
+ BGP4_MIB_RETRY_INTERVAL = 17,
+ BGP4_MIB_HOLD_TIME = 18,
+ BGP4_MIB_KEEPALIVE = 19,
+ BGP4_MIB_HOLD_TIME_CONFIGURED = 20,
+ BGP4_MIB_KEEPALIVE_CONFIGURED = 21,
+ BGP4_MIB_ORIGINATION_INTERVAL = 22, /* UNSUPPORTED - 0 */
+ BGP4_MIB_MIN_ROUTE_ADVERTISEMENT = 23, /* UNSUPPORTED - 0 */
+ BGP4_MIB_IN_UPDATE_ELAPSED_TIME = 24,
} PACKED;
/* version of BGP, here BGP-4 */
#define BGP4_VERSIONS ((char[]) { 0x10 }) /* OID bgp.bgpVersion */
/* for OID bgp.bgpPeerTable.bgpPeerEntry.bgpPeerNegotiatedVersion */
-#define SNMP_BGP_NEGOTIATED_VER_VALUE 4
-#define SNMP_BGP_NEGOTIATED_VER_NO_VALUE 0
+#define BGP4_MIB_NEGOTIATED_VER_VALUE 4
+#define BGP4_MIB_NEGOTIATED_VER_NO_VALUE 0
void snmp_bgp_register(struct snmp_proto *p);
u8 snmp_bgp_get_valid(u8 state);
u8 snmp_bgp_getnext_valid(u8 state);
-struct oid *snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid);
-enum snmp_search_res snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid);
+enum snmp_search_res snmp_bgp_search(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid);
void snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, struct snmp_pdu *c);
//int snmp_bgp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, void* tr, struct oid *oid, uint pkt_type);
void snmp_bgp_notify_established(struct snmp_proto *p, struct bgp_proto *bgp);
void snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp);
-#define SNMP_BGP_VERSION 1
-#define SNMP_BGP_LOCAL_AS 2
-#define SNMP_BGP_PEER_TABLE 3
-#define SNMP_BGP_PEER_ENTRY 1
-#define SNMP_BGP_IDENTIFIER 4 /* BGP4-MIB::bgpIdentifier local router id */
-
-/* BGP linearized state */
-enum BGP_INTERNAL_STATES {
- BGP_INTERNAL_INVALID = 0,
- BGP_INTERNAL_START = 1,
- BGP_INTERNAL_BGP,
- BGP_INTERNAL_VERSION,
- BGP_INTERNAL_LOCAL_AS,
- BGP_INTERNAL_PEER_TABLE,
- BGP_INTERNAL_PEER_ENTRY,
- BGP_INTERNAL_PEER_IDENTIFIER,
- BGP_INTERNAL_STATE,
- BGP_INTERNAL_ADMIN_STATUS,
- BGP_INTERNAL_NEGOTIATED_VERSION,
- BGP_INTERNAL_LOCAL_ADDR,
- BGP_INTERNAL_LOCAL_PORT,
- BGP_INTERNAL_REMOTE_ADDR,
- BGP_INTERNAL_REMOTE_PORT,
- BGP_INTERNAL_REMOTE_AS,
- BGP_INTERNAL_RX_UPDATES,
- BGP_INTERNAL_TX_UPDATES,
- BGP_INTERNAL_RX_MESSAGES,
- BGP_INTERNAL_TX_MESSAGES,
- BGP_INTERNAL_LAST_ERROR,
- BGP_INTERNAL_FSM_TRANSITIONS,
- BGP_INTERNAL_FSM_ESTABLISHED_TIME,
- BGP_INTERNAL_RETRY_INTERVAL,
- BGP_INTERNAL_HOLD_TIME,
- BGP_INTERNAL_KEEPALIVE,
- BGP_INTERNAL_HOLD_TIME_CONFIGURED,
- BGP_INTERNAL_KEEPALIVE_CONFIGURED,
- BGP_INTERNAL_ORIGINATION_INTERVAL,
- BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT,
- BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME,
- BGP_INTERNAL_PEER_TABLE_END,
- BGP_INTERNAL_IDENTIFIER, /* local identification */
- BGP_INTERNAL_END,
- BGP_INTERNAL_NO_VALUE = 255,
+enum bgp4_mib_rows {
+ BGP4_MIB_VERSION = 1,
+ BGP4_MIB_LOCAL_AS = 2,
+ BGP4_MIB_PEER_TABLE = 3, /* subtable */
+ BGP4_MIB_IDENTIFIER = 4, /* BGP4-MIB::bgpIdentifier local router id */
+};
+
+enum bgp4_mib_peer_table_rows {
+ BGP4_MIB_PEER_ENTRY = 1,
+};
+
+enum bgp4_mib_linearized_states {
+ BGP4_MIB_S_INVALID = 0, /* state invalid */
+ BGP4_MIB_S_START = 1,
+ BGP4_MIB_S_BGP,
+ BGP4_MIB_S_VERSION,
+ BGP4_MIB_S_LOCAL_AS,
+ BGP4_MIB_S_PEER_TABLE,
+ BGP4_MIB_S_PEER_ENTRY,
+ BGP4_MIB_S_PEER_IDENTIFIER,
+ BGP4_MIB_S_STATE,
+ BGP4_MIB_S_ADMIN_STATUS,
+ BGP4_MIB_S_NEGOTIATED_VERSION,
+ BGP4_MIB_S_LOCAL_ADDR,
+ BGP4_MIB_S_LOCAL_PORT,
+ BGP4_MIB_S_REMOTE_ADDR,
+ BGP4_MIB_S_REMOTE_PORT,
+ BGP4_MIB_S_REMOTE_AS,
+ BGP4_MIB_S_RX_UPDATES,
+ BGP4_MIB_S_TX_UPDATES,
+ BGP4_MIB_S_RX_MESSAGES,
+ BGP4_MIB_S_TX_MESSAGES,
+ BGP4_MIB_S_LAST_ERROR,
+ BGP4_MIB_S_FSM_TRANSITIONS,
+ BGP4_MIB_S_FSM_ESTABLISHED_TIME,
+ BGP4_MIB_S_RETRY_INTERVAL,
+ BGP4_MIB_S_HOLD_TIME,
+ BGP4_MIB_S_KEEPALIVE,
+ BGP4_MIB_S_HOLD_TIME_CONFIGURED,
+ BGP4_MIB_S_KEEPALIVE_CONFIGURED,
+ BGP4_MIB_S_ORIGINATION_INTERVAL,
+ BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT,
+ BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME,
+ BGP4_MIB_S_PEER_TABLE_END,
+ BGP4_MIB_S_IDENTIFIER, /* state local identification */
+ BGP4_MIB_S_END,
+ BGP4_MIB_S_NO_VALUE = 255,
} PACKED;
+/* valid values for BGP4_MIB_STATE */
enum bgp4_mib_bgp_states {
- BGP_MIB_IDLE = 1,
- BGP_MIB_CONNECT = 2,
- BGP_MIB_ACTIVE = 3,
- BGP_MIB_OPENSENT = 4,
- BGP_MIB_OPENCONFIRM = 5,
- BGP_MIB_ESTABLISHED = 6,
+ BGP4_MIB_IDLE = 1,
+ BGP4_MIB_CONNECT = 2,
+ BGP4_MIB_ACTIVE = 3,
+ BGP4_MIB_OPENSENT = 4,
+ BGP4_MIB_OPENCONFIRM = 5,
+ BGP4_MIB_ESTABLISHED = 6,
};
+STATIC_ASSERT(BGP4_MIB_IDLE == BS_IDLE + 1);
+STATIC_ASSERT(BGP4_MIB_CONNECT == BS_CONNECT + 1);
+STATIC_ASSERT(BGP4_MIB_ACTIVE == BS_ACTIVE + 1);
+STATIC_ASSERT(BGP4_MIB_OPENSENT == BS_OPENSENT + 1);
+STATIC_ASSERT(BGP4_MIB_OPENCONFIRM == BS_OPENCONFIRM + 1);
+STATIC_ASSERT(BGP4_MIB_ESTABLISHED == BS_ESTABLISHED + 1);
+
+/* Traps OID sub-identifiers */
+#define BGP4_MIB_ESTABLISHED_NOTIFICATION 1
+#define BGP4_MIB_BACKWARD_TRANS_NOTIFICATION 2
+
#endif
-/*
- * BIRD -- Simple Network Management Protocol (SNMP) *
+/** BIRD -- Simple Network Management Protocol (SNMP) *
* (c) 2022 Vojtech Vilimek <vojtech.vilimek@nic.cz>
* (c) 2022 CZ.NIC z.s.p.o.
*
static int
snmp_rx_skip(sock UNUSED *sk, uint UNUSED size)
{
- log(L_INFO "snmp_rx_skip with size %u", size);
return 1;
}
*
* The socket tx_hook is called when the TX-buffer is empty, i.e. all data was
* send. This function is used only when we found malformed PDU and we are
- * resetting the established session. If called we direcly reset the session.
+ * resetting the established session. If called, we are reseting the session.
*/
static void
snmp_tx_skip(sock *sk)
{
- log(L_INFO "snmp_tx_skip()");
struct snmp_proto *p = sk->data;
- snmp_set_state(p, SNMP_DOWN);
+ proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
}
/*
* snmp_set_state - change state with associated actions
* @p - SNMP protocol instance
* @state - new SNMP protocol state
+ *
+ * This function does not notify the bird about protocol state. It is therefore
+ * a responsibility of the caller to use the returned value appropriately.
+ *
+ * Return current protocol state.
*/
-void
+int
snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
{
enum snmp_proto_state last = p->state;
TRACE(D_EVENTS, "SNMP changing state to %u", state);
- p->state = state;
+ if (state == SNMP_DOWN && (last == SNMP_REGISTER || last == SNMP_CONN))
+ {
+ /* We have a connection established (at least send out agentx-Open-PDU) */
+ state = SNMP_STOP;
+ }
+ /* else - We did not send any packet, we perform protocol cleanup only. */
if (last == SNMP_RESET)
{
p->sock = NULL;
}
+ p->state = state;
+
switch (state)
{
case SNMP_INIT:
- debug("snmp -> SNMP_INIT\n");
+ DBG("snmp -> SNMP_INIT\n");
ASSERT(last == SNMP_DOWN);
struct object_lock *lock;
lock = p->lock = olock_new(p->pool);
lock->hook = snmp_start_locked;
lock->data = p;
olock_acquire(lock);
- break;
+ return PS_START;
case SNMP_LOCKED:
- debug("snmp -> SNMP_LOCKED\n");
+ DBG("snmp -> SNMP_LOCKED\n");
ASSERT(last == SNMP_INIT || SNMP_RESET);
- snmp_unset_header(p);
sock *s = sk_new(p->pool);
s->type = SK_TCP_ACTIVE;
s->saddr = ipa_from_ip4(p->local_ip);
p->sock = NULL;
tm_start(p->startup_timer, p->timeout);
}
- break;
+ return PS_START;
case SNMP_OPEN:
- debug("snmp -> SNMP_OPEN\n");
+ DBG("snmp -> SNMP_OPEN\n");
ASSERT(last == SNMP_LOCKED);
p->sock->rx_hook = snmp_rx;
p->sock->tx_hook = NULL;
- log(L_WARN " Staring subagent %u %u %u %u", p->header_offset, p->last_index, p->last_size, p->last_pkt_id);
snmp_start_subagent(p);
// handle no response (for long time)
- break;
+ return PS_START;
case SNMP_REGISTER:
- debug("snmp -> SNMP_REGISTER\n");
+ DBG("snmp -> SNMP_REGISTER\n");
ASSERT(last == SNMP_OPEN);
snmp_register_mibs(p);
- break;
+ return PS_START;
case SNMP_CONN:
- debug("snmp -> SNMP_CONN\n");
+ DBG("snmp -> SNMP_CONN\n");
ASSERT(last == SNMP_REGISTER);
- proto_notify_state(&p->p, PS_UP);
- break;
+ return PS_UP;
case SNMP_STOP:
- debug("snmp -> SNMP_STOP\n");
+ DBG("snmp -> SNMP_STOP\n");
ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
snmp_stop_subagent(p);
p->sock->rx_hook = snmp_rx_skip;
p->sock->tx_hook = snmp_tx_skip;
p->startup_timer->hook = snmp_stop_timeout;
tm_start(p->startup_timer, p->timeout);
- proto_notify_state(&p->p, PS_STOP);
- break;
+ return PS_STOP;
case SNMP_DOWN:
- debug("snmp -> SNMP_DOWN\n");
- //ASSUME(last == SNMP_STOP || SNMP_INIT || SNMP_LOCKED || SNMP_OPEN);
+ DBG("snmp -> SNMP_DOWN\n");
snmp_cleanup(p);
// FIXME: handle the state in which we call proto_notify_state and
// immediately return PS_DOWN from snmp_shutdown()
- proto_notify_state(&p->p, PS_DOWN);
- break;
+ return PS_DOWN;
case SNMP_RESET:
- debug("snmp -> SNMP_RESET\n");
+ DBG("snmp -> SNMP_RESET\n");
ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
ASSUME(p->sock);
p->sock->rx_hook = snmp_rx_skip;
p->sock->tx_hook = snmp_tx_skip;
- break;
+ return PS_STOP;
default:
- die("unknown state transition");
+ die("unknown snmp state transition");
+ return PS_DOWN;
}
}
* snmp_init - preinitialize SNMP instance
* @CF - SNMP configuration generic handle
*
- * Return value is generic handle pointing to preinitialized SNMP procotol
+ * Returns a generic handle pointing to preinitialized SNMP procotol
* instance.
*/
static struct proto *
p->bgp_trie = NULL;
}
-#if 0
-/*
- * snmp_down - stop the SNMP protocol and free resources
- * @p - SNMP protocol instance
- *
- * AgentX session is destroyed by closing underlying socket and all resources
- * are freed. Afterwards, the PS_DOWN protocol state is announced.
- */
-void
-snmp_down(struct snmp_proto *p)
-{
- snmp_cleanup(p);
- proto_notify_state(&p->p, PS_DOWN);
-}
-#endif
-
/*
- * snmp_connected - start AgentX session on established channel
+ * snmp_connected - start AgentX session on created socket
* @sk - socket owned by SNMP protocol instance
*
* Starts the AgentX communication by sending an agentx-Open-PDU.
}
/*
- * snmp_sock_disconnect - end or reset socket connection
+ * snmp_reset - end the communication on AgentX session
* @p - SNMP protocol instance
*
- * If the @reconnect flags is set, we close the socket and then reestablish
- * the AgentX session by reentering the start procedure as from the
- * snmp_start_locked() function.
- * Otherwise we simply shutdown the SNMP protocol if the flag is clear.
+ * End the communication on AgentX session by downing the whole procotol. This
+ * causes socket closure that implies AgentX session disconnection.
* This function is internal and shouldn't be used outside the SNMP module.
*/
void
-snmp_sock_disconnect(struct snmp_proto *p, int reconnect)
+snmp_reset(struct snmp_proto *p)
{
tm_stop(p->ping_timer);
-
- if (!reconnect)
- {
- snmp_set_state(p, SNMP_DOWN);
- return;
- }
-
- // TODO - wouldn't be better to use inter jump state RESET (soft reset) ?
- snmp_set_state(p, SNMP_DOWN);
-
- /* We try to reconnect after a short delay */
- //p->startup_timer->hook = snmp_startup_timeout;
- //tm_start(p->startup_timer, 4); // TODO make me configurable
+ proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
}
/*
struct snmp_proto *p = sk->data;
TRACE(D_EVENTS, "SNMP socket error %d", err);
- snmp_sock_disconnect(p, 1);
+ snmp_reset(p);
}
/*
* snmp_reconnect - helper restarting the AgentX session on packet errors
* @tm - the startup_timer holding the SNMP protocol instance
*
- * Rerun the SNMP module start procedure. Used in situations when the master
- * agent returns an agentx-Response-PDU with 'Not Opened' error. We do not close
- * the socket if have one.
+ * Try to recover from an error by reseting the SNMP protocol. It is a simple
+ * snmp_reset() wrapper for timers.
*/
void
snmp_reconnect(timer *tm)
{
struct snmp_proto *p = tm->data;
- // TODO
- snmp_set_state(p, SNMP_DOWN);
+ snmp_reset(p);
return;
- /* reset the connection */
- snmp_sock_disconnect(p, 1);
- // TODO better snmp_set_state(SNMP_DOWM); ??
- if (p->state == SNMP_STOP ||
- p->state == SNMP_DOWN)
- return;
-
- // TO-DO is SNMP_RESET really needed ?
- if (p->state == SNMP_INIT ||
- p->state == SNMP_RESET)
- //snmp_startup(p);
- {}
-
- if (!p->sock)
- snmp_start_locked(p->lock);
- else
- snmp_connected(p->sock);
-}
-
-#if 0
-/*
- * snmp_startup - start initialized SNMP protocol
- * @p - SNMP protocol to start
- *
- * Starting of SNMP protocols begins with address acqusition through object
- * lock. Next step is handled by snmp_start_locked() function.
- * This function is internal and shouldn't be used outside the SNMP
- * module.
- */
-void
-snmp_startup(struct snmp_proto *p)
-{
- // TODO inline to snmp_start()
- if (p->state == SNMP_OPEN ||
- p->state == SNMP_REGISTER ||
- p->state == SNMP_CONN)
- {
- return;
- }
-
- if (p->lock)
- {
- snmp_start_locked(p->lock);
- return;
- }
-
- p->state = SNMP_INIT;
-
- struct object_lock *lock;
- lock = p->lock = olock_new(p->pool);
-
- // lock->addr
- // lock->port
- // lock->iface
- // lock->vrf
- lock->type = OBJLOCK_TCP;
- lock->hook = snmp_start_locked;
- lock->data = p;
-
- olock_acquire(lock);
}
-#endif
/*
* snmp_startup_timeout - start the initiliazed SNMP protocol
snmp_stop_timeout(timer *tm)
{
struct snmp_proto *p = tm->data;
- snmp_set_state(p, SNMP_DOWN);
+ proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
}
/*
* snmp_ping_timeout - send a agentx-Ping-PDU
* @tm - the ping_timer holding the SNMP protocol instance.
*
- * Send an agentx-Ping-PDU and reset the timer for next ping.
+ * Send an agentx-Ping-PDU. This function is periodically called by ping
+ * timer.
*/
static void
snmp_ping_timeout(timer *tm)
* @P - SNMP protocol generic handle
*
* The first step in AgentX subagent startup is protocol initialition.
- * We must prepare lists, find BGP peers and finally asynchornously open
+ * We must prepare lists, find BGP peers and finally asynchronously open
* a AgentX subagent session through snmp_startup() function call.
*/
static int
p->bgp_local_as = cf->bgp_local_as;
p->bgp_local_id = cf->bgp_local_id;
p->timeout = cf->timeout;
- // add default value for startup_delay inside bison .Y file
+ // TODO add default value for startup_delay inside bison .Y file
p->startup_delay = cf->startup_delay;
p->pool = p->p.pool;
snmp_bgp_start(p);
- snmp_unset_header(p);
-
- snmp_set_state(p, SNMP_INIT);
-
- return PS_START;
+ return snmp_set_state(p, SNMP_INIT);
}
static inline int
* @CF - SNMP protocol configuration generic handle carring new values
*
* We accept the reconfiguration if the new configuration @CF is identical with
- * the currently deployed. Otherwise we deny reconfiguration because
+ * the currently deployed configuration. Otherwise we deny reconfiguration because
* the implementation would be cumbersome.
*/
static int
snmp_reconfigure(struct proto *P, struct proto_config *CF)
{
- // remove lost bonds, add newly created
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
const struct snmp_config *new = SKIP_BACK(struct snmp_config, cf, CF);
+ /* We are searching for configuration changes */
int retval = snmp_reconfigure_logic(p, new);
- if (retval) {
+ if (retval)
+ {
/* Reinitialize the hash after snmp_shutdown() */
HASH_INIT(p->bgp_hash, p->pool, 10);
snmp_bgp_start(p);
- snmp_unset_header(p);
}
return retval;
// TODO move me into the bgp_mib.c
cli_msg(-1006, " BGP4-MIB");
- // TODO enabled
cli_msg(-1006, " Local AS %u", p->bgp_local_as);
cli_msg(-1006, " Local router id %R", p->bgp_local_id);
cli_msg(-1006, " BGP peers");
snmp_shutdown(struct proto *P)
{
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
-
- if (p->state == SNMP_REGISTER ||
- p->state == SNMP_CONN)
- {
- /* We have a connection established (at leased send out Open-PDU). */
- snmp_set_state(p, SNMP_STOP);
- return PS_STOP;
- }
- else
- {
- /* We did not create a connection, we clean the lock and other stuff. */
- snmp_set_state(p, SNMP_DOWN);
- return PS_DOWN;
- }
+ return snmp_set_state(p, SNMP_DOWN);
}
#define SNMP_RX_BUFFER_SIZE 8192
#define SNMP_TX_BUFFER_SIZE 8192
+#define SNMP_PKT_SIZE_MAX 8192
enum snmp_proto_state {
SNMP_DOWN = 0,
btime timeout;
btime startup_delay;
u8 priority;
- //struct iface *iface;
+ //struct iface *iface; TODO
u32 bonds;
- const char *description;
- list bgp_entries;
- // TODO add support for subagent oid identification
+ const char *description; /* The order of fields is not arbitrary */
+ list bgp_entries; /* We want dynamically allocated fields to be
+ * at the end of the config struct.
+ * We use this fact to check differences of
+ * nonallocated parts of configs with memcpy
+ */
+ //const struct oid *oid_identifier; TODO
};
#define SNMP_BGP_P_REGISTERING 0x01
sock *sock;
- /* Partial packet processing */
- uint header_offset; /* offset of PDU header in TX-buffer during
- * partial parsing */
- uint last_index; /* stores last index during partial parsing */
- uint last_size; /* number of bytes used inside TX-buffer */
- uint last_pkt_id; /* stores packetId to use for partial packet */
-
btime timeout; /* timeout is part of MIB registration. It
specifies how long should the master
void snmp_connected(sock *sk);
void snmp_startup_timeout(timer *tm);
void snmp_reconnect(timer *tm);
-void snmp_sock_disconnect(struct snmp_proto *p, int reconnect);
-void snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state);
+int snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state);
+void snmp_reset(struct snmp_proto *p);
#endif
#include "snmp_utils.h"
inline void
-snmp_pdu_context(const struct snmp_proto *p, struct snmp_pdu *pdu, sock *sk)
+snmp_pdu_context(struct snmp_pdu *pdu, sock *sk)
{
pdu->error = AGENTX_RES_NO_ERROR;
- if (!snmp_is_partial(p))
- {
- pdu->buffer = sk->tpos;
- pdu->size = sk->tbuf + sk->tbsize - sk->tpos;
- pdu->index = 0;
- return;
- }
-
- pdu->buffer = sk->tbuf + p->header_offset + p->last_size;
- pdu->size = sk->tbuf + sk->tbsize - pdu->buffer;
- pdu->index = p->last_index;
+ pdu->buffer = sk->tpos;
+ pdu->size = sk->tbuf + sk->tbsize - sk->tpos;
+ pdu->index = 0;
}
+/**
+ * snmp_session - store packet ids from protocol to header
+ * @p: source SNMP protocol instance
+ * @h: dest PDU header
+ */
inline void
snmp_session(const struct snmp_proto *p, struct agentx_header *h)
{
STORE_U32(h->session_id, p->session_id);
STORE_U32(h->transaction_id, p->transaction_id);
STORE_U32(h->packet_id, p->packet_id);
- //log(L_INFO "storing packet id %u into the header %p", p->packet_id, h);
}
inline int
return h->flags & AGENTX_NON_DEFAULT_CONTEXT;
}
-inline byte *
-snmp_add_context(struct snmp_proto *p, struct agentx_header *h, uint contid)
-{
- u8 flags = LOAD_U8(h->flags);
- STORE_U8(h->flags, flags | AGENTX_NON_DEFAULT_CONTEXT);
- // TODO append the context after the header
- (void)p;
- (void)contid;
- return (void *)h + AGENTX_HEADER_SIZE;
-}
-
inline void *
snmp_varbind_data(const struct agentx_varbind *vb)
{
* snmp_is_oid_empty - check if oid is null-valued
* @oid: object identifier to check
*
- * Test if the oid header is full of zeroes. For @oid NULL returns 0.
+ * Test if the oid header is full of zeroes. For NULL-pointer @oid returns 0.
*/
int
snmp_is_oid_empty(const struct oid *oid)
{
+ /* We intentionaly ignore padding that should be zeroed */
if (oid != NULL)
return LOAD_U8(oid->n_subid) == 0 && LOAD_U8(oid->prefix) == 0 &&
LOAD_U8(oid->include) == 0;
snmp_oid_copy(struct oid *dest, const struct oid *src)
{
STORE_U8(dest->n_subid, src->n_subid);
- STORE_U8(dest->prefix, src->prefix);
+ STORE_U8(dest->prefix, src->prefix);
STORE_U8(dest->include, src->include ? 1 : 0);
- STORE_U8(dest->pad, 0);
+ STORE_U8(dest->reserved, 0);
for (int i = 0; i < LOAD_U8(src->n_subid); i++)
STORE_U32(dest->ids[i], src->ids[i]);
}
/**
- * create new null oid (blank)
+ * snmp_oid_blank - create new null oid (blank)
* @p: pool hodling snmp_proto structure
*/
struct oid *
}
/**
- * snmp_str_size_from_len - return in-buffer octet-string size
+ * snmp_str_size_from_len - return in-buffer octet string size
* @len: length of C-string, returned from strlen()
*/
-size_t
+inline size_t
snmp_str_size_from_len(uint len)
{
return 4 + BIRD_ALIGN(len, 4);
uint
snmp_oid_size(const struct oid *o)
{
- return 4 + (o->n_subid * 4);
+ return 4 + (LOAD_U8(o->n_subid) * 4);
}
/**
* @n_subid: number of ids in oid
*/
inline size_t
-snmp_oid_sizeof(uint n_subid)
+snmp_oid_size_from_len(uint n_subid)
{
return sizeof(struct oid) + n_subid * sizeof(u32);
}
}
}
+/**
+ * snmp_varbind_size_from_len - get size in-buffer VarBind for known OID and data
+ * @n_subid: number of subidentifiers of the VarBind's OID name
+ * @type: type of VarBind
+ * @len: length of variably long data
+ *
+ * For types with fixed size the @len is not used. For types such as Octet
+ * String, or OID the @len is used directly.
+ *
+ * Return number of bytes used by VarBind in specified form.
+ */
+inline size_t
+snmp_varbind_size_from_len(uint n_subid, enum agentx_type type, uint len)
+{
+ size_t sz = snmp_oid_size_from_len(n_subid)
+ + sizeof(struct agentx_varbind) - sizeof(struct oid);
+
+ int data_sz = agentx_type_size(type);
+ if (data_sz < 0)
+ sz += len;
+ else
+ sz += data_sz;
+
+ return sz;
+}
+
/*
* snmp_test_varbind - test validity of VarBind's type
* @vb: VarBind to test
snmp_create_varbind(byte *buf, struct oid *oid)
{
struct agentx_varbind *vb = (void *) buf;
- STORE_U16(vb->pad, 0);
+ STORE_U16(vb->reserved, 0);
snmp_oid_copy(&vb->name, oid);
return vb;
}
int
snmp_valid_ip4_index(const struct oid *o, uint start)
{
- if (start + 3 < o->n_subid)
+ if (start + 3 < LOAD_U8(o->n_subid))
return snmp_valid_ip4_index_unsafe(o, start);
else
return 0;
snmp_valid_ip4_index_unsafe(const struct oid *o, uint start)
{
for (int i = 0; i < 4; i++)
- if (o->ids[start + i] >= 256)
+ if (LOAD_U32(o->ids[start + i]) >= 256)
return 0;
return 1;
return buf + 3;
}
+/*
+ * snmp_oid_ip4_index - OID append IPv4 index
+ * @o: OID to use
+ * @start: index of IP addr's MSB
+ * @addr: IPv4 address to use
+ *
+ * The indices from start to (inclusive) start+3 are overwritten by @addr bytes.
+ */
void
snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr)
{
STORE_U32(o->ids[start + 3], temp & 0xFF);
}
-void UNUSED
-snmp_oid_dump(const struct oid *oid)
-{
- log(L_WARN "OID DUMP ========");
-
- if (oid == NULL)
- {
- log(L_WARN "is eqaul to NULL");
- log(L_WARN "OID DUMP END ====");
- log(L_WARN ".");
- return;
- }
-
- else if (snmp_is_oid_empty(oid))
- {
- log(L_WARN "is empty");
- log(L_WARN "OID DUMP END ====");
- log(L_WARN ".");
- return;
- }
-
- log(L_WARN " #ids: %4u prefix %3u include: %5s",
- oid->n_subid, oid->prefix, (oid->include)? "true" : "false");
- log(L_WARN "IDS -------------");
-
- for (int i = 0; i < oid->n_subid; i++)
- log(L_WARN " %2u: %11u ~ 0x%08X", i, oid->ids[i], oid->ids[i]);
-
- log(L_WARN "OID DUMP END ====");
- log(L_WARN);
-}
/** snmp_oid_compare - find the lexicographical order relation between @left and @right
* both @left and @right has to be non-blank.
type == AGENTX_INTEGER)
return 4;
- /* AGENTX_COUNTER_64 */
if (type == AGENTX_COUNTER_64)
return 8;
- /* AGENTX_OBJECT_ID, AGENTX_OCTET_STRING, AGENTX_IP_ADDRESS, AGENTX_OPAQUE */
+ if (AGENTX_IP_ADDRESS)
+ return snmp_str_size_from_len(4);
+
+ /* AGENTX_OBJECT_ID, AGENTX_OCTET_STRING, AGENTX_OPAQUE */
else
return -1;
}
return 0;
}
-inline struct agentx_header *
-snmp_create_tx_header(struct snmp_proto *p, byte *tbuf)
-{
- /* the response is created always in TX-buffer */
- p->header_offset = tbuf - p->sock->tbuf;
- ASSERT(p->header_offset < p->sock->tbsize);
- return (struct agentx_header *) tbuf;
-}
/*
- * Partial header manipulation functions
+ * Debugging
*/
-/*
- * snmp_is_partial - check if we have a partially parted packet in TX-buffer
- * @p: SNMP protocol instance
- */
-inline int
-snmp_is_partial(const struct snmp_proto *p)
+void UNUSED
+snmp_oid_dump(const struct oid *oid)
{
- return p->last_size > 0;
-}
+ log(L_WARN "OID DUMP ========");
-/*
- * snmp_get_header - restore partial packet's header from TX-buffer
- * @p: SNMP protocol instance
- */
-inline struct agentx_header *
-snmp_get_header(const struct snmp_proto *p)
-{
- /* Nonzero last size indicates existence of partial packet */
- ASSERT(p->last_size && p->header_offset < p->sock->tbsize);
- return (struct agentx_header *) (p->sock->tbuf + p->header_offset);
-}
+ if (oid == NULL)
+ {
+ log(L_WARN "is eqaul to NULL");
+ log(L_WARN "OID DUMP END ====");
+ log(L_WARN ".");
+ return;
+ }
-/*
- * snmp_set_header - store partial packet's header into protocol
- * @p: SNMP protocol instance
- * @h: header of the currently parsed PDU
- * @c: SNMP PDU context
- *
- * Store the needed values regarding later partial PDU processing.
- */
-inline void
-snmp_set_header(struct snmp_proto *p, struct agentx_header *h, struct snmp_pdu *c)
-{
- sock *sk = p->sock;
- // TODO agentx_headier in last_size or not?
- ASSERT(c->buffer - sk->tpos >= AGENTX_HEADER_SIZE);
- p->last_size = c->buffer - sk->tpos + p->last_size;
- p->header_offset = (((byte *) h) - sk->tbuf);
- p->last_index = c->index;
- log(L_INFO "using p->packet_id %u as a p->last_pkt_id %u", p->packet_id, p->last_pkt_id);
- p->last_pkt_id = p->packet_id;
- log(L_INFO "snmp_set_header() tbuf %p tpos %p buffer %p header %p header2 %p offset %u last_size %u last_index %u last_pkt_id %u",
- sk->tbuf, sk->tpos, c->buffer,h,(byte*)h, p->header_offset, p->last_size,
- p->last_index, p->last_pkt_id);
-}
+ else if (snmp_is_oid_empty(oid))
+ {
+ log(L_WARN "is empty");
+ log(L_WARN "OID DUMP END ====");
+ log(L_WARN ".");
+ return;
+ }
-/*
- * snmp_unset_header - clean partial packet's header
- * @p: SNMP protocol instance
- *
- * Clean the partial packet processing fields of protocol when the packet is
- * fully processed.
- */
-inline void
-snmp_unset_header(struct snmp_proto *p)
-{
- p->last_size = 0;
- p->header_offset = 0;
- p->last_index = 0;
- p->last_pkt_id = 0;
-}
+ log(L_WARN " #ids: %4u prefix %3u include: %5s",
+ oid->n_subid, oid->prefix, (oid->include)? "true" : "false");
+ log(L_WARN "IDS -------------");
+ for (int i = 0; i < oid->n_subid; i++)
+ log(L_WARN " %2u: %11u ~ 0x%08X", i, oid->ids[i], oid->ids[i]);
+
+ log(L_WARN "OID DUMP END ====");
+ log(L_WARN);
+}
#include "subagent.h"
uint snmp_pkt_len(const byte *start, const byte *end);
+
+/*
+ *
+ * AgentX Variable Biding (VarBind) utils
+ *
+ */
+
+/*
+ * AgentX - Variable Binding (VarBind) type utils
+ */
+void snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t);
+enum agentx_type snmp_get_varbind_type(const struct agentx_varbind *vb);
+int agentx_type_size(enum agentx_type t);
+
+/* type Octet String */
size_t snmp_str_size_from_len(uint len);
size_t snmp_str_size(const char *str);
+
+/* type OID - Object Identifier */
int snmp_is_oid_empty(const struct oid *oid);
+uint snmp_oid_size(const struct oid *o);
+size_t snmp_oid_size_from_len(uint n_subid);
+void snmp_oid_copy(struct oid *dest, const struct oid *src);
+int snmp_oid_compare(const struct oid *first, const struct oid *second);
+
+/* type IPv4 */
int snmp_valid_ip4_index(const struct oid *o, uint start);
int snmp_valid_ip4_index_unsafe(const struct oid *o, uint start);
-uint snmp_oid_size(const struct oid *o);
-size_t snmp_oid_sizeof(uint n_subid);
+void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr);
+
+/*
+ * AgentX - Variable Binding (VarBind) manupulation
+ */
uint snmp_varbind_hdr_size_from_oid(const struct oid *oid);
uint snmp_varbind_header_size(const struct agentx_varbind *vb);
uint snmp_varbind_size(const struct agentx_varbind *vb, uint limit);
uint snmp_varbind_size_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);
+void *snmp_varbind_data(const struct agentx_varbind *vb);
+
+/*
+ * AgentX - PDU headers, types, contexts
+ */
void snmp_session(const struct snmp_proto *p, struct agentx_header *h);
int snmp_has_context(const struct agentx_header *h);
-void snmp_pdu_context(const struct snmp_proto *p, struct snmp_pdu *pdu, sock *sk);
-
-void snmp_oid_copy(struct oid *dest, const struct oid *src);
-
+void snmp_pdu_context(struct snmp_pdu *pdu, sock *sk);
struct oid *snmp_oid_duplicate(pool *pool, const struct oid *oid);
struct oid *snmp_oid_blank(struct snmp_proto *p);
-void *snmp_varbind_data(const struct agentx_varbind *vb);
+int snmp_test_close_reason(byte value);
+
+/*
+ * AgentX - TX buffer manipulation
+ */
+
+/* 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);
-byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new);
-
-int snmp_oid_compare(const struct oid *first, const struct oid *second);
+byte *snmp_varbind_int(struct agentx_varbind *vb, uint size, u32 val);
+byte *snmp_varbind_counter32(struct agentx_varbind *vb, uint size, u32 val);
+byte *snmp_varbind_gauge32(struct agentx_varbind *vb, uint size, s64 val);
+byte *snmp_varbind_ticks(struct agentx_varbind *vb, uint size, u32 val);
+byte *snmp_varbind_ip4(struct agentx_varbind *vb, uint size, ip4_addr addr);
+byte *snmp_varbind_nstr(struct agentx_varbind *vb, uint size, const char *str, uint len);
+/* Raw */
byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid);
byte *snmp_no_such_instance(byte *buf, struct agentx_varbind *vb, struct oid *oid);
-
byte *snmp_put_str(byte *buf, const char *str);
byte *snmp_put_nstr(byte *buf, const char *str, uint len);
byte *snmp_put_blank(byte *buf);
byte *snmp_put_oid(byte *buf, struct oid *oid);
-
byte *snmp_put_ip4(byte *buf, ip4_addr ip4);
-
byte *snmp_put_fbyte(byte *buf, u8 data);
-void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr);
-
-void snmp_oid_dump(const struct oid *oid);
-
-void snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t);
-enum agentx_type snmp_get_varbind_type(const struct agentx_varbind *vb);
-
-//struct oid *snmp_prefixize(struct snmp_proto *p, struct oid *o);
+/*
+ *
+ * Helpers, Misc, Debugging
+ *
+ */
struct snmp_registration *snmp_registration_create(struct snmp_proto *p, u8 mib_class);
int snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, u8 class);
-/* Functions filling buffer a typed value */
-byte *snmp_varbind_int(struct agentx_varbind *vb, uint size, u32 val);
-byte *snmp_varbind_counter32(struct agentx_varbind *vb, uint size, u32 val);
-byte *snmp_varbind_gauge32(struct agentx_varbind *vb, uint size, s64 val);
-byte *snmp_varbind_ticks(struct agentx_varbind *vb, uint size, u32 val);
-byte *snmp_varbind_ip4(struct agentx_varbind *vb, uint size, ip4_addr addr);
-byte *snmp_varbind_nstr(struct agentx_varbind *vb, uint size, const char *str, uint len);
-
void snmp_dump_packet(byte *pkt, uint size);
+void snmp_oid_dump(const struct oid *oid);
enum agentx_type snmp_search_res_to_type(enum snmp_search_res res);
-int agentx_type_size(enum agentx_type t);
-
-int snmp_test_close_reason(byte value);
-
-struct agentx_header *snmp_create_tx_header(struct snmp_proto *p, byte *rbuf);
-int snmp_is_partial(const struct snmp_proto *p);
-struct agentx_header *snmp_get_header(const struct snmp_proto *p);
-void snmp_set_header(struct snmp_proto *p, struct agentx_header *h, struct snmp_pdu *c);
-void snmp_unset_header(struct snmp_proto *p);
-
#endif
--- /dev/null
+#! /bin/env python3
+
+"""
+A very simple script used to test that BIRD does not segfaults on randomly split
+AgentX PDUs.
+"""
+
+import socket
+import random
+import time
+import math
+
+ADDRESS = "127.0.0.1"
+PORT = 5000
+AGENTX_MASTER_PORT = 705
+
+def chunks(lst, n):
+ l = len(lst)
+ for i in range(0, l, n):
+ yield lst[i: min(i+n, l)]
+
+def print_msg(header, msg, total):
+ print(header, "{}/{}".format(len(msg), total))
+ for line in chunks(msg, 16):
+ print(" ", end="")
+ for char in line:
+ print("0x{:02x} ".format(char), end="")
+
+ print()
+
+def create_listen():
+ tun = socket.socket()
+ print(f"Binding to port {PORT} on {ADDRESS}")
+ tun.bind((ADDRESS, PORT))
+ print(f"Listening on {ADDRESS} port {PORT}")
+ tun.listen(2)
+
+ return tun
+
+def io_loop(rx, tx):
+ while True:
+ try:
+ to_master = rx.recv(8192)
+ except BlockingIOError:
+ to_master = None
+
+ try:
+ to_subagent = tx.recv(8192)
+ except BlockingIOError:
+ to_subagent = None
+
+ if to_master is not None and len(to_master) > 0:
+ print_msg("S=>M: ", to_master, len(to_master))
+ tx.send(to_master)
+
+ if to_subagent is not None and len(to_subagent) > 0:
+ limit = 5 * len(to_subagent) / 100
+ part_len = random.randint(math.ceil(limit),
+ math.floor(len(to_subagent) - limit))
+
+ print(f"M->S: {len(to_subagent[:part_len])}/{len(to_subagent)}")
+ rx.send(to_subagent[:part_len])
+ time.sleep(0.4)
+ print_msg("M=>S: ", to_subagent, len(to_subagent))
+ rx.send(to_subagent[part_len:])
+
+ time.sleep(0.02)
+
+def safe_io_loop(tun):
+ while True:
+ try:
+ rx, addr = tun.accept()
+ print("Subagent connected")
+
+ tx = socket.socket()
+ tx.connect((ADDRESS, AGENTX_MASTER_PORT))
+ print("Connected to master agent")
+
+ rx.setblocking(False)
+ tx.setblocking(False)
+
+ io_loop(rx, tx)
+ except BrokenPipeError:
+ rx.close()
+ tx.close()
+
+def main():
+ with create_listen() as listening:
+ safe_io_loop(listening)
+
+if __name__ == '__main__':
+ main()
*/
static void snmp_mib_fill2(struct snmp_proto *p, struct oid *oid, struct snmp_pdu *c);
-static uint parse_response(struct snmp_proto *p, byte *buf, uint size);
-static void do_response(struct snmp_proto *p, byte *buf, uint size);
-static uint parse_gets2_pdu(struct snmp_proto *p, byte *buf, uint size, uint *skip);
+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 uint update_packet_size(struct snmp_proto *p, struct agentx_header *start, byte *end);
+static uint update_packet_size(struct agentx_header *start, byte *end);
static struct oid *search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_end, struct oid *o_curr, struct snmp_pdu *c, enum snmp_search_res *result);
u32 snmp_internet[] = { SNMP_ISO, SNMP_ORG, SNMP_DOD, SNMP_INTERNET };
p->state == SNMP_CONN;
}
+/*
+ * snmp_header - store packet information into buffer
+ * @h: pointer to created packet header in TX-buffer
+ * @type: created PDU type
+ * @flags: set flags
+ *
+ * Payload length is set to zero legth. Padding is also zeroed. Real stored
+ * flags are dependent on compile-time message byte-order configuration.
+ */
static inline void
snmp_header(struct agentx_header *h, enum agentx_pdu_types type, u8 flags)
{
STORE_U8(h->version, AGENTX_VERSION);
- STORE_U8(h->type, (u8) type);
+ STORE_U8(h->type, type);
STORE_U8(h->flags, flags | SNMP_ORDER);
- STORE_U8(h->pad, 0);
+ STORE_U8(h->reserved, 0);
STORE_U32(h->payload, 0);
}
+/*
+ * snmp_blank_header - create header with no flags except default
+ * @h: pointer to created header in TX-buffer
+ * @type: create PDU type
+ *
+ * Only flag possibly set may be packet byte order configuration.
+ */
static inline void
snmp_blank_header(struct agentx_header *h, enum agentx_pdu_types type)
{
- snmp_header(h, type, 0);
+ snmp_header(h, type, (u8) 0);
}
/*
static void
snmp_register_ok(struct snmp_proto *p, struct agentx_response *res, struct oid *oid, u8 UNUSED class)
{
- // TODO switch based on oid type
+ // todo switch based on oid type
snmp_bgp_reg_ok(p, res, oid);
}
* @oid: OID whose registration failed
* @class: MIB subtree of @oid
*
- * Send a notification to MIB (selected by @class) about @oid registraion
+ * Send a notification to MIB (selected by @class) about @oid registration
* failure.
*/
static void
snmp_register_failed(struct snmp_proto *p, struct agentx_response *res, struct oid *oid, u8 UNUSED class)
{
- // TODO switch based on oid type
+ // todo switch based on oid type
snmp_bgp_reg_failed(p, res, oid);
}
/*
- * snmp_register_ack - handle registration -- response to agentx-Register-PDU
+ * snmp_register_ack - handle registration response
* @p: SNMP protocol instance
* @res: header of agentx-Response-PDU
- * @class: MIB subtree associated with agentx-Register-PDU
+ * @class: MIB subtree associated with agentx-Register-PDU
*/
void
snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class)
struct snmp_registration *reg;
WALK_LIST(reg, p->registration_queue)
{
- // TODO add support for more mib trees (other than BGP)
+ // todo add support for more mib trees (other than BGP4-MIB)
if (snmp_registration_match(reg, &res->h, class))
{
struct snmp_registered_oid *ro = \
static inline void
snmp_error(struct snmp_proto *p)
{
- snmp_set_state(p, SNMP_RESET);
+ snmp_reset(p);
+ //snmp_set_state(p, SNMP_RESET);
}
/*
* snmp_simple_response - send an agentx-Response-PDU with no data payload
* @p: SNMP protocol instance
- * @error: PDU error fields value
- * @index: PDU error index field value
+ * @error: response PDU error fields value
+ * @index: response PDU error index field value
*
* This function assumes that the buffer has enough space to fill in the AgentX
* Response PDU. So it is the responsibility of the caller to provide that.
{
sock *sk = p->sock;
struct snmp_pdu c;
- snmp_pdu_context(p, &c, sk);
+ snmp_pdu_context(&c, sk);
ASSUME(c.size >= sizeof(struct agentx_response));
sock *sk = p->sock;
struct snmp_pdu c;
- snmp_pdu_context(p, &c, sk);
+ snmp_pdu_context(&c, sk);
-#define TIMEOUT_SIZE 4 /* 1B timeout, 3B zero padding */
+#define TIMEOUT_SIZE sizeof(u32) /* 1B timeout, 3B zero padding */
+
+ /* Make sure that we have enough space in TX-buffer */
if (c.size < AGENTX_HEADER_SIZE + TIMEOUT_SIZE + snmp_oid_size(oid) +
+ snmp_str_size(cf->description))
snmp_manage_tbuf(p, &c);
- struct agentx_header *h = snmp_create_tx_header(p, c.buffer);
+ struct agentx_header *h = (void *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
snmp_blank_header(h, AGENTX_OPEN_PDU);
c.buffer = snmp_put_oid(c.buffer, oid);
c.buffer = snmp_put_str(c.buffer, cf->description);
- uint s = update_packet_size(p, h, c.buffer);
+ uint s = update_packet_size(h, c.buffer);
sk_send(sk, s);
#undef TIMEOUT_SIZE
}
sock *sk = p->sock;
struct snmp_pdu c;
- snmp_pdu_context(p, &c, sk);
+ snmp_pdu_context(&c, sk);
#define UPTIME_SIZE \
(6 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[4] } ) */
if (include_uptime)
sz += UPTIME_SIZE;
+ /* Make sure that we have enough space in TX-buffer */
if (c.size < sz)
snmp_manage_tbuf(p, &c);
- struct agentx_header *h = snmp_create_tx_header(p, c.buffer);
+ struct agentx_header *h = (void *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
snmp_blank_header(h, AGENTX_NOTIFY_PDU);
- p->packet_id++;
- log(L_INFO "incrementing packet_id to %u (notify)", p->packet_id);
+ p->packet_id++; /* New packet id */
snmp_session(p, h);
if (include_uptime)
.n_subid = 4,
.prefix = SNMP_MGMT,
.include = 0,
- .pad = 0,
+ .reserved = 0,
};
/* {mgmt}.mib-2.system.sysUpTime.sysUpTimeInstance (0) */
u32 uptime_ids[] = { 1, 1, 3, 0 };
for (uint i = 0; i < uptime_oid.n_subid; i++)
STORE_U32(vb->name.ids[i], uptime_ids[i]);
- /* TODO: use time from last reconfiguration instead? [config->load_time] */
+ /* TODO use time from last reconfiguration instead? [config->load_time] */
btime uptime = current_time() - boot_time;
snmp_varbind_ticks(vb, c.size, (uptime TO_S) / 100);
ASSUME(snmp_test_varbind(vb));
.n_subid = 6,
.prefix = 6, /* snmpV2 */
.include = 0,
- .pad = 0,
+ .reserved = 0,
};
/* {snmpV2}.snmpModules.snmpAlarmNextIndex.snmpMIBObjects.snmpTrap.snmpTrapIOD.0 */
u32 trap0_ids[] = { 3, 1, 1, 4, 1, 0 };
memcpy(c.buffer, data, size);
ADVANCE(c.buffer, c.size, size);
- uint s = update_packet_size(p, h, c.buffer);
+ uint s = update_packet_size(h, c.buffer);
sk_send(sk, s);
#undef TRAP0_HEADER_SIZE
* see snmp_register() and snmp_unregister() functions.
*/
static void
-un_register_pdu(struct snmp_proto *p, struct oid *oid, uint bound, uint index, enum agentx_pdu_types type, u8 is_instance, uint UNUSED contid)
+un_register_pdu(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, enum agentx_pdu_types type, u8 is_instance, uint UNUSED contid)
{
/* used for agentx-Register-PDU and agentx-Unregister-PDU */
const struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf);
sock *sk = p->sock;
struct snmp_pdu c;
- snmp_pdu_context(p, &c, sk);
+ snmp_pdu_context(&c, sk);
+#define BOUND_SIZE sizeof(u32)
/* conditional +4 for upper-bound (optinal field) */
- uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) + ((bound > 1) ? 4 : 0);
+ uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) +
+ ((bound > 1) ? BOUND_SIZE : 0);
if (c.size < sz)
snmp_manage_tbuf(p, &c);
- struct agentx_header *h = snmp_create_tx_header(p, c.buffer);
+ struct agentx_header *h = (void *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
snmp_header(h, type, is_instance ? AGENTX_FLAG_INSTANCE_REGISTRATION : 0);
p->packet_id++;
- log(L_INFO "incementing the packet_id to %u (%s)", p->packet_id, type ==
- AGENTX_REGISTER_PDU ? "register" : "unregister");
snmp_session(p, h);
struct agentx_un_register_hdr *ur = (struct agentx_un_register_hdr *) c.buffer;
/* use selected priority */
STORE_U8(ur->priority, cf->priority);
STORE_U8(ur->range_subid, (bound > 1) ? index : 0);
- STORE_U8(ur->pad, 0);
+ STORE_U8(ur->reserved, 0);
ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_hdr));
snmp_put_oid(c.buffer, oid);
if (bound > 1)
{
STORE_PTR(c.buffer, bound);
- ADVANCE(c.buffer, c.size, 4);
+ ADVANCE(c.buffer, c.size, BOUND_SIZE);
}
- uint s = update_packet_size(p, h, c.buffer);
+ uint s = update_packet_size(h, c.buffer);
sk_send(sk, s);
+#undef BOUND_SIZE
}
/*
* For more detailed description see un_register_pdu() function.
*/
void
-snmp_register(struct snmp_proto *p, struct oid *oid, uint bound, uint index, u8 is_instance, uint contid)
+snmp_register(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, u8 is_instance, uint contid)
{
- log(L_INFO "performing a registration");
un_register_pdu(p, oid, bound, index, AGENTX_REGISTER_PDU, is_instance, contid);
}
* For more detailed description see un_register_pdu() function.
*/
void UNUSED
-snmp_unregister(struct snmp_proto *p, struct oid *oid, uint len, uint index, uint contid)
+snmp_unregister(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, uint contid)
{
- un_register_pdu(p, oid, len, index, AGENTX_UNREGISTER_PDU, 0, contid);
+ un_register_pdu(p, oid, bound, index, AGENTX_UNREGISTER_PDU, 0, contid);
}
/*
* @p: SNMP protocol instance
* @reason: reason for closure
*/
-static void
+static void UNUSED
close_pdu(struct snmp_proto *p, enum agentx_close_reasons reason)
{
sock *sk = p->sock;
struct snmp_pdu c;
- snmp_pdu_context(p, &c, sk);
+ snmp_pdu_context(&c, sk);
-#define REASON_SIZE 4
+#define REASON_SIZE sizeof(u32)
if (c.size < AGENTX_HEADER_SIZE + REASON_SIZE)
snmp_manage_tbuf(p, &c);
- struct agentx_header *h = snmp_create_tx_header(p, c.buffer);
+ struct agentx_header *h = (void *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
snmp_blank_header(h, AGENTX_CLOSE_PDU);
p->packet_id++;
- log(L_INFO "incrementing packet_id %u (close)", p->packet_id);
snmp_session(p, h);
snmp_put_fbyte(c.buffer, (u8) reason);
ADVANCE(c.buffer, c.size, 4);
- uint s = update_packet_size(p, h, c.buffer);
+ uint s = update_packet_size(h, c.buffer);
sk_send(sk, s);
#undef REASON_SIZE
}
* parse_close_pdu - parse an agentx-Close-PDU
* @p: SNMP protocol instance
* @pkt_start: pointer to first byte of PDU
- * @size: number of bytes received from a socket
*
* Return number of bytes parsed from RX-buffer.
*/
static uint
-parse_close_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
+parse_close_pdu(struct snmp_proto *p, byte * const pkt_start)
{
TRACE(D_PACKETS, "SNMP received agentx-Close-PDU");
byte *pkt = pkt_start;
- if (size < sizeof(struct agentx_close_pdu))
+ struct agentx_close_pdu *pdu = (void *) pkt;
+ pkt += sizeof(struct agentx_close_pdu);
+ uint pkt_size = pdu->h.payload;
+
+ if (pkt_size != sizeof(struct agentx_close_pdu))
{
TRACE(D_PACKETS, "SNMP malformed agentx-Close-PDU, closing anyway");
snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
snmp_set_state(p, SNMP_RESET);
- return size;
+ return MIN(pkt_size + AGENTX_HEADER_SIZE, sizeof(struct agentx_close_pdu));
}
- struct agentx_close_pdu *pdu = (void *) pkt;
- ADVANCE(pkt, size, sizeof(struct agentx_close_pdu));
-
if (!snmp_test_close_reason(pdu->reason))
{
- TRACE(D_PACKETS, "SNMP invalid close reason");
+ TRACE(D_PACKETS, "SNMP invalid close reason %u", pdu->reason);
snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
snmp_set_state(p, SNMP_RESET);
- return sizeof(struct agentx_close_pdu);
+ return pkt_size + AGENTX_HEADER_SIZE;
}
enum agentx_close_reasons reason = (enum agentx_close_reasons) pdu->reason;
TRACE(D_PACKETS, "SNMP close reason %u", reason);
snmp_simple_response(p, AGENTX_RES_NO_ERROR, 0);
snmp_set_state(p, SNMP_RESET);
- return sizeof(struct agentx_close_pdu);
+ return pkt_size + AGENTX_HEADER_SIZE;
}
{
/* Hard-coded no support for writing */
(void)p;(void)vb;(void)oid;(void)pkt_size;
- return 0;
+ snmp_simple_response(p, AGENTX_RES_NOT_WRITABLE, 1);
+ return pkt_size + AGENTX_HEADER_SIZE;
#if 0
if (!oid)
return 0;
{
p->transaction_id = LOAD_U32(h->transaction_id);
p->packet_id = LOAD_U32(h->packet_id);
- //log(L_INFO "loading packet_id %u from header %p", p->packet_id, h);
}
/*
*
* Return number of bytes parsed from RX-buffer.
*/
-static uint
-parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
+static inline uint
+parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start)
{
TRACE(D_PACKETS, "SNMP received agentx-TestSet-PDU");
byte *pkt = pkt_start; /* pointer to agentx-TestSet-PDU in RX-buffer */
struct agentx_response *res; /* pointer to reponse in TX-buffer */
struct agentx_header *h = (void *) pkt;
- ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
- uint pkt_size = LOAD_U32(h->payload);
-
- if (pkt_size < size)
- return 0;
+ pkt += AGENTX_HEADER_SIZE;
+ //uint pkt_size = LOAD_U32(h->payload);
sock *sk = p->sock;
struct snmp_pdu c;
- snmp_pdu_context(p, &c, sk);
+ snmp_pdu_context(&c, sk);
if (c.size < AGENTX_HEADER_SIZE)
snmp_manage_tbuf(p, &c);
vb = (void *) pkt;
sz = snmp_varbind_size(vb, size);
- if (sz > size)
- /* wait for more data to arive */
- return 0;
-
if (sz > pkt_size)
{
c.error = AGENTX_RES_PARSE_ERROR;
}
mb_free(tr);
#endif
- s = update_packet_size(p, h, c.buffer);
+ s = update_packet_size(h, c.buffer);
if (c.error != AGENTX_RES_NO_ERROR)
{
* parse_sets_pdu - common functionality for commit set and undo set PDUs
* @p: SNMP protocol instance
* @pkt_start: pointer to first byte of on of set related PDU
- * @size: number of bytes received from a socket
* @error: error status to use
*
* Return number of bytes parsed from RX-buffer.
*/
static uint
-parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, enum agentx_response_errs err)
+parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, enum agentx_response_errs err)
{
byte *pkt = pkt_start;
struct agentx_header *h = (void *) pkt;
- ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
+ pkt += AGENTX_HEADER_SIZE;
uint pkt_size = LOAD_U32(h->payload);
if (pkt_size != 0)
{
TRACE(D_PACKETS, "SNMP received malformed set PDU (size)");
snmp_simple_response(p, AGENTX_RES_PARSE_ERROR, 0);
- // TODO: best solution for possibly malicious pkt_size
- return MIN(size, pkt_size + AGENTX_HEADER_SIZE);
+ // TODO best solution for possibly malicious pkt_size
+ return AGENTX_HEADER_SIZE;
// use varbind_list_size()??
}
struct snmp_pdu c;
- snmp_pdu_context(p, &c, p->sock);
+ snmp_pdu_context(&c, p->sock);
if (c.size < sizeof(struct agentx_response))
snmp_manage_tbuf(p, &c);
struct agentx_response *r = prepare_response(p, &c);
- if (size < pkt_size)
- {
- c.error = AGENTX_RES_PARSE_ERROR;
- }
- else
- {
- // TODO: free resource allocated by parse_test_set_pdu()
- // TODO: do something meaningful
- //mb_free(tr);
- c.error = err;
- }
+ // TODO free resource allocated by parse_test_set_pdu()
+ // TODO do something meaningful
+ //mb_free(tr);
+ c.error = err;
TRACE(D_PACKETS, "SNMP received set PDU with error %u", c.error);
response_err_ind(p, r, c.error, 0);
* parse_commit_set_pdu - parse an agentx-CommitSet-PDU
* @p: SNMP protocol instance
* @pkt: pointer to first byte of PDU inside RX-buffer
- * @size: number of bytes received from a socket
*
* Return number of bytes parsed from RX-buffer.
*/
-static uint
-parse_commit_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
+static inline uint
+parse_commit_set_pdu(struct snmp_proto *p, byte *pkt)
{
// don't forget to free resoures allocated by parse_test_set_pdu()
//mb_free(tr);
TRACE(D_PACKETS, "SNMP received agentx-CommitSet-PDU");
- return parse_sets_pdu(p, pkt, size, AGENTX_RES_COMMIT_FAILED);
+ return parse_sets_pdu(p, pkt, AGENTX_RES_COMMIT_FAILED);
}
/*
* parse_undo_set_pdu - parse an agentx-UndoSet-PDU
* @p: SNMP protocol instance
* @pkt: pointer to first byte of PDU inside RX-buffer
- * @size: number of bytes received from a socket
*
* Return number of bytes parsed from buffer.
*/
-static uint
-parse_undo_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
+static inline uint
+parse_undo_set_pdu(struct snmp_proto *p, byte *pkt)
{
// don't forget to free resources allocated by parse_test_set_pdu()
//mb_free(tr);
TRACE(D_PACKETS, "SNMP received agentx-UndoSet-PDU");
- return parse_sets_pdu(p, pkt, size, AGENTX_RES_UNDO_FAILED);
+ return parse_sets_pdu(p, pkt, AGENTX_RES_UNDO_FAILED);
}
/*
* parse_cleanup_set_pdu - parse an agentx-CleanupSet-PDU
* @p: SNMP protocol instance
* @pkt_start: pointer to first byte of PDU inside RX-buffer
- * @size: number of bytes received from a socket
*
* Return number of bytes parsed from RX-buffer.
*/
static uint
-parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
+parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start)
{
TRACE(D_PACKETS, "SNMP received agentx-CleanupSet-PDU");
(void)p;
- //TODO:
- // don't forget to free resources allocated by parse_test_set_pdu()
+ // TODO don't forget to free resources allocated by parse_test_set_pdu()
//mb_free(p->tr);
byte *pkt = pkt_start;
if (pkt_size != 0)
{
// TODO should we free even for malformed packets ??
- return MIN(size, pkt_size + AGENTX_HEADER_SIZE);
+ return AGENTX_HEADER_SIZE;
}
/* No agentx-Response-PDU is sent in response to agentx-CleanupSet-PDU */
* @p: SNMP protocol instance
* @pkt: first byte of PDU inside RX-buffer
* @size: number of bytes received from a socket
- * @skip: length of header that stays still in partial processing
*
* Return number of bytes parsed from RX-buffer.
*/
static uint
-parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip)
+parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
{
/* TX-buffer free space */
ASSERT(snmp_is_active(p));
struct agentx_header *h = (void *) pkt;
uint pkt_size = LOAD_U32(h->payload);
+ /* RX side checks - too big packet */
if (pkt_size > SNMP_PKT_SIZE_MAX)
- return simple_response(p, AGENTX_RES_GEN_ERR, 0);
+ {
+ snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
+ snmp_reset(p);
+ return 0; // TODO return size??
+ }
+
+ /* This guarantees that we have the full packet already received */
+ if (size < pkt_size + AGENTX_HEADER_SIZE)
+ return 0; /* no bytes parsed */
/* We need to see the responses for PDU such as
* agentx-Open-PDU, agentx-Register-PDU, ...
* even when we are outside the SNMP_CONNECTED state
*/
if (h->type == AGENTX_RESPONSE_PDU)
- return parse_response(p, pkt, size);
+ return parse_response(p, pkt);
ASSERT(snmp_is_active(p));
if (p->state != SNMP_CONN ||
p->session_id != LOAD_U32(h->session_id))
{
- // TODO: resolve issues connected to partial processed packets
struct agentx_header copy = {
.session_id = p->session_id,
.transaction_id = p->transaction_id,
* After unexpected state, we simply reset the session
* only sending the agentx-Response-PDU.
*/
- snmp_set_state(p, SNMP_RESET);
- return 0;
+ snmp_reset(p);
+ return 0; // return size??
}
ASSERT(snmp_is_active(p));
if (h->flags & AGENTX_NON_DEFAULT_CONTEXT)
{
- // TODO: add non-default context support
+ // TODO add non-default context support
TRACE(D_PACKETS, "SNMP received PDU with unexpected byte order");
snmp_simple_response(p, AGENTX_RES_UNSUPPORTED_CONTEXT, 0);
/* We always accept the packet length as correct, up to set limit */
case AGENTX_GET_PDU:
case AGENTX_GET_NEXT_PDU:
case AGENTX_GET_BULK_PDU:
- return parse_gets2_pdu(p, pkt, size, skip);
+ return parse_gets_pdu(p, pkt);
case AGENTX_CLOSE_PDU:
- return parse_close_pdu(p, pkt, size);
+ return parse_close_pdu(p, pkt);
case AGENTX_TEST_SET_PDU:
- return parse_test_set_pdu(p, pkt, size);
+ return parse_test_set_pdu(p, pkt);
case AGENTX_COMMIT_SET_PDU:
- return parse_commit_set_pdu(p, pkt, size);
+ return parse_commit_set_pdu(p, pkt);
case AGENTX_UNDO_SET_PDU:
- return parse_undo_set_pdu(p, pkt, size);
+ return parse_undo_set_pdu(p, pkt);
case AGENTX_CLEANUP_SET_PDU:
- return parse_cleanup_set_pdu(p, pkt, size);
+ return parse_cleanup_set_pdu(p, pkt);
default:
/* We reset the connection for malformed packet (Unknown packet type) */
* parse_response - parse an agentx-Response-PDU
* @p: SNMP protocol instance
* @res: pointer of agentx-Response-PDU header in RX-buffer
- * @size: number of bytes received from a socket
*
* Return number of bytes parsed from RX-buffer.
*/
static uint
-parse_response(struct snmp_proto *p, byte *res, uint size)
+parse_response(struct snmp_proto *p, byte *res)
{
- log(L_WARN "parse response");
- if (size < sizeof(struct agentx_response))
- return 0;
-
struct agentx_response *r = (void *) res;
struct agentx_header *h = (void *) r;
// todo reject not compiled byte order
uint pkt_size = LOAD_U32(h->payload);
- if (size < pkt_size + AGENTX_HEADER_SIZE)
- return 0;
switch (r->error)
{
case AGENTX_RES_NO_ERROR:
TRACE(D_PACKETS, "SNMP received agetnx-Response-PDU");
- do_response(p, res, size);
+ do_response(p, res);
break;
/* Registration errors */
case AGENTX_RES_DUPLICATE_REGISTER:
case AGENTX_RES_REQUEST_DENIED:
case AGENTX_RES_UNKNOWN_REGISTER:
- // TODO: more direct path to mib-specifiec code
+ // TODO more direct path to mib-specific code
TRACE(D_PACKETS, "SNMP received agentx-Response-PDU with error %u", r->error);
- snmp_register_ack(p, r, size);
+ byte *pkt = res + sizeof(struct agentx_response);
+ struct oid *failed = (void *) pkt;
+ snmp_register_ack(p, r, snmp_get_mib_class(failed));
break;
/*
/*
* do_response - act on agentx-Response-PDU and protocol state
* @p: SNMP protocol instance
- * @buf: RX-buffer with PDU bytes
- * @size: number of bytes received from a socket
+ * @pkt: RX-buffer with PDU bytes
*
* Return number of bytes parsed from RX-buffer.
*/
static void
-do_response(struct snmp_proto *p, byte *buf, uint size)
+do_response(struct snmp_proto *p, byte *pkt)
{
- struct agentx_response *r = (void *) buf;
+ struct agentx_response *r = (void *) pkt;
struct agentx_header *h = (void *) r;
/* TODO make it asynchronous for better speed */
break;
case SNMP_REGISTER:;
- byte *pkt = buf;
- ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
+ pkt += AGENTX_HEADER_SIZE;
const struct oid *oid = (void *) pkt;
/*
* update_packet_size - set PDU size
- * @p - SNMP protocol instance
* @start - pointer to PDU data start (excluding header size)
* @end - pointer after the last PDU byte
*
* Return number of bytes in TX-buffer (including header size).
*/
static inline uint
-update_packet_size(struct snmp_proto *p, struct agentx_header *start, byte *end)
+update_packet_size(struct agentx_header *start, byte *end)
{
uint s = snmp_pkt_len((byte *) start, end);
STORE_U32(start->payload, s);
STORE_U32(res->index, 0);
}
+static uint
+parse_gets_error(struct snmp_proto *p, struct snmp_pdu *c, uint len)
+{
+ TRACE(D_PACKETS, "SNMP error %u while parsing gets PDU", c->error);
+ if (c->index > UINT16_MAX)
+ snmp_simple_response(p, AGENTX_RES_GEN_ERROR, UINT16_MAX);
+ else
+ snmp_simple_response(p, AGENTX_RES_GEN_ERROR, c->index);
+
+ return len + AGENTX_HEADER_SIZE;
+}
/*
* parse_gets_pdu - parse received gets PDUs
* @p: SNMP protocol instance
* @pkt_start: pointer to first byte of received PDU
- * @size: number of bytes received from a socket
- * @skip: length of header that stays still in partial processing
*
* Gets PDUs are agentx-Get-PDU, agentx-GetNext-PDU, agentx-GetBulk-PDU.
*
* Return number of bytes parsed from RX-buffer
*/
static uint
-parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *skip)
+parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
{
// TODO checks for c.size underflow
- uint ret = 0;
struct oid *o_start = NULL, *o_end = NULL;
byte *pkt = pkt_start;
struct agentx_header *h = (void *) pkt;
- ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
+ pkt += AGENTX_HEADER_SIZE;
uint pkt_size = LOAD_U32(h->payload);
sock *sk = p->sock;
struct snmp_pdu c;
- snmp_pdu_context(p, &c, sk);
+ snmp_pdu_context(&c, sk);
/*
* Get-Bulk processing stops if all the varbind have type END_OF_MIB_VIEW
struct agentx_bulk_state bulk_state = { };
if (h->type == AGENTX_GET_BULK_PDU)
{
- if (size < sizeof(struct agentx_getbulk))
- goto wait;
-
if (pkt_size < sizeof(struct agentx_getbulk))
{
c.error = AGENTX_RES_PARSE_ERROR;
c.index = 0;
- ret = pkt_size + AGENTX_HEADER_SIZE;
- goto error;
+ return parse_gets_error(p, &c, pkt_size);
}
struct agentx_getbulk *bulk_info = (void *) pkt;
struct agentx_response *response_header = prepare_response(p, &c);
- while (c.error == AGENTX_RES_NO_ERROR && size > 0 && pkt_size > 0)
+ while (c.error == AGENTX_RES_NO_ERROR && pkt_size > 0)
{
- if (size < snmp_oid_sizeof(0))
- goto partial;
-
/* We load search range start OID */
const struct oid *o_start_b = (void *) pkt;
uint sz;
if ((sz = snmp_oid_size(o_start_b)) > pkt_size)
{
c.error = AGENTX_RES_PARSE_ERROR;
- ret = MIN(size, pkt_size + AGENTX_HEADER_SIZE);
- goto error;
- }
-
- /*
- * If we already have written same relevant data to the TX buffer, then
- * we send processed part, otherwise we don't have anything to send and
- * need to wait for more data to be received.
- */
- if (sz > size && c.index > 0)
- {
- goto partial;
- }
- else if (sz > size)
- {
- goto wait;
+ return parse_gets_error(p, &c, pkt_size);
}
/* Update buffer pointer and remaining size counters. */
ADVANCE(pkt, pkt_size, sz);
- size -= sz;
/*
* We load search range end OID
if ((sz = snmp_oid_size(o_end_b)) > pkt_size)
{
c.error = AGENTX_RES_PARSE_ERROR;
- ret = MIN(size, pkt_size + AGENTX_HEADER_SIZE);
- goto error;
- }
-
- if (sz > size && c.index > 0)
- {
- size += snmp_oid_size(o_start_b);
- goto partial;
- }
- else if (sz > size)
- {
- goto wait;
+ return parse_gets_error(p, &c, pkt_size);
}
ADVANCE(pkt, pkt_size, sz);
- size -= sz;
- // TODO check for oversized OIDs before any allocation (in prefixize())
+ /* We don't too to check for oversided OID because the PDU has 8k size limit */
/* We create copy of OIDs outside of rx-buffer and also prefixize them */
o_start = snmp_prefixize(p, o_start_b);
if (!snmp_is_oid_empty(o_end) && snmp_oid_compare(o_start, o_end) > 0)
{
c.error = AGENTX_RES_GEN_ERROR;
- ret = MIN(size, pkt_size + AGENTX_HEADER_SIZE);
- goto error;
+ mb_free(o_start);
+ mb_free(o_end);
+ return parse_gets_error(p, &c, pkt_size);
}
- /* TODO find mib_class, check if type is GET of GET_NEXT, act acordingly */
+ /* TODO find mib_class, check if type is GET of GET_NEXT, act accordingly */
switch (h->type)
{
case AGENTX_GET_PDU:
}
}
- /* send the constructed packet */
- struct agentx_response *res;
- if (snmp_is_partial(p))
- {
- snmp_log("snmp_is_partial() <pkt> packet_id %u last_pkt_id %u [proto packet_id] %u", LOAD_U32(res->h.packet_id), p->last_pkt_id, p->packet_id);
- res = SKIP_BACK(struct agentx_response, h, snmp_get_header(p));
- ASSERT(LOAD_U32(res->h.packet_id) == p->last_pkt_id);
- STORE_U32(res->h.packet_id, p->last_pkt_id);
- snmp_unset_header(p);
- }
- else
- res = response_header;
-
/* We update the error, index pair on the beginning of the packet. */
- response_err_ind(p, res, c.error, c.index + 1);
- uint s = update_packet_size(p, &res->h, c.buffer);
+ response_err_ind(p, response_header, c.error, c.index + 1);
+ uint s = update_packet_size(&response_header->h, c.buffer);
/* We send the message in TX-buffer. */
- snmp_unset_header(p);
sk_send(sk, s);
// TODO think through the error state
/* number of bytes parsed from RX-buffer */
- ret = pkt - pkt_start;
- goto free;
-
-partial:
- /* need to tweak RX buffer packet size */
- //STORE_U32(h->payload, pkt_size);
- *skip = AGENTX_HEADER_SIZE;
- snmp_set_header(p, &response_header->h, &c);
-
- /* number of bytes parsed from RX-buffer */
- ret = pkt - pkt_start;
- /* update the packet length such that the used bytes are not included */
- STORE_U32(h->payload, LOAD_U32(h->payload) - ret + AGENTX_HEADER_SIZE);
- goto free;
-
-wait:
- p->packet_id--; /* we did not use the packetID */
- log(L_INFO "decrementing back the packet_id to %u", p->packet_id);
- ret = 0;
- goto free;
-
-error:
- TRACE(D_PACKETS, "SNMP error %u while parsing gets PDU", c.error);
- if (c.index > UINT16_MAX)
- snmp_simple_response(p, AGENTX_RES_GEN_ERROR, UINT16_MAX);
- else
- snmp_simple_response(p, c.error, c.index);
-
-free:
mb_free(o_start);
mb_free(o_end);
- return ret;
+ return pkt - pkt_start;
}
/*
snmp_stop_subagent(struct snmp_proto *p)
{
tm_stop(p->ping_timer);
- close_pdu(p, AGENTX_CLOSE_SHUTDOWN);
+ /* This cause problems with net-snmp daemon witch halts afterwards */
+ //close_pdu(p, AGENTX_CLOSE_SHUTDOWN);
}
/*
byte *pkt_start = sk->rbuf;
byte *end = pkt_start + size;
- byte *last_pkt = pkt_start;
-
- /*
- * In some cases we want to save the header for future parsing, skip is number
- * of bytes that should not be overriden by memmove()
- */
- uint skip = 0;
-
- while (snmp_is_active(p) && end >= pkt_start + AGENTX_HEADER_SIZE && skip == 0)
+ while (snmp_is_active(p) && end >= pkt_start + AGENTX_HEADER_SIZE)
{
- uint parsed_len = parse_pkt(p, pkt_start, size, &skip);
+ uint parsed_len = parse_pkt(p, pkt_start, size);
if (parsed_len == 0)
break;
- last_pkt = pkt_start;
pkt_start += parsed_len;
size -= parsed_len;
}
- if (!snmp_is_active(p))
- return 1;
-
- if (skip != 0 || pkt_start != end)
- {
- memmove(sk->rbuf, last_pkt, skip); /* maybe no op */
- memmove(sk->rbuf + skip, pkt_start, size);
- sk->rpos = sk->rbuf + size + skip;
- return 0;
- }
+ /* We flush the RX-buffer on errors */
+ if (!snmp_is_active(p) || pkt_start == end)
+ return 1; /* The whole RX-buffer was consumed */
- return 1;
+ /* Incomplete packet parsing */
+ memmove(sk->rbuf, pkt_start, size);
+ sk->rpos = sk->rbuf + size;
+ return 0;
}
/*
sock *sk = p->sock;
struct snmp_pdu c;
- snmp_pdu_context(p, &c, sk);
+ snmp_pdu_context(&c, sk);
if (c.size < AGENTX_HEADER_SIZE)
return;
int unused = sk->tbuf + sk->tbsize - c.buffer;
- if (snmp_is_partial(p) && unused >= AGENTX_HEADER_SIZE)
- {
- /* We use the start of unsent TX-buffer to fit in the agentx-Ping-PDU */
- memmove(sk->tpos + AGENTX_HEADER_SIZE, sk->tpos, p->last_size);
- p->header_offset += AGENTX_HEADER_SIZE;
- }
- else if (snmp_is_partial(p))
- /* Not enough space inside the buffer */
+ if (unused < AGENTX_HEADER_SIZE)
return;
- /* we do not use the snmp_create_tx_header() because of side effects */
- struct agentx_header *h = (void *) sk->tpos;
+ //struct agentx_header *h = (void *) sk->tpos;
+ struct agentx_header *h = (void *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
snmp_blank_header(h, AGENTX_PING_PDU);
p->packet_id++;
log(L_INFO "incrementing packet_id to %u (ping)", p->packet_id);
snmp_session(p, h);
-
- if (snmp_is_partial(p)) // TODO remove me
- snmp_log("snmp_ping() <pkt> packet_id %u last_pkt_id %u [proto packet_id] ))%u", LOAD_U32(h->packet), p->last_pkt_id, p->packet_id);
/* sending only header */
- uint s = update_packet_size(p, h, (byte *) h + AGENTX_HEADER_SIZE);
+ uint s = update_packet_size(h, (byte *) h + AGENTX_HEADER_SIZE);
sk_send(sk, s);
}
switch (o_curr->ids[1])
{
case SNMP_BGP4_MIB:
- r = snmp_bgp_search2(p, &o_curr, o_end, 0);
+ r = snmp_bgp_search(p, &o_curr, o_end, 0);
if (r == SNMP_SEARCH_OK)
{
static struct agentx_response *
prepare_response(struct snmp_proto *p, struct snmp_pdu *c)
{
- if (snmp_is_partial(p))
- return (struct agentx_response *) snmp_get_header(p);
-
struct agentx_response *r = (void *) c->buffer;
- struct agentx_header *h = snmp_create_tx_header(p, (byte *) r);
+ struct agentx_header *h = &r->h;
snmp_blank_header(h, AGENTX_RESPONSE_PDU);
snmp_session(p, h);
u8 version;
u8 type;
u8 flags;
- u8 pad;
+ u8 reserved; /* always zero filled */
u32 session_id; /* AgentX sessionID established by Open-PDU */
u32 transaction_id; /* last transactionID seen/used */
u32 packet_id; /* last packetID seen/used */
u8 n_subid;
u8 prefix;
u8 include;
- u8 pad;
+ u8 reserved; /* always zero filled */
u32 ids[];
};
struct agentx_varbind {
u16 type;
- u16 pad;
+ u16 reserved; /* always zero filled */
/* oid part */
struct oid name;
/* AgentX variable binding data optionaly here */
struct agentx_close_pdu {
struct agentx_header h;
u8 reason;
- u8 pad1;
- u16 pad2;
+ u8 reserved1; /* reserved u24 */
+ u16 reserved2; /* whole u24 is always zero filled */
};
struct agentx_un_register_hdr {
u8 timeout;
u8 priority;
u8 range_subid;
- u8 pad;
+ u8 reserved; /* always zero filled */
};
struct agentx_bulk_state {