📄 msg_in.c
字号:
}
if (mn == NULL)
{
/* mn == NULL, noSuchName */
snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
}
}
if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
(msg_ps->vb_idx == msg_ps->invb.count))
{
snmp_ok_response(msg_ps);
}
}
/**
* Service an internal or external event for SNMP SET.
*
* @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
* @param msg_ps points to the assosicated message process state
*/
static void
snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
{
struct mib_external_node *en;
struct snmp_name_ptr np;
/* get_object_def() answer*/
en = msg_ps->ext_mib_node;
np = msg_ps->ext_name_ptr;
/* translate answer into a known lifeform */
en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
{
msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;
en->set_test_q(request_id, &msg_ps->ext_object_def);
}
else
{
en->get_object_def_pc(request_id, np.ident_len, np.ident);
/* search failed, object id points to unknown object (nosuchname) */
snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
}
}
else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)
{
struct mib_external_node *en;
/* set_test() answer*/
en = msg_ps->ext_mib_node;
if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)
{
if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
(en->set_test_a(request_id,&msg_ps->ext_object_def,
msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
{
msg_ps->state = SNMP_MSG_SEARCH_OBJ;
msg_ps->vb_idx += 1;
}
else
{
en->set_test_pc(request_id,&msg_ps->ext_object_def);
/* bad value */
snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
}
}
else
{
en->set_test_pc(request_id,&msg_ps->ext_object_def);
/* object not available for set */
snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
}
}
else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)
{
struct mib_external_node *en;
struct snmp_name_ptr np;
/* get_object_def() answer*/
en = msg_ps->ext_mib_node;
np = msg_ps->ext_name_ptr;
/* translate answer into a known lifeform */
en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
{
msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;
en->set_value_q(request_id, &msg_ps->ext_object_def,
msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
}
else
{
en->get_object_def_pc(request_id, np.ident_len, np.ident);
/* set_value failed, object has disappeared for some odd reason?? */
snmp_error_response(msg_ps,SNMP_ES_GENERROR);
}
}
else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)
{
struct mib_external_node *en;
/** set_value_a() */
en = msg_ps->ext_mib_node;
en->set_value_a(request_id, &msg_ps->ext_object_def,
msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value);
/** @todo use set_value_pc() if toobig */
msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
msg_ps->vb_idx += 1;
}
/* test all values before setting */
while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
(msg_ps->vb_idx < msg_ps->invb.count))
{
struct mib_node *mn;
struct snmp_name_ptr np;
if (msg_ps->vb_idx == 0)
{
msg_ps->vb_ptr = msg_ps->invb.head;
}
else
{
msg_ps->vb_ptr = msg_ps->vb_ptr->next;
}
/** test object identifier for .iso.org.dod.internet prefix */
if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident))
{
mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
msg_ps->vb_ptr->ident + 4, &np);
if (mn != NULL)
{
if (mn->node_type == MIB_NODE_EX)
{
/* external object */
struct mib_external_node *en = (struct mib_external_node*)mn;
msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
/* save en && args in msg_ps!! */
msg_ps->ext_mib_node = en;
msg_ps->ext_name_ptr = np;
en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
}
else
{
/* internal object */
struct obj_def object_def;
msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
mn->get_object_def(np.ident_len, np.ident, &object_def);
if (object_def.instance != MIB_OBJECT_NONE)
{
mn = mn;
}
else
{
/* search failed, object id points to unknown object (nosuchname) */
mn = NULL;
}
if (mn != NULL)
{
msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
if (object_def.access == MIB_OBJECT_READ_WRITE)
{
if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
(mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
{
msg_ps->state = SNMP_MSG_SEARCH_OBJ;
msg_ps->vb_idx += 1;
}
else
{
/* bad value */
snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
}
}
else
{
/* object not available for set */
snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
}
}
}
}
}
else
{
mn = NULL;
}
if (mn == NULL)
{
/* mn == NULL, noSuchName */
snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
}
}
if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
(msg_ps->vb_idx == msg_ps->invb.count))
{
msg_ps->vb_idx = 0;
msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
}
/* set all values "atomically" (be as "atomic" as possible) */
while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
(msg_ps->vb_idx < msg_ps->invb.count))
{
struct mib_node *mn;
struct snmp_name_ptr np;
if (msg_ps->vb_idx == 0)
{
msg_ps->vb_ptr = msg_ps->invb.head;
}
else
{
msg_ps->vb_ptr = msg_ps->vb_ptr->next;
}
/* skip iso prefix test, was done previously while settesting() */
mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
msg_ps->vb_ptr->ident + 4, &np);
/* check if object is still available
(e.g. external hot-plug thingy present?) */
if (mn != NULL)
{
if (mn->node_type == MIB_NODE_EX)
{
/* external object */
struct mib_external_node *en = (struct mib_external_node*)mn;
msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;
/* save en && args in msg_ps!! */
msg_ps->ext_mib_node = en;
msg_ps->ext_name_ptr = np;
en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
}
else
{
/* internal object */
struct obj_def object_def;
msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;
mn->get_object_def(np.ident_len, np.ident, &object_def);
msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
msg_ps->vb_idx += 1;
}
}
}
if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
(msg_ps->vb_idx == msg_ps->invb.count))
{
/* simply echo the input if we can set it
@todo do we need to return the actual value?
e.g. if value is silently modified or behaves sticky? */
msg_ps->outvb = msg_ps->invb;
msg_ps->invb.head = NULL;
msg_ps->invb.tail = NULL;
msg_ps->invb.count = 0;
snmp_ok_response(msg_ps);
}
}
/**
* Handle one internal or external event.
* Called for one async event. (recv external/private answer)
*
* @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
*/
void
snmp_msg_event(u8_t request_id)
{
struct snmp_msg_pstat *msg_ps;
if (request_id < SNMP_CONCURRENT_REQUESTS)
{
msg_ps = &msg_input_list[request_id];
if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)
{
snmp_msg_getnext_event(request_id, msg_ps);
}
else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)
{
snmp_msg_get_event(request_id, msg_ps);
}
else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)
{
snmp_msg_set_event(request_id, msg_ps);
}
}
}
/* lwIP UDP receive callback function */
static void
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
{
struct udp_hdr *udphdr;
/* suppress unused argument warning */
LWIP_UNUSED_ARG(arg);
/* peek in the UDP header (goto IP payload) */
if(pbuf_header(p, UDP_HLEN)){
LWIP_ASSERT("Can't move to UDP header", 0);
pbuf_free(p);
return;
}
udphdr = p->payload;
/* check if datagram is really directed at us (including broadcast requests) */
if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT))
{
struct snmp_msg_pstat *msg_ps;
u8_t req_idx;
/* traverse input message process list, look for SNMP_MSG_EMPTY */
msg_ps = &msg_input_list[0];
req_idx = 0;
while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
{
req_idx++;
msg_ps++;
}
if (req_idx != SNMP_CONCURRENT_REQUESTS)
{
err_t err_ret;
u16_t payload_len;
u16_t payload_ofs;
u16_t varbind_ofs = 0;
/* accepting request */
snmp_inc_snmpinpkts();
/* record used 'protocol control block' */
msg_ps->pcb = pcb;
/* source address (network order) */
msg_ps->sip = *addr;
/* source port (host order (lwIP oddity)) */
msg_ps->sp = port;
/* read UDP payload length from UDP header */
payload_len = ntohs(udphdr->len) - UDP_HLEN;
/* adjust to UDP payload */
payload_ofs = UDP_HLEN;
/* check total length, version, community, pdu type */
err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||
(msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||
(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&
((msg_ps->error_status == SNMP_ES_NOERROR) &&
(msg_ps->error_index == 0)) )
{
/* Only accept requests and requests without error (be robust) */
err_ret = err_ret;
}
else
{
/* Reject response and trap headers or error requests as input! */
err_ret = ERR_ARG;
}
if (err_ret == ERR_OK)
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
/* Builds a list of variable bindings. Copy the varbinds from the pbuf
chain to glue them when these are divided over two or more pbuf's. */
err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))
{
/* we've decoded the incoming message, release input msg now */
pbuf_free(p);
msg_ps->error_status = SNMP_ES_NOERROR;
msg_ps->error_index = 0;
/* find object for each variable binding */
msg_ps->state = SNMP_MSG_SEARCH_OBJ;
/* first variable binding from list to inspect */
msg_ps->vb_idx = 0;
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
/* handle input event and as much objects as possible in one go */
snmp_msg_event(req_idx);
}
else
{
/* varbind-list decode failed, or varbind list empty.
drop request silently, do not return error!
(errors are only returned for a specific varbind failure) */
pbuf_free(p);
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
}
}
else
{
/* header check failed
drop request silently, do not return error! */
pbuf_free(p);
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
}
}
else
{
/* exceeding number of concurrent requests */
pbuf_free(p);
}
}
else
{
/* datagram not for us */
pbuf_free(p);
}
}
/**
* Checks and decodes incoming SNMP message header, logs header errors.
*
* @param p points to pbuf chain of SNMP message (UDP payload)
* @param ofs points to first octet of SNMP message
* @param pdu_len the length of the UDP payload
* @param ofs_ret returns the ofset of the variable bindings
* @param m_stat points to the current message request state return
* @return
* - ERR_OK SNMP header is sane and accepted
* - ERR_ARG SNMP header is either malformed or rejected
*/
static err_t
snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
{
err_t derr;
u16_t len, ofs_base;
u8_t len_octets;
u8_t type;
s32_t version;
ofs_base = ofs;
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) ||
(pdu_len != (1 + len_octets + len)) ||
(type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
{
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
ofs += (1 + len_octets);
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
{
/* can't decode or no integer (version) */
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);
if (derr != ERR_OK)
{
/* can't decode */
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
}
if (version != 0)
{
/* not version 1 */
snmp_inc_snmpinbadversions();
return ERR_ARG;
}
ofs += (1 + len_octets + len);
snmp_asn1_dec_type(p, ofs, &type);
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))
{
/* can't decode or no octet string (community) */
snmp_inc_snmpinasnparseerrs();
return ERR_ARG;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -