/* hash table only store ip4 addresses */
#define SNMP_HASH_LESS(ip1, ip2) SNMP_HASH_LESS4(ip1,ip2)
-// delete me
-#define SNMP_MANAGE_TBUF(...) (void)0
-
#define DECLARE_BGP4(addr, proto, conn, stats, config) \
ip4_addr addr; \
const struct bgp_proto UNUSED *proto; \
static void
snmp_bgp_reg_ok(struct snmp_proto *p, const struct agentx_response *res, struct snmp_registration *reg)
{
+ /* TODO(contexts): add meaningful action */
const struct oid * const oid = reg->oid;
(void)oid;
(void)p;
static void
snmp_bgp_reg_failed(struct snmp_proto *p, const struct agentx_response *res, struct snmp_registration *reg)
{
+ /* TODO(contexts): add meaningful action */
const struct oid * const oid = reg->oid;
(void) res;
(void)oid;
return SNMP_SEARCH_OK;
}
+
+/*
+ *
+ * MIB tree fill hooks
+ *
+ */
+
static enum snmp_search_res
fill_bgp_version(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c)
{
}
/*
- * bgp4_next_peer
+ * bgp4_next_peer - find next BGP peer with IPv4 address
+ * @state: MIB tree walk state
+ * @c: SNMP PDU context data
+ *
+ * Update TX-buffer VarBind name to next peer address.
*/
static int
bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c)
ASSUME(oid->n_subid == 9);
- /* full path BGP4-MIB::bgpPeerEntry.x: .1.3.6.1.2.1.15.3.1.x
- * index offset = ARRAY_SIZE(snmp_internet) + 1 <prefix> + 4 + 1 <identifier x> */
+ /* Stack has one more node for empty prefix (tree root) */
ASSUME(state->stack_pos > 10);
oid->ids[4] = state->stack[10]->empty.id;
struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf);
- /* Create binding to BGP protocols */
+ /* Create binding to BGP protocols */
struct snmp_bond *b;
WALK_LIST(b, cf->bgp_entries)
{
/*
* agentx_get_mib - classify an OID based on MIB prefix
- *
*/
enum agentx_mibs agentx_get_mib(const struct oid *o)
{
+ /* TODO: move me into MIB tree as hooks/MIB module root */
enum agentx_mibs mib = AGENTX_MIB_UNKNOWN;
for (uint i = 0; i < AGENTX_MIB_COUNT + 1; i++)
{
TRACE(D_EVENTS, "SNMP changing state to %u", 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)
- {
- rfree(p->sock);
- p->sock = NULL;
- }
-
p->state = state;
switch (state)
DBG("snmp -> SNMP_STOP\n");
ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
snmp_stop_subagent(p);
+ // FIXME: special treatment for SNMP_OPEN last state?
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);
return PS_STOP;
case SNMP_DOWN:
DBG("snmp -> SNMP_DOWN\n");
+ ASSERT(last == SNMP_STOP || last == SNMP_RESET);
snmp_cleanup(p);
// FIXME: handle the state in which we call proto_notify_state and
// immediately return PS_DOWN from snmp_shutdown()
DBG("snmp -> SNMP_RESET\n");
ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
ASSUME(p->sock);
- snmp_stop_subagent(p);
+ tm_stop(p->ping_timer);
+ // FIXME: special treatment for SNMP_OPEN last state?
p->sock->rx_hook = snmp_rx_skip;
p->sock->tx_hook = snmp_tx_skip;
return PS_STOP;
}
/*
- * snmp_reset - end the communication on AgentX session
- * @p - SNMP protocol instance
+ * snmp_reset - reset AgentX session
+ * @p: SNMP protocol instance
*
- * 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.
+ * We wait until the last PDU written into the socket is send while ignoring all
+ * incomming PDUs. Then we hard reset the connection by socket closure. The
+ * protocol instance is automatically restarted by nest.
*/
void
snmp_reset(struct snmp_proto *p)
{
- tm_stop(p->ping_timer);
- proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
+ proto_notify_state(&p->p, snmp_set_state(p, SNMP_RESET));
+}
+
+
+/*
+ * snmp_stop - close AgentX session
+ * @p: SNMP protocol instance
+ *
+ * We write agentx-Close-PDU into the socket, wait until all written PDUs are
+ * send and then close the socket. The protocol instance is automatically
+ * restarted by nest.
+ */
+void
+snmp_stop(struct snmp_proto *p)
+{
+ proto_notify_state(&p->p, snmp_set_state(p, SNMP_STOP));
}
+
/*
* snmp_sock_err - handle errors on socket by reopenning the socket
* @sk - socket owned by SNMP protocol instance
*/
/**
- *
- *
- *
*
* Handling of malformed packet:
*
}
/*
- * snmp_blank_header - create header with no flags except default
+ * snmp_blank_header - create header with no flags except byte order
* @h: pointer to created header in TX-buffer
* @type: create PDU type
*
if (snmp_tbuf_reserve(&c, sz))
snmp_log("agentx-Notify-PDU small buffer");
- struct agentx_header *h = (void *) c.buffer;
+ struct agentx_header *h = (struct agentx_header *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
snmp_blank_header(h, AGENTX_NOTIFY_PDU);
p->packet_id++; /* New packet id */
STORE_U8(ur->reserved, 0);
ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_hdr));
- snmp_put_oid(c.buffer, oid);
+ (void) snmp_put_oid(c.buffer, oid);
ADVANCE(c.buffer, c.size, snmp_oid_size(oid));
/* place upper-bound if needed */
if (c.error != AGENTX_RES_NO_ERROR)
{
response_err_ind(p, res, c.error, c.index + 1);
- snmp_reset(p); // error
+ snmp_reset(p);
}
else if (all_possible)
{
static uint
parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
{
- snmp_log("parse_pkt %t", current_time());
- /* TX-buffer free space */
if (size < AGENTX_HEADER_SIZE)
return 0;
- struct agentx_header *h = (void *) pkt;
+ struct agentx_header *h = (struct agentx_header *) pkt;
if (h->flags & AGENTX_NETWORK_BYTE_ORDER)
{
TRACE(D_PACKETS, "SNMP received PDU with unexpected byte order");
+ snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
snmp_reset(p);
return 0;
}
- uint pkt_size = LOAD_U32(h->payload);
+ u32 pkt_size = LOAD_U32(h->payload);
/* RX side checks - too big packet */
if (pkt_size > SNMP_PKT_SIZE_MAX)
{
+ TRACE(D_PACKETS, "SNMP received PDU is too long");
snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
snmp_reset(p);
return 0; /* no bytes parsed */
if (size < pkt_size + AGENTX_HEADER_SIZE)
return 0; /* no bytes parsed */
- /* We need to see the responses for PDU such as
+ /*
+ * 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
*/
p->session_id = copy.session_id;
p->transaction_id = copy.transaction_id;
p->packet_id = copy.packet_id;
- snmp_log("restoring packet_id %u from temporal state", p->packet_id);
/*
* After unexpected state, we simply reset the session
{
TRACE(D_PACKETS, "SNMP received PDU with non-default context");
snmp_simple_response(p, AGENTX_RES_UNSUPPORTED_CONTEXT, 0);
- return pkt_size + AGENTX_HEADER_SIZE;
+ snmp_reset(p);
+ return 0;
}
refresh_ids(p, h);
- switch (h->type)
+ switch (LOAD_U8(h->type))
{
case AGENTX_GET_PDU:
case AGENTX_GET_NEXT_PDU:
default:
/* We reset the connection for malformed packet (Unknown packet type) */
- TRACE(D_PACKETS, "SNMP received unknown packet with type %u", h->type);
- snmp_set_state(p, SNMP_RESET);
+ TRACE(D_PACKETS, "SNMP received unknown packet with type %u", LOAD_U8(h->type));
+ snmp_reset(p);
return 0;
}
}
case AGENTX_RES_PARSE_ERROR:
case AGENTX_RES_PROCESSING_ERR:
default:
- DBG("SNMP agentx-Response-PDU with unexpected error %u", r->error);
- snmp_set_state(p, SNMP_DOWN);
+ TRACE(D_PACKETS, "SNMP agentx-Response-PDU with unexepected error %u", r->error);
+ snmp_stop(p);
break;
}
snmp_log("SNMP vb_to_tx small buffer");
ASSERT(c->size >= vb_hdr_size);
- struct agentx_varbind *vb = (void *) c->buffer;
+ struct agentx_varbind *vb = (struct agentx_varbind *) c->buffer;
ADVANCE(c->buffer, c->size, sizeof(struct agentx_varbind) - sizeof(struct oid));
/* Move the c->buffer so that is points at &vb->name */
snmp_set_varbind_type(vb, AGENTX_NULL);
static inline void
response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_response_errs err, u16 ind)
{
- STORE_U32(res->error, (u16) err);
+ STORE_U16(res->error, (u16) err);
// TODO deal with auto-incrementing of snmp_pdu context c.ind
if (err != AGENTX_RES_NO_ERROR && err != AGENTX_RES_GEN_ERROR)
{
TRACE(D_PACKETS, "Last PDU resulted in error %u", err);
- STORE_U32(res->index, ind);
+ STORE_U16(res->index, ind);
TRACE(D_PACKETS, "Storing packet size %u (was %u)", sizeof(struct agentx_response) - AGENTX_HEADER_SIZE, LOAD_U32(res->h.payload));
STORE_U32(res->h.payload,
sizeof(struct agentx_response) - AGENTX_HEADER_SIZE);
else if (err == AGENTX_RES_GEN_ERROR)
{
TRACE(D_PACKETS, "Last PDU resulted in error %u genErr", err);
- STORE_U32(res->index, 0);
+ STORE_U16(res->index, 0);
TRACE(D_PACKETS, "Storing packet size %u (was %u)", sizeof(struct agentx_response) - AGENTX_HEADER_SIZE, LOAD_U32(res->h.payload));
STORE_U32(res->h.payload,
sizeof(struct agentx_response) - AGENTX_HEADER_SIZE);
}
else
- STORE_U32(res->index, 0);
+ STORE_U16(res->index, 0);
}
static inline uint
int
snmp_rx(sock *sk, uint size)
{
- snmp_log("snmp_rx with size %u", size);
- struct snmp_proto *p = sk->data;
+ struct snmp_proto *p = (struct snmp_proto *) sk->data;
byte *pkt_start = sk->rbuf;
byte *end = pkt_start + size;