*
*/
-
static void snmp_mib_fill2(struct snmp_proto *p, struct oid *oid, struct snmp_pdu_context *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 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 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_context *c, enum snmp_search_res *result);
+static void notify_pdu(struct snmp_proto *p, struct oid *oid, void *opaque, uint size, int include_uptime);
static const char * const snmp_errs[] = {
#define SNMP_ERR_SHIFT 256
open_pdu(struct snmp_proto *p, struct oid *oid)
{
sock *sk = p->sock;
+
struct snmp_pdu_context c = {
.buffer = sk->tpos,
.size = sk->tbuf + sk->tbsize - sk->tpos,
const char *str = "bird";
/* +4 for timeout (1B with 4B alignment) */
- if (c.size < AGENTX_HEADER_SIZE + snmp_oid_size(oid) + snmp_str_size(str) + 4)
+ if (c.size < AGENTX_HEADER_SIZE + 4 + snmp_oid_size(oid) + snmp_str_size(str))
{
+ return;
+ // TODO create and add message info into message queue
snmp_manage_tbuf(p, &c);
buf = c.buffer;
}
c.buffer = snmp_put_oid(c.buffer, oid);
c.buffer = snmp_put_str(c.buffer, str);
- snmp_log("send PDU data (open) ...");
uint s = update_packet_size(p, buf, c.buffer);
int ret = sk_send(sk, s);
if (ret > 0)
snmp_log("sk_send error");
}
-#if 0
-static int
-de_allocate_pdu(struct snmp_proto *p, struct oid *oids[], uint len,
- struct agentx_alloc_context *ac, u8 type)
+static void
+notify_pdu(struct snmp_proto *p, struct oid *oid, void *opaque, uint size, int include_uptime)
{
sock *sk = p->sock;
- //byte *buf = sk->tbuf;
- //uint size = sk->tbsize;
- byte *buf = sk->tpos;
- uint size = sk->tbuf + sk->tbsize - sk->tpos;
- uint total_len = 0;
- struct oid *o_curr = NULL;
- for (uint i = 0; i < len; i++)
+ struct snmp_pdu_context c = {
+ .buffer = sk->tpos,
+ .size = sk->tbuf + sk->tbsize - sk->tpos,
+ };
+
+ if (c.size < AGENTX_HEADER_SIZE)
{
- o_curr = oids[i];
- uint sz = snmp_oid_size(o_curr);
- total_len += sz;
+ snmp_manage_tbuf(p, &c);
}
- if (total_len == 0)
- return 0;
+ struct agentx_header *h = (struct agentx_header *) c.buffer;
+ ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
+ SNMP_BLANK_HEADER(h, AGENTX_NOTIFY_PDU);
+ SNMP_SESSION(h, p);
- if (size < AGENTX_HEADER_SIZE + total_len)
- {
- // need bigger tx buffer (more mem)
- return 0;
- }
+ c.byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER;
- int blank = AGENTX_FLAG_BLANK;
- struct agentx_header *h;
- SNMP_CREATE(buf, struct agentx_header, h);
- SNMP_HEADER(h, type,
- (ac->is_instance ? AGENTX_FLAG_INSTANCE_REGISTRATION : blank)
- | (ac->new_index ? AGENTX_FLAG_NEW_INDEX : blank)
- | (ac->any_index ? AGENTX_FLAG_ANY_INDEX : blank));
- ADVANCE(buf, size, AGENTX_HEADER_SIZE);
- STORE(h->payload, total_len);
+#define UPTIME_SIZE \
+ (6 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[4] } )*/
+#define TRAP0_HEADER_SIZE \
+ (7 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[6] } ) */
- for (uint i = 0; i < len; i++)
+ uint sz = AGENTX_HEADER_SIZE + TRAP0_HEADER_SIZE + snmp_oid_size(oid) \
+ + snmp_varbind_hdr_size_from_oid(oid) + size;
+
+ if (include_uptime)
+ sz += UPTIME_SIZE;
+
+ if (c.size < sz)
+ snmp_manage_tbuf(p, &c);
+
+ if (include_uptime)
{
- o_curr = oids[i];
- // TODO fix copy to buffer
- memcpy(buf, o_curr, snmp_oid_size(o_curr));
- ADVANCE(buf, size, snmp_oid_size(o_curr));
+ /* sysUpTime.0 oid */
+ struct oid uptime = {
+ .n_subid = 4,
+ .prefix = 2,
+ .include = 0,
+ .pad = 0,
+ };
+ u32 uptime_ids[] = { 1, 1, 3, 0 };
+
+ struct agentx_varbind *vb = snmp_create_varbind(c.buffer, &uptime);
+ for (uint i = 0; i < uptime.n_subid; i++)
+ STORE_U32(vb->name.ids[i], uptime_ids[i]);
+ ADVANCE(c.buffer, c.size, snmp_varbind_header_size(vb));
+ snmp_varbind_ticks(vb, c.size, current_time() TO_S);
+ ADVANCE(c.buffer, c.size, agentx_type_size(AGENTX_TIME_TICKS));
}
- // increment p->packet_id
- // queue the allocation request
+ /* snmpTrapOID.0 oid */
+ struct oid trap0 = {
+ .n_subid = 6,
+ .prefix = 6,
+ .include = 0,
+ .pad = 0,
+ };
+ u32 trap0_ids[] = { 3, 1, 1, 4, 1, 0 };
+
+ struct agentx_varbind *trap_vb = snmp_create_varbind(c.buffer, &trap0);
+ for (uint i = 0; i < trap0.n_subid; i++)
+ STORE_U32(trap_vb->name.ids[i], trap0_ids[i]);
+ trap_vb->type = AGENTX_OBJECT_ID;
+ snmp_put_oid(SNMP_VB_DATA(trap_vb), oid);
+ ADVANCE(c.buffer, c.size, snmp_varbind_size(trap_vb, c.byte_ord));
- int ret = sk_send(sk, total_len);
- if (ret == 0)
- {
+ // TODO fix the endianess
+ memcpy(c.buffer, opaque, size);
+ ADVANCE(c.buffer, c.size, (size + snmp_varbind_hdr_size_from_oid(oid)));
+
+ uint s = update_packet_size(p, sk->tbuf, c.buffer);
+
+ int ret = sk_send(sk, s);
+ if (ret > 0)
+ snmp_log("sk_send OK!");
+ else if (ret == 0)
snmp_log("sk_send sleep");
- return 1;
- }
- else if (ret < 0)
- {
- snmp_log("sk_send err %d", ret);
- return 1;
- }
else
- {
- snmp_log("sk_send ok !!");
- return 0;
- }
-}
+ snmp_log("sk_send error");
-static int UNUSED
-index_allocate_pdu(struct snmp_proto *p, struct oid *oids[], uint len, struct
-agentx_alloc_context *ac)
-{
- return de_allocate_pdu(p, oids, len, ac, AGENTX_INDEX_ALLOCATE_PDU);
+#undef TRAP0_HEADER_SIZE
+#undef UPTIME_SIZE
}
-static int UNUSED
-index_deallocate_pdu(struct snmp_proto *p, struct oid *oids[], uint len, struct
-agentx_alloc_context *ac)
+/* index allocate / deallocate pdu * /
+static void
+de_allocate_pdu(struct snmp_proto *p, struct oid *oid, u8 type)
{
- return de_allocate_pdu(p, oids, len, ac, AGENTX_INDEX_DEALLOCATE_PDU);
+ sock *sk = p->sock;
+ byte *buf, *pkt;
+ buf = pkt = sk->tbuf;
+ uint size = sk->tbsize;
+
+
+ if (size > AGENTX_HEADER_SIZE + )
+ {
+ snmp_log("de_allocate_pdu()");
+
+ struct agentx_header *h;
+ SNMP_CREATE(pkt, struct agentx_header, h);
+ SNMP_BLANK_HEADER(h, type);
+ SNMP_SESSION(h,p);
+
+ struct agentx_varbind *vb = (struct agentx_varbind *) pkt;
+ STORE_16(vb->type, AGENTX_OBJECT_ID);
+ STORE(vb->oid,
+ }
+
+ else
+ snmp_log("de_allocate_pdu(): insufficient size");
}
-#endif
+*/
-/* Register-PDU / Unregister-PDU common code */
-static inline void
+/* Register-PDU / Unregister-PDU */
+static void
un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 type, u8 is_instance)
{
sock *sk = p->sock;
- //buf = pkt = sk->tbuf;
- //uint size = sk->tbsize;
struct snmp_pdu_context c = {
.buffer = sk->tpos,
.size = sk->tbuf + sk->tbsize - sk->tpos,
};
byte *buf = c.buffer;
- /* conditional +4 for upper-bound */
+ /* conditional +4 for upper-bound (optinal field) */
if (c.size < AGENTX_HEADER_SIZE + snmp_oid_size(oid) + ((len > 1) ? 4 : 0))
{
snmp_log("un_register_pdu() insufficient size");
ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_pdu));
struct agentx_header *h = &ur->h;
+ // FIXME correctly set INSTANCE REGISTRATION bit
SNMP_HEADER(h, type, is_instance ? AGENTX_FLAG_INSTANCE_REGISTRATION : 0);
- /* use new packetID */
+ /* use new transactionID, reset packetID */
p->packet_id++;
SNMP_SESSION(h, p);
/* do not override timeout */
STORE_U32(ur->timeout, 15);
- /* We use default priority */
- STORE_U32(ur->priority, AGENTX_PRIORITY); // TODO configurable priority
+ /* default priority */
+ STORE_U32(ur->priority, AGENTX_PRIORITY);
STORE_U32(ur->range_subid, (len > 1) ? index : 0);
snmp_put_oid(c.buffer, oid);
ADVANCE(c.buffer, c.size, snmp_oid_size(oid));
- /* We place upper-bound if needed. */
+ /* place upper-bound if needed */
if (len > 1)
{
STORE_PTR(c.buffer, len);
snmp_log("sk_send error");
}
-/* Register-PDU */
+/* register pdu */
void
snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 is_instance)
{
}
-/* Unregister-PDU */
+/* unregister pdu */
void UNUSED
snmp_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len)
{
ADVANCE(buf, size, in_pkt);
}
- memcpy(buf, cap, snmp_oid_size(cap));
+ // memcpy(buf, cap, snmp_oid_size(cap));
ADVANCE(buf, size, snmp_oid_size(cap));
in_pkt = snmp_put_nstr(buf, descr, descr_len) - buf;
uint parsed_len = 0;
struct agentx_header *h = (void *) pkt;
- snmp_log("parse_pkt got type %s", snmp_pkt_type[h->type]);
+ snmp_log("parse_pkt got type %s (%d)", snmp_pkt_type[h->type], h->type);
+ snmp_log("parse_pkt rx size %u", size);
snmp_dump_packet((void *)h, MIN(h->payload, 256));
switch (h->type)
{
parsed_len = parse_response(p, pkt, size);
break;
+ /*
+ case AGENTX_GET_PDU:
+ refresh_ids(p, h);
+ return parse_get_pdu(p, pkt, size);
+ */
+
case AGENTX_GET_PDU:
case AGENTX_GET_NEXT_PDU:
case AGENTX_GET_BULK_PDU:
refresh_ids(p, h);
+ //parsed_len = parse_gets_pdu(p, &c);
+ //parsed_len = parse_gets_pdu(p, pkt, size, skip);
parsed_len = parse_gets2_pdu(p, pkt, size, skip);
break;
//die("unknown packet type %u", h->type);
}
+ /* We will process the same header again later * /
+ if (*skip || parsed_len < size)
+ {
+ / * We split our answer to multiple packet, we should differentiate them * /
+ h->packet_id++;
+ }
+ */
+
snmp_log("parse_pkt returning parsed length");
+ //snmp_dump_packet(p->sock->tbuf, 64);
return parsed_len;
}
{
snmp_log("parse_response() g%u h%u", size, sizeof(struct agentx_header));
+ //snmp_dump_packet(res, size);
+
if (size < sizeof(struct agentx_response))
return 0;
if (r->error == AGENTX_RES_NO_ERROR)
do_response(p, res, size);
else
- /* Erronous packet should be dropped quietly. */
+ /* erronous packet should be dropped quietly */
snmp_log("an error occured '%s'", snmp_errs[get_u16(&r->error) - SNMP_ERR_SHIFT]);
return pkt_size + AGENTX_HEADER_SIZE;
switch (p->state)
{
case SNMP_INIT:
- /* We copy session info from recieved packet */
+ case SNMP_LOCKED:
+ /* silent drop of recieved packet */
+ break;
+
+ case SNMP_OPEN:
+ /* copy session info from recieved packet */
p->session_id = LOAD_U32(h->session_id, byte_ord);
refresh_ids(p, h);
- /*
- * The state needs to be changed before sending registering PDUs to
+ /* the state needs to be changed before sending registering PDUs to
* use correct do_response action on them
*/
snmp_log("changing state to REGISTER");
if (snmp_registered_all(p)) {
snmp_log("changing proto_snmp state to CONNECTED");
p->state = SNMP_CONN;
+ proto_notify_state(&p->p, PS_UP);
}
break;
break;
case SNMP_STOP:
- /* do nothing here */
+ snmp_shutdown();
break;
default:
u8
snmp_get_mib_class(const struct oid *oid)
{
+ // TODO check code paths for oid->n_subid < 3
if (oid->prefix != 2 && oid->ids[0] != SNMP_MIB_2)
return SNMP_CLASS_INVALID;
- ASSUME(oid->n_subid > 1);
switch (oid->ids[1])
{
case SNMP_BGP4_MIB:
if (c->size < sz)
{
- /* This is a bit tricky as we invalidate all in TX buffer pointers */
- snmp_manage_tbuf(p, c);
+ /* TODO create NULL varbind */
+ c->error = AGENTX_RES_GEN_ERROR;
+ return;
}
vb = snmp_create_varbind(c->buffer, o_start);
return;
case SNMP_SEARCH_OK:
- default: /* intentionaly left blank */
+ default:
break;
}
if (o_copy)
{
- /* Basicaly snmp_create_varbind(c->buffer, o_copy),
- * but without any copying */
+ /* basicaly snmp_create_varbind(c->buffer, o_copy), but without any copying */
vb = (void *) c->buffer;
snmp_mib_fill2(p, o_copy, c);
- /* Override the error value for GetNext-PDU when object is not found. */
+ /* override the error for GetNext-PDU object not find */
switch (vb->type)
{
case AGENTX_NO_SUCH_OBJECT:
struct agentx_bulk_state *state, struct snmp_pdu_context *c)
{
if (state->index <= state->getbulk.non_repeaters)
+ {
return snmp_get_next2(p, o_start, o_end, c);
- else
+ /*
+ * 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;
+
+ uint i = 0;
+ do
{
- 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);
+
+ /* Object Identifier fall-backs */
+ if (!o_curr)
+ o_curr = o_predecessor;
- uint i = 0;
- do
- {
- o_predecessor = o_curr;
- o_curr = search_mib(p, o_start, o_end, o_curr, c, &r);
- i++;
- } while (o_curr && i <= state->repetition);
+ if (!o_curr)
+ o_curr = o_start;
- if (!o_curr && i == 1)
- {
- o_predecessor = o_start;
- goto abnormal;
- }
+ uint sz = snmp_varbind_hdr_size_from_oid(o_curr);
- if (!o_curr)
- goto abnormal;
+ if (c->size < sz)
+ {
+ c->error = AGENTX_RES_GEN_ERROR;
+ return;
+ }
- return snmp_mib_fill2(p, o_curr, c);
+ /* we need the varbind handle to be able to override it's type */
+ struct agentx_varbind *vb = (void *) c->buffer;
+ vb->type = AGENTX_END_OF_MIB_VIEW;
-abnormal:;
- uint sz = snmp_varbind_hdr_size_from_oid(o_predecessor);
+ if (r == SNMP_SEARCH_OK)
+ /* the varbind will be recreated inside the snmp_mib_fill2() */
+ snmp_mib_fill2(p, o_curr, c);
+ else
+ ADVANCE(c->buffer, c->size, snmp_varbind_header_size(vb));
- if (c->size < sz)
- {
- snmp_log("snmp_get_bulk2() insufficient amount of memory in TX buffer, returning GET_ERROR");
- c->error = AGENTX_RES_GEN_ERROR;
- return;
- }
+ /* override the error for GetBulk-PDU object not found */
+ switch (vb->type)
+ {
+ case AGENTX_NO_SUCH_OBJECT:
+ case AGENTX_NO_SUCH_INSTANCE:
+ case AGENTX_END_OF_MIB_VIEW:
+ vb->type = AGENTX_END_OF_MIB_VIEW;
+ break;
- struct agentx_varbind *vb = snmp_create_varbind(c->buffer, o_predecessor);
- vb->type = AGENTX_END_OF_MIB_VIEW;
- ADVANCE(c->buffer, c->size, snmp_varbind_size(vb, c->byte_ord));
+ default: /* intentionally left blank */
+ break;
}
}
p->state = SNMP_ERR;
+ proto_notify(PS_DOWN, &p->p);
*/
return 0;
}
static inline uint
update_packet_size(struct snmp_proto *p, byte *start, byte *end)
{
- /* Work even for partial packets */
+ /* work even for partial messages */
struct agentx_header *h = (void *) p->sock->tpos;
size_t s = snmp_pkt_len(start, end);
STORE_U32(h->payload, s);
return AGENTX_HEADER_SIZE + s;
+
+#if 0
+ if (EMPTY_LIST(p->additional_buffers))
+ {
+ return AGENTX_HEADER_SIZE + STORE_U32(h->payload, snmp_pkt_len(start, end));
+ }
+
+ uint size = p->to_send; /* to_send contain also the AGENTX_HEADER_SIZE */
+ struct additional_buffer *b = TAIL(p->additional_buffers);
+ snmp_log("update_packet_size additional buf 0x%p pos 0x%p new pos 0x%p", b->buf, b->pos, end);
+ b->pos = end;
+
+ snmp_log("update_packet_size to_send %u", p->to_send);
+
+ /* TODO add packet size limiting
+ * we couldn't overflow the size because we limit the maximum packet size
+ */
+ WALK_LIST(b, p->additional_buffers)
+ {
+ size += b->pos - b->buf;
+ snmp_log("update_packet_size add %u => %u", b->pos - b->buf, size);
+ }
+
+ STORE_U32(h->payload, size - AGENTX_HEADER_SIZE);
+
+ return size;
+// if (p->additional_bufferson
+// STORE_U32(h->payload, p->to_send + (end - start));
+// else {}
+//// STORE_U32(h->payload, snmp_pkt_len(start, end));
+#endif
}
static inline void
.context = 0,
};
- uint clen; /* Count of characters in context (without last '\0') */
- char *context; /* Newly allocated string of character */
+ uint clen; /* count of characters in context (without last '\0') */
+ char *context; /* newly allocated string of character */
/* alters pkt; assign context, clen */
SNMP_LOAD_CONTEXT(p, h, pkt, context, clen);
*/
if (pkt_size < clen)
{
- /* For malformed packets consume full pkt_size */
+ /* for malformed packets consume full pkt_size [or size] */
c.error = AGENTX_RES_PARSE_ERROR;
goto send;
}
c.context = ...
*/
- struct agentx_bulk_state bulk_state = { 0 };
+ struct agentx_bulk_state bulk_state = { };
+ if (h->type == AGENTX_GET_BULK_PDU)
+ {
+ if (size < sizeof(struct agentx_getbulk))
+ goto wait;
- if (c.size < sizeof(struct agentx_response))
+ if (pkt_size < sizeof(struct agentx_getbulk))
+ {
+ c.error = AGENTX_RES_PARSE_ERROR;
+ goto send;
+ }
+
+ struct agentx_getbulk *bulk_info = (void *) pkt;
+ ADVANCE(pkt, pkt_size, sizeof(struct agentx_getbulk));
+
+ bulk_state = (struct agentx_bulk_state) {
+ .getbulk = {
+ .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,
+ };
+ }
+
+ if (!p->partial_response && c.size < sizeof(struct agentx_response))
{
- die("gets2: too small tx buffer");
snmp_manage_tbuf(p, &c);
}
uint ind = 1;
while (c.error == AGENTX_RES_NO_ERROR && size > 0 && pkt_size > 0)
{
- snmp_log("iter %u ``size'' %u", ind, c.buffer - ((byte *) response_header));
+ snmp_log("iter %u size %u remaining %u/%u", ind, c.buffer - sk->tpos, size, pkt_size);
+#if 0
+ if (EMPTY_LIST(p->additional_buffers))
+ snmp_log("iter %u size %u remaining %u/%u", ind, c.buffer - sk->tpos, size, pkt_size);
+ else
+ snmp_log("iter+ %u size %u remaining %u/%u", ind, c.buffer - ((struct additional_buffer *) TAIL(p->additional_buffers))->buf, size, pkt_size);
+#endif
if (size < snmp_oid_sizeof(0))
goto partial;
uint sz;
if ((sz = snmp_oid_size(o_start_b)) > pkt_size)
{
- /* For malformed packets consume full pkt_size */
+ /* for malformed packets consume full pkt_size [or size] */
c.error = AGENTX_RES_PARSE_ERROR; /* Packet error, inconsistent values */
goto send;
}
/*
- * If we already have written same relevant data to the tx-buffer then
+ * 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 recieved.
*/
if (sz > size && ind > 1)
{
snmp_log("sz %u > %u size && ind %u > 1", sz, size, ind);
- /* Wait until the rest of the packet arrives, mark the proccess bytes */
- goto partial;
+ goto partial; /* send already processed part */
}
else if (sz > size)
{
size -= sz;
/*
- * We load search range end OID.
+ * We load search range end OID
* The exactly same process of sanity checking is preformed while loading
- * the SearchRange's end OID.
+ * the SearchRange's end OID
*/
const struct oid *o_end_b = (void *) pkt;
if ((sz = snmp_oid_size(o_end_b)) > pkt_size)
goto send;
}
+ /* TODO find mib_class, check if type is GET of GET_NEXT, act acordingly */
switch (h->type)
{
case AGENTX_GET_PDU:
send:
snmp_log("gets2: sending response ...");
- response_err_ind(response_header, c.error, ind);
-
- /* Number of bytes put into the TX buffer */
+ struct agentx_response *res = (void *) sk->tbuf;
+ /* update the error, index pair on the beginning of the packet */
+ response_err_ind(res, c.error, ind);
uint s = update_packet_size(p, (byte *) response_header, c.buffer);
- snmp_log("sending response to Get-PDU, GetNext-PDU or GetBulk-PDU request ...");
+
+ snmp_log("sending response to Get-PDU, GetNext-PDU or GetBulk-PDU request (size %u)...", s);
+ /* send the message in TX buffer */
int ret = sk_send(sk, s);
+ if (ret > 0)
+ snmp_log("sk_send OK!");
+ else if (ret == 0)
+ snmp_log("sk_send sleep");
+ else
+ snmp_log("sk_send error");
+ // TODO think through the error state
+
+ p->partial_response = NULL;
+ /*
+ int ret = sk_send(sk, c.buffer - sk->tpos);
if (ret == 0)
snmp_log("sk_send sleep (gets2");
else if (ret < 0)
snmp_log("sk_send err %d (gets2)", ret);
else
snmp_log("sk_send was successful (gets2) !");
-
- p->partial_response = NULL;
+ */
mb_free(context);
mb_free(o_start);
mb_free(o_end);
- /* Number of bytes consumed from RX buffer */
+ /* number of bytes parsed form rx-buffer */
return pkt - pkt_start;
partial:
snmp_log("partial packet");
/* The context octet is not added into response pdu */
- /* We need to tweak RX buffer packet size. */
+ /* need to tweak RX buffer packet size */
snmp_log("old rx-buffer size %u", h->payload);
(c.byte_ord) ? put_u32(&h->payload, pkt_size) : (h->payload = pkt_size);
snmp_log("new rx-buffer size %u", h->payload);
-
*skip = AGENTX_HEADER_SIZE;
p->partial_response = response_header;
-
- /* Number of bytes consumed from RX buffer */
return pkt - pkt_start;
wait:
snmp_log("snmp_start_subagent() starting subagent");
snmp_log("DEBUG p->local_as %u", p->local_as);
- /* Blank oid means unsupported */
- // TODO optional subagent identification
+ /* blank oid means unsupported */
struct oid *blank = snmp_oid_blank(p);
open_pdu(p, blank);
+
+ p->state = SNMP_OPEN;
+
mb_free(blank);
}
void
snmp_stop_subagent(struct snmp_proto *p)
{
- snmp_log("snmp_stop_subagent() state %s", p->state);
+ snmp_log("snmp_stop_subagent() state %d", p->state);
if (p->state == SNMP_STOP)
close_pdu(p, AGENTX_CLOSE_SHUTDOWN);
snmp_rx(sock *sk, uint size)
{
snmp_log("snmp_rx() size %u", size);
+ //snmp_dump_packet(sk->tbuf, 64);
struct snmp_proto *p = sk->data;
byte *pkt_start = sk->rbuf;
byte *end = pkt_start + size;
uint skip = 0;
snmp_log("snmp_rx before loop");
- while (end >= pkt_start + AGENTX_HEADER_SIZE)
+ while (end >= pkt_start + AGENTX_HEADER_SIZE && skip == 0)
{
uint parsed_len = parse_pkt(p, pkt_start, size, &skip);
snmp_log("snmp_rx loop end %p parsed >>> %u <<< curr %p", end, parsed_len,
pkt_start + parsed_len);
+ snmp_log("snmp_rx loop2 rpos 0x%p", sk->rpos);
if (parsed_len == 0)
break;
void
snmp_ping(struct snmp_proto *p)
{
- /* this code does not support non-default context */
+ {
+#define SNMP_OID_SIZE_FROM_LEN(x) (sizeof(struct oid) + (x) * sizeof(u32))
+ /* trap OID bgpEstablishedNotification (.1.3.6.1.2.1.0.1) */
+ struct oid *head = mb_alloc(p->p.pool, SNMP_OID_SIZE_FROM_LEN(3));
+ head->n_subid = 3;
+ head->prefix = 2;
+ head->include = head->pad = 0;
+
+ u32 trap_ids[] = { 1, 0, 1 };
+ for (uint i = 0; i < head->n_subid; i++)
+ head->ids[i] = trap_ids[i];
+
+ /* paylaod oids */
+ uint sz = 3 * SNMP_OID_SIZE_FROM_LEN(9) + 3 * 4 + 2 * 8 + 4 - 20;
+ void *data = mb_alloc(p->p.pool, sz);
+ struct agentx_varbind *addr_vb = data;
+ /* +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;
+#undef SNMP_OID_SIZE_FROM_LEN
+
+ 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;
+
+ u32 oid_ids[] = {
+ SNMP_MIB_2, SNMP_BGP4_MIB, SNMP_BGP_PEER_TABLE, SNMP_BGP_PEER_ENTRY, 0,
+ 10, 1, 2, 1
+ };
+ for (uint i = 0; i < addr->n_subid; 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;
+
+ ip4_addr ip4 = ip4_build(10,1,2,1);
+ snmp_varbind_ip4(addr_vb, 100, ip4);
+
+ char error_str[] = { 0, 0 };
+ snmp_varbind_nstr(error_vb, 100, error_str, 2);
+
+ snmp_varbind_int(state_vb, 100, 6);
+
+ u32 now = current_time() TO_S;
+ if (now % 4 == 0)
+ notify_pdu(p, head, data, sz, 1);
+ else if (now % 2 == 0)
+ notify_pdu(p, head, data, sz, 0);
+ }
+
sock *sk = p->sock;
+ snmp_dump_packet(sk->tpos, AGENTX_HEADER_SIZE + 4);
+ snmp_log("snmp_ping sk->tpos 0x%p", sk->tpos);
struct snmp_pdu_context c = {
.buffer = sk->tpos,
.size = sk->tbuf + sk->tbsize - sk->tpos,
p->packet_id++;
SNMP_SESSION(h, p);
- /* We send only the header */
- snmp_log("sending ping packet ...");
- uint s = update_packet_size(p, sk->tpos, c.buffer);
+ snmp_log("sending ping packet ... tpos 0x%p", sk->tpos);
+ snmp_dump_packet(sk->tpos, AGENTX_HEADER_SIZE + 4);
+ /* sending only header -> pkt - buf */
+ uint s = update_packet_size(p, sk->tpos, c.buffer);
int ret = sk_send(sk, s);
if (ret > 0)
snmp_log("sk_send OK!");
{
}
+
*/
static inline int
}
if (o_end == blank)
- mb_free((void *) o_end);
- return o_curr;
-}
+ mb_free((void *) blank);
-/*
-static byte *
-find_ospf_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size)
-{
- // TO DO X XX
- return NULL;
+ return o_curr;
}
-*/
/**
* snmp_prefixize - return prefixed oid copy if possible
if (snmp_is_oid_empty(oid))
{
- /* Allocate new zeroed oid */
+ /* allocate new zeroed oid */
snmp_log("blank");
return snmp_oid_blank(proto);
}
- /* The oid is already in prefixed form */
+ /* already in prefixed form */
else if (oid->prefix != 0) {
struct oid *new = snmp_oid_duplicate(proto->p.pool, oid);
snmp_log("already prefixed");
}
if (oid->n_subid < 5)
- return NULL;
+ { snmp_log("too small"); return NULL; }
for (int i = 0; i < 4; i++)
if (LOAD_U32(oid->ids[i], byte_ord) != prefix[i])
{ snmp_log("different prefix"); return NULL; }
- /* Interval validity check */
+ /* validity check here */
if (oid->ids[4] >= 256)
{ snmp_log("outside byte first id"); return NULL; }
memcpy(new, oid, sizeof(struct oid));
new->n_subid = oid->n_subid - 5;
- /* We validated the fifth identifier, we can safely use it as prefix */
+ /* validity check before allocation => ids[4] < 256
+ and can be copied to one byte new->prefix */
new->prefix = oid->ids[4];
memcpy(&new->ids, &oid->ids[5], new->n_subid * sizeof(u32));
{
ASSUME(oid != NULL);
+ snmp_log("critical part");
if (c->size < snmp_varbind_hdr_size_from_oid(oid))
{
snmp_manage_tbuf(p, c);
}
+ else
+ {
+ u32 *ptr = mb_alloc(p->p.pool, sizeof(u32) * 4);
+ *ptr = 0xbeef;
+ mb_free(ptr);
+ }
+ snmp_log("critical part done");
struct agentx_varbind *vb = snmp_create_varbind(c->buffer, oid);
* are invalidated!
*/
void
-snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu_context *c)
+snmp_manage_tbuf(struct snmp_proto UNUSED *p, struct snmp_pdu_context *c)
{
snmp_log("snmp_manage_tbuf()");
sock *sk = p->sock;
-
- sk_set_tbsize(sk , sk->tbsize + 2048);
+
+ sk_set_tbsize(sk, sk->tbsize + 2048);
c->size += 2048;
+ //sk_set_tbsize(sk, sk->tbsize + SNMP_TX_BUFFER_SIZE);
+ //c->size += SNMP_TX_BUFFER_SIZE;
+
+ return;
+
+#if 0
+ if (!EMPTY_LIST(p->additional_buffers))
+ {
+ struct additional_buffer *t = TAIL(p->additional_buffers);
+ t->pos = c->buffer;
+ }
+ else
+ p->to_send = c->buffer - p->sock->tpos;
+
+ struct additional_buffer *b = mb_allocz(p->p.pool, sizeof(struct additional_buffer));
+ b->buf = b->pos = mb_alloc(p->p.pool, SNMP_TX_BUFFER_SIZE);
+ add_tail(&p->additional_buffers, &b->n);
+
+ c->buffer = b->buf;
+ c->size = SNMP_TX_BUFFER_SIZE;
+#endif
}
+#if 0
+static int
+send_remaining_buffers(sock *sk)
+{
+ struct snmp_proto *p = sk->data;
+
+ while (!EMPTY_LIST(p->additional_buffers))
+ {
+ struct additional_buffer *b = HEAD(p->additional_buffers);
+ p->to_send = b->pos - b->buf;
+ snmp_log("send_remaining_buffers sending next %u bytes", p->to_send);
+
+ ASSUME(sk->tbuf == sk->tpos);
+ memcpy(sk->tbuf, b->buf, p->to_send);
+ sk->tpos = sk->tbuf + p->to_send;
+
+ rem_node(&b->n);
+ snmp_log("state of additional b at 0x%p .buf = 0x%p .pos = 0x%p", b, b->buf, b->pos);
+ mb_free(b->buf);
+ snmp_log("b->buf fried, cause is b");
+ mb_free(b);
+
+ snmp_log("packet byte stream part next");
+ snmp_dump_packet(sk->tpos, p->to_send);
+
+ int ret;
+ if ((ret = sk_send(sk, p->to_send)) <= 0)
+ {
+ snmp_log("sending_remaining - error or sleep;returning");
+ return ret;
+ }
+ }
+
+ snmp_log("sending_remaining all done returning 1");
+ return 1;
+}
+#endif
+
void
snmp_tx(sock UNUSED *sk)
{
- snmp_log("snmp_tx() hook");
+ snmp_log("snmp_tx");
+ //struct snmp_proto *p = sk->data;
return;
+
+#if 0
+ if (!p->partial_response)
+ return;
+
+ send_remaining_buffers(sk);
+#endif
}
{
snmp_log("prepare_response()");
- if (p->partial_response)
- return p->partial_response;
+ if (!p->partial_response)
+ {
+ struct agentx_response *r = (void *) c->buffer;
+ struct agentx_header *h = &r->h;
- struct agentx_response *r = (void *) c->buffer;
- struct agentx_header *h = &r->h;
+ SNMP_BLANK_HEADER(h, AGENTX_RESPONSE_PDU);
+ SNMP_SESSION(h, p);
- SNMP_BLANK_HEADER(h, AGENTX_RESPONSE_PDU);
- SNMP_SESSION(h, p);
+ /* protocol doesn't care about subagent upTime */
+ STORE_U32(r->uptime, 0);
+ STORE_U16(r->error, AGENTX_RES_NO_ERROR);
+ STORE_U16(r->index, 0);
- /* AgentX protocol does not care about subagent upTime */
- STORE_U32(r->uptime, 0);
- STORE_U16(r->error, AGENTX_RES_NO_ERROR);
- STORE_U16(r->index, 0);
+ ADVANCE(c->buffer, c->size, sizeof(struct agentx_response));
+ return r;
+ }
- ADVANCE(c->buffer, c->size, sizeof(struct agentx_response));
- return r;
+ return p->partial_response;
}