/** * Sums varbind lengths from tail to head and * annotates lengths in varbind for second encoding pass. * * @param root points to the root of the variable binding list * @return the required length for encoding the variable bindings */ static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root) { struct snmp_varbind *vb; u32_t *uint_ptr; s32_t *sint_ptr; u16_t tot_len; tot_len = 0; vb = root->tail; while (vb != NULL) { /* encoded value lenght depends on type */ switch (vb->value_type) { case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen); 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_cnt(*uint_ptr, &vb->vlen); break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): vb->vlen = vb->value_len; break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen); break; default: /* unsupported type */ vb->vlen = 0; break; } /* encoding length of value length field */ snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen); snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen); snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen); vb->seqlen = 1 + vb->vlenlen + vb->vlen; vb->seqlen += 1 + vb->olenlen + vb->olen; snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen); /* varbind seq */ tot_len += 1 + vb->seqlenlen + vb->seqlen; vb = vb->prev; } /* varbind-list seq */ root->seqlen = tot_len; snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen); tot_len += 1 + root->seqlenlen; return tot_len; }
/** * Sums trap header field lengths from tail to head and * returns trap_header_lengths for second encoding pass. * * @param vb_len varbind-list length * @param thl points to returned header lengths * @return the required length for encoding the trap header */ static u16_t snmp_trap_header_sum(struct snmp_msg_trap *trap) { u16_t tot_len; u16_t len; u8_t lenlen; tot_len = 0; snmp_asn1_enc_u32t_cnt(trap->ts, &len); snmp_asn1_enc_length_cnt(len, &lenlen); tot_len += 1 + len + lenlen; snmp_asn1_enc_s32t_cnt(trap->spc_trap, &len); snmp_asn1_enc_length_cnt(len, &lenlen); tot_len += 1 + len + lenlen; snmp_asn1_enc_s32t_cnt(trap->gen_trap, &len); snmp_asn1_enc_length_cnt(len, &lenlen); tot_len += 1 + len + lenlen; if(IP_IS_V6_VAL(trap->sip)) { #if LWIP_IPV6 len = sizeof(ip_2_ip6(&trap->sip)->addr); #endif } else { #if LWIP_IPV4 len = sizeof(ip_2_ip4(&trap->sip)->addr); #endif } snmp_asn1_enc_length_cnt(len, &lenlen); tot_len += 1 + len + lenlen; snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &len); snmp_asn1_enc_length_cnt(len, &lenlen); tot_len += 1 + len + lenlen; trap->pdulen = tot_len; snmp_asn1_enc_length_cnt(trap->pdulen, &lenlen); tot_len += 1 + lenlen; trap->comlen = (u16_t)strlen(snmp_community_trap); snmp_asn1_enc_length_cnt(trap->comlen, &lenlen); tot_len += 1 + lenlen + trap->comlen; snmp_asn1_enc_s32t_cnt(trap->snmp_version, &len); snmp_asn1_enc_length_cnt(len, &lenlen); tot_len += 1 + len + lenlen; trap->seqlen = tot_len; snmp_asn1_enc_length_cnt(trap->seqlen, &lenlen); tot_len += 1 + lenlen; return tot_len; }
/** * Sums trap header field lengths from tail to head and * returns trap_header_lengths for second encoding pass. * * @param vb_len varbind-list length * @param thl points to returned header lengths * @return the required lenght for encoding the trap header */ static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len) { u16_t tot_len; struct snmp_trap_header_lengths *thl; thl = &m_trap->thl; tot_len = vb_len; snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen); snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen); tot_len += 1 + thl->tslen + thl->tslenlen; snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen); snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen); tot_len += 1 + thl->strplen + thl->strplenlen; snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen); snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen); tot_len += 1 + thl->gtrplen + thl->gtrplenlen; thl->aaddrlen = 4; snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen); tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen; snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen); snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen); tot_len += 1 + thl->eidlen + thl->eidlenlen; thl->pdulen = tot_len; snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen); tot_len += 1 + thl->pdulenlen; thl->comlen = sizeof(snmp_publiccommunity) - 1; snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen); tot_len += 1 + thl->comlenlen + thl->comlen; snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen); snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen); tot_len += 1 + thl->verlen + thl->verlenlen; thl->seqlen = tot_len; snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen); tot_len += 1 + thl->seqlenlen; return tot_len; }
/** * 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); }
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; }