mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 17:51:53 +00:00
SNMP: Bare support for agentx-TestSet-PDU
This commit is contained in:
parent
faa6262573
commit
e15f38e082
@ -1302,3 +1302,12 @@ snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb,
|
||||
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
|
||||
|
||||
|
@ -46,6 +46,7 @@ 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);
|
||||
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);
|
||||
|
@ -328,6 +328,59 @@ close_pdu(struct snmp_proto *p, u8 reason)
|
||||
sk_send(sk, s);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (size < sizeof(struct agentx_header))
|
||||
{
|
||||
snmp_log("p_close early return");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// struct agentx_header *h = (void *) req;
|
||||
ADVANCE(req, size, AGENTX_HEADER_SIZE);
|
||||
//snmp_log("after header %p", req);
|
||||
|
||||
p->state = SNMP_ERR;
|
||||
|
||||
// or snmp_cleanup(); // ??!
|
||||
proto_notify_state(&p->p, PS_DOWN);
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MUCH better signature would be
|
||||
static int snmp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, uint pkt_size);
|
||||
*/
|
||||
/* return 1 if the value could be set */
|
||||
static int
|
||||
snmp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, struct oid *oid, uint pkt_size)
|
||||
{
|
||||
/* Hard-coded no support for writing */
|
||||
(void)p;(void)vb;(void)oid;(void)pkt_size;
|
||||
return 0;
|
||||
#if 0
|
||||
// TODO better logic
|
||||
if (!oid)
|
||||
return 0;
|
||||
|
||||
switch (oid->ids[1])
|
||||
{
|
||||
case SNMP_BGP4_MIB:
|
||||
return snmp_bgp_testset(p, vb, oid, pkt_size);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void UNUSED
|
||||
addagentcaps_pdu(struct snmp_proto *p, struct oid *cap, char *descr,
|
||||
@ -420,6 +473,194 @@ refresh_ids(struct snmp_proto *p, struct agentx_header *h)
|
||||
p->packet_id = LOAD_U32(h->packet_id, byte_ord);
|
||||
}
|
||||
|
||||
static uint
|
||||
parse_test_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
|
||||
{
|
||||
//snmp_log("parse_test_set");
|
||||
const byte *pkt_start = pkt; /* start of packet in RX-buffer */
|
||||
uint ind = 0; /* index of the error */
|
||||
uint s; /* final packat size */
|
||||
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, h->flags & AGENTX_NETWORK_BYTE_ORDER);
|
||||
|
||||
sock *sk = p->sock;
|
||||
struct snmp_pdu c = SNMP_PDU_CONTEXT(sk);
|
||||
byte *buf = c.buffer; /* start of packet in TX-buffer */
|
||||
c.byte_ord = 0; /* use little-endian */
|
||||
|
||||
if (c.size < AGENTX_HEADER_SIZE)
|
||||
{
|
||||
snmp_manage_tbuf(p, &c);
|
||||
// TODO renew all pointers
|
||||
}
|
||||
|
||||
res = prepare_response(p, &c);
|
||||
|
||||
uint clen;
|
||||
const char *context;
|
||||
SNMP_LOAD_CONTEXT(h, pkt, context, clen);
|
||||
|
||||
if (size < clen)
|
||||
return 0;
|
||||
|
||||
if (pkt_size < clen)
|
||||
{
|
||||
c.error = AGENTX_RES_PARSE_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ADVANCE(pkt, pkt_size, clen);
|
||||
size -= clen;
|
||||
|
||||
//snmp_log("test_set: parsed header and context");
|
||||
/* 0 if there is piece, that we cannot set */
|
||||
int all_possible = 0;
|
||||
/* the all_possible is currently hard-coded with no support for writing to mib
|
||||
* variables, when implementing the mentioned support, change the initializer
|
||||
* to 1
|
||||
*/
|
||||
|
||||
#if 0
|
||||
// TODO think about future value setting data structure
|
||||
//struct agentx_transaction *tr = mb_alloc(...);
|
||||
void *tr = mb_alloc(p->pool, 16);
|
||||
|
||||
struct agentx_varbind *vb;
|
||||
uint sz;
|
||||
while (size > 0 && all_possible)
|
||||
{
|
||||
vb = (void *) pkt;
|
||||
sz = snmp_varbind_size(vb, 0);
|
||||
|
||||
if (sz > size)
|
||||
/* wait for more data to arive */
|
||||
return 0;
|
||||
|
||||
if (sz > pkt_size)
|
||||
{
|
||||
c.error = AGENTX_RES_PARSE_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Unknown VarBind type check */
|
||||
if (!snmp_test_varbind(vb))
|
||||
{
|
||||
c.error = AGENTX_RES_PARSE_ERROR;
|
||||
goto error;
|
||||
}
|
||||
ADVANCE(pkt, size, snmp_varbind_size(vb, 0));
|
||||
|
||||
// TODO remove the mb_alloc() in prefixize()
|
||||
struct oid *work = snmp_prefixize(p, &vb->name, c.byte_ord);
|
||||
(void)work;
|
||||
all_possible = snmp_testset(p, vb, tr, work, pkt_size);
|
||||
mb_free(work);
|
||||
}
|
||||
//snmp_log("test_set parsed all varbinds");
|
||||
mb_free(tr);
|
||||
#endif
|
||||
|
||||
error:
|
||||
s = update_packet_size(p, buf, c.buffer);
|
||||
|
||||
if (c.error != AGENTX_RES_NO_ERROR)
|
||||
response_err_ind(res, c.error, ind + 1);
|
||||
else if (all_possible)
|
||||
response_err_ind(res, AGENTX_RES_NO_ERROR, 0);
|
||||
else
|
||||
//response_err_ind(res, AGENTX_RES_RESOURCE_UNAVAILABLE, ind + 1);
|
||||
response_err_ind(res, AGENTX_RES_NOT_WRITABLE, ind + 1);
|
||||
|
||||
//snmp_log("test_set sending response");
|
||||
sk_send(sk, s);
|
||||
return pkt - pkt_start;
|
||||
}
|
||||
|
||||
static uint
|
||||
parse_set_pdu(struct snmp_proto *p, byte *pkt, uint size, uint err)
|
||||
{
|
||||
const byte *pkt_start = pkt;
|
||||
|
||||
if (size < AGENTX_HEADER_SIZE)
|
||||
return 0;
|
||||
|
||||
struct agentx_header *h = (void *) pkt;
|
||||
ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
|
||||
uint pkt_size = LOAD_U32(h->payload, h->flags & AGENTX_NETWORK_BYTE_ORDER);
|
||||
|
||||
struct snmp_pdu c = SNMP_PDU_CONTEXT(p->sock);
|
||||
if (c.size < sizeof(struct agentx_response))
|
||||
{
|
||||
snmp_manage_tbuf(p, &c);
|
||||
// TODO renew all pointers
|
||||
}
|
||||
|
||||
struct agentx_response *r = prepare_response(p, &c);
|
||||
|
||||
uint clen;
|
||||
const char *context;
|
||||
SNMP_LOAD_CONTEXT(h, pkt, context, clen);
|
||||
|
||||
if (size < snmp_str_size_from_len(clen))
|
||||
return 0;
|
||||
|
||||
if (size < pkt_size)
|
||||
{
|
||||
c.error = AGENTX_RES_PARSE_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ADVANCE(pkt, size, snmp_str_size_from_len(clen));
|
||||
// TODO: work with context
|
||||
|
||||
// TODO: free resource allocated by parse_test_set_pdu()
|
||||
// TODO: do something meaningful
|
||||
//mb_free(tr);
|
||||
c.error = err;
|
||||
|
||||
error:;
|
||||
response_err_ind(r, c.error, 0);
|
||||
sk_send(p->sock, AGENTX_HEADER_SIZE);
|
||||
return pkt - pkt_start;
|
||||
}
|
||||
|
||||
/* agentx-CommitSet-PDU */
|
||||
static uint
|
||||
parse_commit_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
|
||||
{
|
||||
// don't forget to free resoures allocated by parse_test_set_pdu()
|
||||
//mb_free(tr);
|
||||
return parse_set_pdu(p, pkt, size, AGENTX_RES_COMMIT_FAILED);
|
||||
}
|
||||
|
||||
/* agentx-UndoSet-PDU */
|
||||
static uint
|
||||
parse_undo_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
|
||||
{
|
||||
// don't forget to free resources allocated by parse_test_set_pdu()
|
||||
//mb_free(tr);
|
||||
return parse_set_pdu(p, pkt, size, AGENTX_RES_UNDO_FAILED);
|
||||
}
|
||||
|
||||
/* agentx-CleanupSet-PDU */
|
||||
static uint
|
||||
parse_cleanup_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
|
||||
{
|
||||
// don't forget to free resources allocated by parse_test_set_pdu()
|
||||
//mb_free(tr);
|
||||
|
||||
if (size < AGENTX_HEADER_SIZE)
|
||||
return 0;
|
||||
|
||||
struct agentx_header *h = (void *) pkt;
|
||||
return LOAD_U32(h->payload, h->flags & AGENTX_NETWORK_BYTE_ORDER);
|
||||
|
||||
/* No agentx-Response-PDU is sent in response to agentx-CleanupSet-PDU */
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_pkt - parse recieved response packet
|
||||
* @p:
|
||||
@ -437,7 +678,6 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip)
|
||||
if (size < AGENTX_HEADER_SIZE)
|
||||
return 0;
|
||||
|
||||
uint parsed_len = 0;
|
||||
struct agentx_header *h = (void *) pkt;
|
||||
|
||||
//snmp_log("parse_pkt got type %s (%d)", snmp_pkt_type[h->type], h->type);
|
||||
@ -447,33 +687,58 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip)
|
||||
{
|
||||
case AGENTX_RESPONSE_PDU:
|
||||
//snmp_log("parse_pkt returning parse_response");
|
||||
parsed_len = parse_response(p, pkt, size);
|
||||
break;
|
||||
return parse_response(p, pkt, size);
|
||||
|
||||
case AGENTX_GET_PDU:
|
||||
case AGENTX_GET_NEXT_PDU:
|
||||
case AGENTX_GET_BULK_PDU:
|
||||
refresh_ids(p, h);
|
||||
parsed_len = parse_gets2_pdu(p, pkt, size, skip);
|
||||
break;
|
||||
|
||||
/* during testing the connection should stay opened (we die if we screw up
|
||||
* and get CLOSE_PDU in response)
|
||||
return parse_gets2_pdu(p, pkt, size, skip);
|
||||
|
||||
case AGENTX_CLOSE_PDU:
|
||||
refresh_ids(p, h);
|
||||
parsed_len = parse_close_pdu(p, pkt, size);
|
||||
break;
|
||||
*/
|
||||
return parse_close_pdu(p, pkt, size);
|
||||
|
||||
case AGENTX_TEST_SET_PDU:
|
||||
refresh_ids(p, h);
|
||||
return parse_test_set_pdu(p, pkt, size);
|
||||
|
||||
case AGENTX_COMMIT_SET_PDU:
|
||||
refresh_ids(p, h);
|
||||
return parse_commit_set_pdu(p, pkt, size);
|
||||
|
||||
case AGENTX_UNDO_SET_PDU:
|
||||
refresh_ids(p, h);
|
||||
return parse_undo_set_pdu(p, pkt, size);
|
||||
|
||||
case AGENTX_CLEANUP_SET_PDU:
|
||||
refresh_ids(p, h);
|
||||
return parse_cleanup_set_pdu(p, pkt, size);
|
||||
|
||||
default:
|
||||
/* drop the packet with unknown type silently */
|
||||
//snmp_log("unknown packet type %u", h->type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//snmp_log("parse_pkt returning parsed length");
|
||||
return parsed_len;
|
||||
static void
|
||||
snmp_register_ok(struct snmp_proto *p, struct agentx_response *r, uint size, u8 type)
|
||||
{
|
||||
(void)p;(void)r;(void)size;(void)type;
|
||||
}
|
||||
|
||||
static void
|
||||
snmp_register_failed(struct snmp_proto *p, struct agentx_response *r, uint size, u8 type)
|
||||
{
|
||||
(void)p;(void)r;(void)size;(void)type;
|
||||
}
|
||||
|
||||
static void
|
||||
unsupported_context(struct snmp_proto *p, struct agentx_response *r, uint size)
|
||||
{
|
||||
(void)p;(void)r;(void)size;
|
||||
// TODO unsupported_context
|
||||
}
|
||||
|
||||
static uint
|
||||
@ -506,13 +771,58 @@ parse_response(struct snmp_proto *p, byte *res, uint size)
|
||||
*/
|
||||
//snmp_log(" pkt size %u", h->payload);
|
||||
|
||||
//snmp_log(" pkt size %u", h->payload);
|
||||
|
||||
if (r->error == AGENTX_RES_NO_ERROR)
|
||||
switch (r->error)
|
||||
{
|
||||
case AGENTX_RES_NO_ERROR:
|
||||
do_response(p, res, size);
|
||||
break;
|
||||
|
||||
case AGENTX_RES_NOT_OPEN:
|
||||
if (p->state == SNMP_LOCKED || p->state == SNMP_INIT)
|
||||
snmp_startup(p);
|
||||
else
|
||||
snmp_connected(p->sock);
|
||||
break;
|
||||
|
||||
case AGENTX_RES_OPEN_FAILED:
|
||||
if (p->state == SNMP_LOCKED || p->state == SNMP_INIT)
|
||||
{
|
||||
ASSUME(p->startup_timer);
|
||||
p->startup_timer->hook = snmp_startup_timeout;
|
||||
// TODO: better timeout
|
||||
tm_set(p->startup_timer, current_time() + p->timeout S);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSUME(p->startup_timer);
|
||||
p->startup_timer->hook = snmp_reconnect;
|
||||
// TODO: better timeout
|
||||
tm_set(p->startup_timer, current_time() + p->timeout S);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Registration errors */
|
||||
case AGENTX_RES_DUPLICATE_REGISTER:
|
||||
case AGENTX_RES_REQUEST_DENIED:
|
||||
snmp_register_failed(p, r, size, h->type);
|
||||
break;
|
||||
|
||||
case AGENTX_RES_UNSUPPORTED_CONTEXT:
|
||||
unsupported_context(p, r, size);
|
||||
break;
|
||||
|
||||
/* We are trying to unregister a MIB, the unknownRegistration has same
|
||||
* effect as success */
|
||||
case AGENTX_RES_UNKNOWN_REGISTER:
|
||||
case AGENTX_RES_UNKNOWN_AGENT_CAPS:
|
||||
case AGENTX_RES_PARSE_ERROR:
|
||||
case AGENTX_RES_PROCESSING_ERR:
|
||||
default:
|
||||
/* erronous packet should be dropped quietly */
|
||||
{}//snmp_log("an error occured '%s'", snmp_errs[get_u16(&r->error) - SNMP_ERR_SHIFT]);
|
||||
// TODO correct error?
|
||||
snmp_log("recieved response with error '%s'", snmp_errs[get_u16(&r->error) - SNMP_ERR_SHIFT]);
|
||||
break;
|
||||
}
|
||||
|
||||
return pkt_size + AGENTX_HEADER_SIZE;
|
||||
}
|
||||
|
@ -289,7 +289,9 @@ enum agentx_response_err {
|
||||
AGENTX_RES_NO_CREATION = 11,
|
||||
AGENTX_RES_INCONSISTENT_VALUE = 12,
|
||||
AGENTX_RES_RESOURCE_UNAVAILABLE = 13,
|
||||
AGENTX_RES_NOT_WRITEABLE = 17,
|
||||
AGENTX_RES_COMMIT_FAILED = 14,
|
||||
AGENTX_RES_UNDO_FAILED = 15,
|
||||
AGENTX_RES_NOT_WRITABLE = 17,
|
||||
AGENTX_RES_INCONSISTENT_NAME = 18,
|
||||
/* end of TEST_SET_PDU resonse errs (master -> subagent) */
|
||||
AGENTX_RES_OPEN_FAILED = 256,
|
||||
|
Loading…
Reference in New Issue
Block a user