proto_notify_state(&p->p, PS_DOWN);
}
+/* this function is internal and shouldn't be used outside the snmp module */
+void
+snmp_connected(sock *sk)
+{
+ struct snmp_proto *p = sk->data;
+ snmp_log("snmp_connected() connection created");
+
+ p->state = SNMP_OPEN;
+
+ sk->rx_hook = snmp_rx;
+ sk->tx_hook = NULL;
+ //sk->tx_hook = snmp_tx;
+
+ snmp_start_subagent(p);
+
+ // TODO ping interval <move to do_response()>
+ tm_set(p->ping_timer, current_time() + p->timeout S);
+}
+
+/* this function is internal and shouldn't be used outside the snmp module */
+void
+snmp_reconnect(timer *tm)
+{
+ struct snmp_proto *p = tm->data;
+ ASSUME(p->sock);
+ snmp_connected(p->sock);
+}
+
static void
snmp_sock_err(sock *sk, int err)
{
snmp_log("changing proto_snmp state to LOCKED");
p->state = SNMP_LOCKED;
- // TODO ping interval
- tm_start(p->startup_timer, 4 S);
+ p->startup_timer->hook = snmp_startup_timeout;
+ tm_start(p->startup_timer, 4 S); // TODO make me configurable
}
-static void
-snmp_connected(sock *sk)
-{
- struct snmp_proto *p = sk->data;
- snmp_log("snmp_connected() connection created");
-
- p->state = SNMP_OPEN;
-
- sk->rx_hook = snmp_rx;
- sk->tx_hook = NULL;
- //sk->tx_hook = snmp_tx;
-
- snmp_start_subagent(p);
-
- // TODO ping interval <move to do_response()>
- tm_set(p->ping_timer, p->timeout S);
-}
static void
snmp_start_locked(struct object_lock *lock)
struct snmp_proto *p = lock->data;
p->state = SNMP_LOCKED;
+ sock *s = p->sock;
- sock *s = sk_new(p->p.pool);
- s->type = SK_TCP_ACTIVE;
- s->saddr = p->local_ip;
- s->daddr = p->remote_ip;
- s->dport = p->remote_port;
- s->rbsize = SNMP_RX_BUFFER_SIZE;
- s->tbsize = SNMP_TX_BUFFER_SIZE;
-
- //s->tos = IP_PREC_INTERNET_CONTROL
- //s->rx_hook = snmp_connected;
- s->tx_hook = snmp_connected;
- s->err_hook = snmp_sock_err;
-
- p->sock = s;
- s->data = p;
-
- p->to_send = 0;
- p->errs = 0;
+ if (!s)
+ {
+ s = sk_new(p->p.pool);
+ s->type = SK_TCP_ACTIVE;
+ s->saddr = p->local_ip;
+ s->daddr = p->remote_ip;
+ s->dport = p->remote_port;
+ s->rbsize = SNMP_RX_BUFFER_SIZE;
+ s->tbsize = SNMP_TX_BUFFER_SIZE;
+
+ //s->tos = IP_PREC_INTERNET_CONTROL
+ s->tx_hook = snmp_connected;
+ s->err_hook = snmp_sock_err;
+
+ p->sock = s;
+ s->data = p;
+
+ p->to_send = 0;
+ p->errs = 0;
+ }
if (sk_open(s) < 0)
{
}
}
-static void
+/* this function is internal and shouldn't be used outside the snmp module */
+void
snmp_startup(struct snmp_proto *p)
{
if (p->state != SNMP_INIT &&
*/
}
-static void
+/* this function is internal and shouldn't be used outside the snmp module */
+void
snmp_startup_timeout(timer *t)
{
snmp_log("startup timer triggered");
}
static void
-snmp_ping_timeout(struct timer *tm)
+snmp_ping_timeout(timer *tm)
{
struct snmp_proto *p = tm->data;
}
}
- {
- u32 *ptr = mb_alloc(p->p.pool, 4 * sizeof(u32));
- *ptr = 1;
- ptr[2] = 4;
- (void)ptr[1]; (void)ptr[0]; (void)ptr[2];
- mb_free(ptr);
- log(L_INFO "testing alloc 3");
- }
-
snmp_log("values of context cf %u proto %u", cf->contexts, p->context_max);
ASSUME(cf->contexts == p->context_max);
p->startup_timer->hook = snmp_stop_timeout;
- tm_set(p->startup_timer, p->timeout S);
+ tm_set(p->startup_timer, current_time() + p->timeout S);
snmp_stop_subagent(p);
* @pkt: first byte past packet end
*/
uint
-snmp_pkt_len(byte *start, byte *end)
+snmp_pkt_len(const byte *start, const byte *end)
{
snmp_log("snmp_pkt_len start 0x%p end 0x%p res %u", start, end, (end - start)
- AGENTX_HEADER_SIZE);
*
* used for copying oid to in buffer oid @dest
*/
-void snmp_oid_copy(struct oid *dest, const struct oid *src)
+void
+snmp_oid_copy(struct oid *dest, const struct oid *src)
{
STORE_U8(dest->n_subid, src->n_subid);
STORE_U8(dest->prefix, src->prefix);
return hdr_size + snmp_str_size_from_len(LOAD_PTR(data, byte_ord));
}
+/* test if the varbind has valid type */
+int
+snmp_test_varbind(const struct agentx_varbind *vb)
+{
+ if (vb->type == AGENTX_INTEGER ||
+ vb->type == AGENTX_OCTET_STRING ||
+ vb->type == AGENTX_NULL ||
+ vb->type == AGENTX_OBJECT_ID ||
+ vb->type == AGENTX_IP_ADDRESS ||
+ vb->type == AGENTX_COUNTER_32 ||
+ vb->type == AGENTX_GAUGE_32 ||
+ vb->type == AGENTX_TIME_TICKS ||
+ vb->type == AGENTX_OPAQUE ||
+ vb->type == AGENTX_COUNTER_64 ||
+ vb->type == AGENTX_NO_SUCH_OBJECT ||
+ vb->type == AGENTX_NO_SUCH_INSTANCE ||
+ vb->type == AGENTX_END_OF_MIB_VIEW)
+ return 1;
+ else
+ return 0;
+}
+
/*
inline uint
snmp_context_size(struct agentx_context *c)
STORE_U32(o->ids[start + 3], temp & 0xFF);
}
-void snmp_oid_dump(struct oid *oid)
+void snmp_oid_dump(const struct oid *oid)
{
log(L_WARN "OID DUMP ========");
static uint parse_close_pdu(struct snmp_proto *p, byte *buf, uint size);
static struct agentx_response *prepare_response(struct snmp_proto *p, struct snmp_pdu *c);
static void response_err_ind(struct agentx_response *res, uint err, uint ind);
-static uint update_packet_size(struct snmp_proto *p, byte *start, byte *end);
+static uint update_packet_size(struct snmp_proto *p, const byte *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 };
}
#if 0
-static void UNUSED
-parse_testset_pdu(struct snmp_proto *p)
-{
- sock *sk = p->sock;
- sk_send(sk, 0);
-}
-
-static void UNUSED
-parse_commitset_pdu(struct snmp_proto *p)
-{
- sock *sk = p->sock;
- sk_send(sk, 0);
-}
-
-static void UNUSED
-parse_undoset_pdu(struct snmp_proto *p)
-{
- sock *sk = p->sock;
- sk_send(sk, 0);
-}
-
-static void UNUSED
-parse_cleanupset_pdu(struct snmp_proto *p)
-{
- sock *sk = p->sock;
- sk_send(sk, 0);
-}
-
static void UNUSED
addagentcaps_pdu(struct snmp_proto *p, struct oid *cap, char *descr,
uint descr_len, struct agentx_context *c)
}
}
-static void
+/* return 0 if the created varbind type is END_OF_MIB_VIEW, 1 otherwise */
+static int
snmp_get_next2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end,
struct snmp_pdu *c)
{
{
/* TODO create NULL varbind */
c->error = AGENTX_RES_GEN_ERROR;
- return;
+ return 0;
}
vb = snmp_create_varbind(c->buffer, o_start);
vb->type = AGENTX_END_OF_MIB_VIEW;
ADVANCE(c->buffer, c->size, snmp_varbind_header_size(vb));
- return;
+ return 0;
case SNMP_SEARCH_OK:
default:
case AGENTX_NO_SUCH_INSTANCE:
case AGENTX_END_OF_MIB_VIEW:
vb->type = AGENTX_END_OF_MIB_VIEW;
- break;
+ return 0;
- default: /* intentionally left blank */
- break;
+ default:
+ return 1;
}
-
- return;
}
if (c->size < snmp_varbind_hdr_size_from_oid(o_start))
vb = snmp_create_varbind(c->buffer, o_start);
vb->type = AGENTX_END_OF_MIB_VIEW;
ADVANCE(c->buffer, c->size, snmp_varbind_header_size(vb));
+ return 0;
}
-static void
+/* returns 0 if the created varbind has type EndOfMibView, 1 otherwise */
+static int
snmp_get_bulk2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end,
struct agentx_bulk_state *state, struct snmp_pdu *c)
{
- if (state->index <= state->getbulk.non_repeaters)
- {
- return snmp_get_next2(p, o_start, o_end, c);
- /*
- * Here we don't need to do any overriding, not even in case no object was
- * found, as the GetNext-PDU override is same as GetBulk-PDU override
- * (to AGENTX_RES_END_OF_MIB_VIEW)
- */
- }
-
struct oid *o_curr = NULL;
struct oid *o_predecessor = NULL;
enum snmp_search_res r;
o_predecessor = o_curr;
o_curr = search_mib(p, o_start, o_end, o_curr, c, &r);
i++;
- } while (o_curr && i <= state->repetition);
-
+ } while (o_curr && i < state->repetition);
+
+ // TODO check if the approach below works
+ // it need to generate varbinds that will be only of type EndOfMibView
/* Object Identifier fall-backs */
if (!o_curr)
o_curr = o_predecessor;
if (c->size < sz)
{
c->error = AGENTX_RES_GEN_ERROR;
- return;
+ return 0;
}
/* we need the varbind handle to be able to override it's type */
case AGENTX_NO_SUCH_INSTANCE:
case AGENTX_END_OF_MIB_VIEW:
vb->type = AGENTX_END_OF_MIB_VIEW;
- break;
-
- default: /* intentionally left blank */
- break;
- }
-}
-
-static uint UNUSED
-parse_close_pdu(struct snmp_proto UNUSED *p, byte UNUSED *req, uint UNUSED size)
-{
- /*
- snmp_log("parse_close_pdu()");
-
- // byte *pkt = req;
- // sock *sk = p->sock;
+ return 0;
- if (size < sizeof(struct agentx_header))
- {
- snmp_log("p_close early return");
- return 0;
+ default:
+ return 1;
}
-
- // struct agentx_header *h = (void *) req;
- ADVANCE(req, size, AGENTX_HEADER_SIZE);
- //snmp_log("after header %p", req);
-
- p->state = SNMP_ERR;
-
- proto_notify_state(&p->p, PS_DOWN);
- */
- return 0;
}
static inline uint
-update_packet_size(struct snmp_proto *p, byte *start, byte *end)
+update_packet_size(struct snmp_proto *p, const byte *start, byte *end)
{
/* work even for partial messages */
struct agentx_header *h = (void *) p->sock->tpos;
c.context = ...
*/
+ /*
+ * Get-Bulk processing stops if all the varbind have type END_OF_MIB_VIEW
+ * has_any is true if some varbind has type other than END_OF_MIB_VIEW
+ */
+ int has_any = 0;
struct agentx_bulk_state bulk_state = { };
if (h->type == AGENTX_GET_BULK_PDU)
{
.non_repeaters = LOAD_U32(bulk_info->non_repeaters, c.byte_ord),
.max_repetitions = LOAD_U32(bulk_info->max_repetitions, c.byte_ord),
},
- .index = 1,
- .repetition = 1,
+ /* In contrast to the RFC, we use 0-based indices. */
+ .index = 0,
+ .repetition = 0,
};
}
if (!p->partial_response && c.size < sizeof(struct agentx_response))
{
snmp_manage_tbuf(p, &c);
+ // TODO renew pkt, pkt_start pointers context clen
}
struct agentx_response *response_header = prepare_response(p, &c);
- uint ind = 1;
+ uint ind = 0;
while (c.error == AGENTX_RES_NO_ERROR && size > 0 && pkt_size > 0)
{
- snmp_log("iter %u size %u remaining %u/%u", ind, c.buffer - sk->tpos, size, pkt_size);
+ snmp_log("iter %u size %u remaining %u/%u", ind + 1, c.buffer - sk->tpos, size, pkt_size);
if (size < snmp_oid_sizeof(0))
goto partial;
* we send processed part, otherwise we don't have anything to send and
* need to wait for more data to be recieved.
*/
- if (sz > size && ind > 1)
+ if (sz > size && ind > 0)
{
- snmp_log("sz %u > %u size && ind %u > 1", sz, size, ind);
+ snmp_log("sz %u > %u size && ind %u > 1", sz, size, ind + 1);
goto partial; /* send already processed part */
}
else if (sz > size)
goto send;
}
- if (sz > size && ind > 1)
+ if (sz > size && ind > 0)
{
- snmp_log("sz2 %u > %u size && ind %u > 1", sz, size, ind);
+ snmp_log("sz2 %u > %u size && ind %u > 1", sz, size, ind + 1);
size += snmp_oid_size(o_start_b);
goto partial;
}
break;
case AGENTX_GET_BULK_PDU:
- snmp_get_bulk2(p, o_start, o_end, &bulk_state, &c);
+ if (ind >= bulk_state.getbulk.non_repeaters)
+ bulk_state.repeaters++;
+
+ // store the o_start, o_end
+
+ /* The behavior of GetBulk pdu in the first iteration is
+ * identical to GetNext pdu. */
+ has_any = has_any || snmp_get_next2(p, o_start, o_end, &c);
break;
default:
ind++;
} /* while (c.error == AGENTX_RES_NO_ERROR && size > 0) */
+ if (h->type == AGENTX_GET_BULK_PDU)
+ {
+ for (bulk_state.repetition++;
+ has_any && bulk_state.repetition < bulk_state.getbulk.max_repetitions;
+ bulk_state.repetition++)
+ {
+ // TODO find propper start and end
+ struct oid *start = NULL;
+ struct oid *end = NULL;
+ has_any = 0;
+ for (bulk_state.index = 0; bulk_state.index < bulk_state.repeaters;
+ bulk_state.repeaters++)
+ has_any = has_any || snmp_get_bulk2(p, start, end, &bulk_state, &c);
+ }
+ }
+
send:
snmp_log("gets2: sending response ...");
struct agentx_response *res = (void *) sk->tbuf;
/* We update the error, index pair on the beginning of the packet. */
- response_err_ind(res, c.error, ind);
+ response_err_ind(res, c.error, ind + 1);
uint s = update_packet_size(p, (byte *) response_header, c.buffer);
snmp_log("sending response to Get-PDU, GetNext-PDU or GetBulk-PDU request (size %u)...", s);