static err_t snmp_prepare_outbound_frame(struct snmp_request *request) { struct snmp_asn1_tlv tlv; struct snmp_pbuf_stream* pbuf_stream = &(request->outbound_pbuf_stream); /* try allocating pbuf(s) for maximum response size */ request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM); if (request->outbound_pbuf == NULL) { return ERR_MEM; } snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len); /* 'Message' sequence */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); /* version */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len); OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) ); /* community */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen); OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) ); /* 'PDU' sequence */ request->outbound_pdu_offset = pbuf_stream->offset; SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, 0); OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); /* request ID */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len); OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) ); /* error status */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); request->outbound_error_status_offset = pbuf_stream->offset; snmp_pbuf_stream_write(pbuf_stream, 0); /* error index */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); request->outbound_error_index_offset = pbuf_stream->offset; snmp_pbuf_stream_write(pbuf_stream, 0); /* 'VarBindList' sequence */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); request->outbound_varbind_offset = pbuf_stream->offset; return ERR_OK; }
/** * Encodes response header from head to tail. */ static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p) { u16_t ofs; s32_t snmp_req_ver; ofs = 0; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen); ofs += m_stat->rhl.seqlenlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen); ofs += m_stat->rhl.verlenlen; snmp_req_ver = m_stat->version; snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_req_ver); ofs += m_stat->rhl.verlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen); ofs += m_stat->rhl.comlenlen; snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community); ofs += m_stat->rhl.comlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen); ofs += m_stat->rhl.pdulenlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen); ofs += m_stat->rhl.ridlenlen; snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid); ofs += m_stat->rhl.ridlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen); ofs += m_stat->rhl.errstatlenlen; snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status); ofs += m_stat->rhl.errstatlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen); ofs += m_stat->rhl.erridxlenlen; snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index); ofs += m_stat->rhl.erridxlen; return ofs; }
/** * Encodes trap header from head to tail. */ static void snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream) { struct snmp_asn1_tlv tlv; /* 'Message' sequence */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->seqlen); snmp_ans1_enc_tlv(pbuf_stream, &tlv); /* version */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); snmp_asn1_enc_s32t_cnt(trap->snmp_version, &tlv.value_len); snmp_ans1_enc_tlv(pbuf_stream, &tlv); snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version); /* community */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, trap->comlen); snmp_ans1_enc_tlv(pbuf_stream, &tlv); snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)snmp_community_trap, trap->comlen); /* 'PDU' sequence */ SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP), 0, trap->pdulen); snmp_ans1_enc_tlv(pbuf_stream, &tlv); /* object ID */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, 0, 0); snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &tlv.value_len); snmp_ans1_enc_tlv(pbuf_stream, &tlv); snmp_asn1_enc_oid(pbuf_stream, trap->enterprise->id, trap->enterprise->len); /* IP addr */ if(IP_IS_V6_VAL(trap->sip)) { #if LWIP_IPV6 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip6(&trap->sip)->addr)); snmp_ans1_enc_tlv(pbuf_stream, &tlv); snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip6(&trap->sip)->addr, sizeof(ip_2_ip6(&trap->sip)->addr)); #endif } else { #if LWIP_IPV4 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip4(&trap->sip)->addr)); snmp_ans1_enc_tlv(pbuf_stream, &tlv); snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip4(&trap->sip)->addr, sizeof(ip_2_ip4(&trap->sip)->addr)); #endif } /* trap length */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); snmp_asn1_enc_s32t_cnt(trap->gen_trap, &tlv.value_len); snmp_ans1_enc_tlv(pbuf_stream, &tlv); snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->gen_trap); /* specific trap */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); snmp_asn1_enc_s32t_cnt(trap->spc_trap, &tlv.value_len); snmp_ans1_enc_tlv(pbuf_stream, &tlv); snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->spc_trap); /* timestamp */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_TIMETICKS, 0, 0); snmp_asn1_enc_s32t_cnt(trap->ts, &tlv.value_len); snmp_ans1_enc_tlv(pbuf_stream, &tlv); snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->ts); }
/** * Encodes varbind list from head to tail. */ static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs) { struct snmp_varbind *vb; s32_t *sint_ptr; u32_t *uint_ptr; u8_t *raw_ptr; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); ofs += 1; snmp_asn1_enc_length(p, ofs, root->seqlen); ofs += root->seqlenlen; vb = root->head; while ( vb != NULL ) { snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); ofs += 1; snmp_asn1_enc_length(p, ofs, vb->seqlen); ofs += vb->seqlenlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)); ofs += 1; snmp_asn1_enc_length(p, ofs, vb->olen); ofs += vb->olenlen; snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]); ofs += vb->olen; snmp_asn1_enc_type(p, ofs, vb->value_type); ofs += 1; snmp_asn1_enc_length(p, ofs, vb->vlen); ofs += vb->vlenlen; switch (vb->value_type) { case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr); break; case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): uint_ptr = (u32_t*)vb->value; snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr); break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): raw_ptr = (u8_t*)vb->value; snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr); break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr); break; default: /* unsupported type */ break; }; ofs += vb->vlen; vb = vb->next; } return ofs; }
/** * Encodes trap header from head to tail. */ static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p) { u16_t ofs; ofs = 0; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen); ofs += m_trap->thl.seqlenlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen); ofs += m_trap->thl.verlenlen; snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version); ofs += m_trap->thl.verlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen); ofs += m_trap->thl.comlenlen; snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]); ofs += m_trap->thl.comlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen); ofs += m_trap->thl.pdulenlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen); ofs += m_trap->thl.eidlenlen; snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]); ofs += m_trap->thl.eidlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen); ofs += m_trap->thl.aaddrlenlen; snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]); ofs += m_trap->thl.aaddrlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen); ofs += m_trap->thl.gtrplenlen; snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap); ofs += m_trap->thl.gtrplen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen); ofs += m_trap->thl.strplenlen; snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap); ofs += m_trap->thl.strplen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen); ofs += m_trap->thl.tslenlen; snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts); ofs += m_trap->thl.tslen; return ofs; }
static err_t snmp_complete_outbound_frame(struct snmp_request *request) { struct snmp_asn1_tlv tlv; u16_t frame_size; if (request->version == SNMP_VERSION_1) { if (request->error_status != SNMP_ERR_NOERROR) { /* map v2c error codes to v1 compliant error code (according to RFC 2089) */ switch (request->error_status) { /* mapping of implementation specific "virtual" error codes * (during processing of frame we already stored them in error_status field, * so no need to check all varbinds here for those exceptions as suggested by RFC) */ case SNMP_ERR_NOSUCHINSTANCE: case SNMP_ERR_NOSUCHOBJECT: case SNMP_ERR_ENDOFMIBVIEW: request->error_status = SNMP_ERR_NOSUCHNAME; break; /* mapping according to RFC */ case SNMP_ERR_WRONGVALUE: case SNMP_ERR_WRONGENCODING: case SNMP_ERR_WRONGTYPE: case SNMP_ERR_WRONGLENGTH: case SNMP_ERR_INCONSISTENTVALUE: request->error_status = SNMP_ERR_BADVALUE; break; case SNMP_ERR_NOACCESS: case SNMP_ERR_NOTWRITABLE: case SNMP_ERR_NOCREATION: case SNMP_ERR_INCONSISTENTNAME: case SNMP_ERR_AUTHORIZATIONERROR: request->error_status = SNMP_ERR_NOSUCHNAME; break; case SNMP_ERR_RESOURCEUNAVAILABLE: case SNMP_ERR_COMMITFAILED: case SNMP_ERR_UNDOFAILED: default: request->error_status = SNMP_ERR_GENERROR; break; } } } else { if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) { /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */ LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n")); return ERR_ABRT; } } if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) { /* all inbound vars are returned in response without any modification for error responses and successful set requests*/ struct snmp_pbuf_stream inbound_stream; OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) ); OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, request->outbound_varbind_offset, request->outbound_pbuf->tot_len - request->outbound_varbind_offset) ); snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0); } frame_size = request->outbound_pbuf_stream.offset; /* complete mssing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) ); OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); /* complete mssing length in 'PDU' sequence */ SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) ); OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); /* process and encode final error status */ if (request->error_status != 0) { u16_t len; snmp_asn1_enc_s32t_cnt(request->error_status, &len); if (len != 1) { /* error, we only reserved one byte for it */ return ERR_ABRT; } OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) ); OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) ); /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */ switch (request->error_status) { case SNMP_ERR_TOOBIG: snmp_stats.outtoobigs++; break; case SNMP_ERR_NOSUCHNAME: snmp_stats.outnosuchnames++; break; case SNMP_ERR_BADVALUE: snmp_stats.outbadvalues++; break; case SNMP_ERR_GENERROR: default: snmp_stats.outgenerrs++; break; } if (request->error_status == SNMP_ERR_TOOBIG) { request->error_index = 0; /* defined by RFC 1157 */ } else if (request->error_index == 0) { /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */ request->error_index = request->inbound_varbind_enumerator.varbind_count; } } else { if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count; } else { snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count; } } /* encode final error index*/ if (request->error_index != 0) { u16_t len; snmp_asn1_enc_s32t_cnt(request->error_index, &len); if (len != 1) { /* error, we only reserved one byte for it */ return ERR_VAL; } OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) ); OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) ); } /* complete mssing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset); OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_varbind_offset - 1 - 3) ); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); pbuf_realloc(request->outbound_pbuf, frame_size); snmp_stats.outgetresponses++; snmp_stats.outpkts++; return ERR_OK; }
static err_t snmp_append_outbound_varbind(struct snmp_request *request, struct snmp_varbind* varbind) { struct snmp_asn1_tlv tlv; u8_t vb_len_len, oid_len_len, value_len_len; u16_t vb_value_len, oid_value_len, value_value_len; /* calculate required lengths */ snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &oid_value_len); snmp_asn1_enc_length_cnt(oid_value_len, &oid_len_len); if (varbind->value_len == 0) { value_value_len = 0; } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA); } else { switch (varbind->type) { case SNMP_ASN1_TYPE_INTEGER: if (varbind->value_len != sizeof(s32_t)) { return ERR_VAL; } snmp_asn1_enc_s32t_cnt(*((s32_t*)varbind->value) , &value_value_len); break; case SNMP_ASN1_TYPE_COUNTER: case SNMP_ASN1_TYPE_GAUGE: case SNMP_ASN1_TYPE_TIMETICKS: if (varbind->value_len != sizeof(u32_t)) { return ERR_VAL; } snmp_asn1_enc_u32t_cnt(*((u32_t*)varbind->value) , &value_value_len); break; case SNMP_ASN1_TYPE_OCTET_STRING: case SNMP_ASN1_TYPE_IPADDR: case SNMP_ASN1_TYPE_OPAQUE: value_value_len = varbind->value_len; break; case SNMP_ASN1_TYPE_NULL: if (varbind->value_len != 0) { return ERR_VAL; } value_value_len = 0; break; case SNMP_ASN1_TYPE_OBJECT_ID: if ((varbind->value_len % sizeof(u32_t)) != 0) { return ERR_VAL; } snmp_asn1_enc_oid_cnt((u32_t*)varbind->value, varbind->value_len / sizeof(u32_t), &value_value_len); break; case SNMP_ASN1_TYPE_COUNTER64: if (varbind->value_len != (2 * sizeof(u32_t))) { return ERR_VAL; } snmp_asn1_enc_u64t_cnt((u32_t*)varbind->value , &value_value_len); break; default: /* unsupported type */ return ERR_VAL; } } snmp_asn1_enc_length_cnt(value_value_len, &value_len_len); vb_value_len = 1 + oid_len_len + oid_value_len + 1 + value_len_len + value_value_len; snmp_asn1_enc_length_cnt(vb_value_len, &vb_len_len); /* check length already before adding first data because in case of GetBulk, * data added so far is returned and therefore no partial data shall be added */ if ((1 + vb_len_len + vb_value_len) > request->outbound_pbuf_stream.length) { return ERR_BUF; } /* 'VarBind' sequence */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, vb_len_len, vb_value_len); OVB_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); /* VarBind OID */ SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, oid_len_len, oid_value_len); OVB_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); OVB_BUILD_EXEC( snmp_asn1_enc_oid(&(request->outbound_pbuf_stream), varbind->oid.id, varbind->oid.len) ); /* VarBind value */ SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, value_len_len, value_value_len); OVB_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); if (value_value_len > 0) { if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { OVB_BUILD_EXEC( snmp_asn1_enc_raw(&(request->outbound_pbuf_stream), (u8_t*)varbind->value, value_value_len) ); } else { switch (varbind->type) { case SNMP_ASN1_TYPE_INTEGER: OVB_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), value_value_len, *((s32_t*)varbind->value)) ); break; case SNMP_ASN1_TYPE_COUNTER: case SNMP_ASN1_TYPE_GAUGE: case SNMP_ASN1_TYPE_TIMETICKS: OVB_BUILD_EXEC( snmp_asn1_enc_u32t(&(request->outbound_pbuf_stream), value_value_len, *((u32_t*)varbind->value)) ); break; case SNMP_ASN1_TYPE_OCTET_STRING: case SNMP_ASN1_TYPE_IPADDR: case SNMP_ASN1_TYPE_OPAQUE: OVB_BUILD_EXEC( snmp_asn1_enc_raw(&(request->outbound_pbuf_stream), (u8_t*)varbind->value, value_value_len) ); value_value_len = varbind->value_len; break; case SNMP_ASN1_TYPE_OBJECT_ID: OVB_BUILD_EXEC( snmp_asn1_enc_oid(&(request->outbound_pbuf_stream), (u32_t*)varbind->value, varbind->value_len / sizeof(u32_t)) ); break; case SNMP_ASN1_TYPE_COUNTER64: OVB_BUILD_EXEC( snmp_asn1_enc_u64t(&(request->outbound_pbuf_stream), value_value_len, (u32_t*)varbind->value) ); break; default: LWIP_ASSERT("Unknown variable type", 0); break; } } } return ERR_OK; }