1*5d5fbe79SDavid van Moolenbroek /**
2*5d5fbe79SDavid van Moolenbroek * @file
3*5d5fbe79SDavid van Moolenbroek * Abstract Syntax Notation One (ISO 8824, 8825) encoding
4*5d5fbe79SDavid van Moolenbroek *
5*5d5fbe79SDavid van Moolenbroek * @todo not optimised (yet), favor correctness over speed, favor speed over size
6*5d5fbe79SDavid van Moolenbroek */
7*5d5fbe79SDavid van Moolenbroek
8*5d5fbe79SDavid van Moolenbroek /*
9*5d5fbe79SDavid van Moolenbroek * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
10*5d5fbe79SDavid van Moolenbroek * All rights reserved.
11*5d5fbe79SDavid van Moolenbroek *
12*5d5fbe79SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without modification,
13*5d5fbe79SDavid van Moolenbroek * are permitted provided that the following conditions are met:
14*5d5fbe79SDavid van Moolenbroek *
15*5d5fbe79SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright notice,
16*5d5fbe79SDavid van Moolenbroek * this list of conditions and the following disclaimer.
17*5d5fbe79SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright notice,
18*5d5fbe79SDavid van Moolenbroek * this list of conditions and the following disclaimer in the documentation
19*5d5fbe79SDavid van Moolenbroek * and/or other materials provided with the distribution.
20*5d5fbe79SDavid van Moolenbroek * 3. The name of the author may not be used to endorse or promote products
21*5d5fbe79SDavid van Moolenbroek * derived from this software without specific prior written permission.
22*5d5fbe79SDavid van Moolenbroek *
23*5d5fbe79SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
24*5d5fbe79SDavid van Moolenbroek * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25*5d5fbe79SDavid van Moolenbroek * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
26*5d5fbe79SDavid van Moolenbroek * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27*5d5fbe79SDavid van Moolenbroek * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
28*5d5fbe79SDavid van Moolenbroek * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29*5d5fbe79SDavid van Moolenbroek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30*5d5fbe79SDavid van Moolenbroek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
31*5d5fbe79SDavid van Moolenbroek * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32*5d5fbe79SDavid van Moolenbroek * OF SUCH DAMAGE.
33*5d5fbe79SDavid van Moolenbroek *
34*5d5fbe79SDavid van Moolenbroek * Author: Christiaan Simons <christiaan.simons@axon.tv>
35*5d5fbe79SDavid van Moolenbroek * Martin Hentschel <info@cl-soft.de>
36*5d5fbe79SDavid van Moolenbroek */
37*5d5fbe79SDavid van Moolenbroek
38*5d5fbe79SDavid van Moolenbroek #include "lwip/apps/snmp_opts.h"
39*5d5fbe79SDavid van Moolenbroek
40*5d5fbe79SDavid van Moolenbroek #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
41*5d5fbe79SDavid van Moolenbroek
42*5d5fbe79SDavid van Moolenbroek #include "snmp_asn1.h"
43*5d5fbe79SDavid van Moolenbroek
44*5d5fbe79SDavid van Moolenbroek #define PBUF_OP_EXEC(code) \
45*5d5fbe79SDavid van Moolenbroek if ((code) != ERR_OK) { \
46*5d5fbe79SDavid van Moolenbroek return ERR_BUF; \
47*5d5fbe79SDavid van Moolenbroek }
48*5d5fbe79SDavid van Moolenbroek
49*5d5fbe79SDavid van Moolenbroek /**
50*5d5fbe79SDavid van Moolenbroek * Encodes a TLV into a pbuf stream.
51*5d5fbe79SDavid van Moolenbroek *
52*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
53*5d5fbe79SDavid van Moolenbroek * @param tlv TLV to encode
54*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
55*5d5fbe79SDavid van Moolenbroek */
56*5d5fbe79SDavid van Moolenbroek err_t
snmp_ans1_enc_tlv(struct snmp_pbuf_stream * pbuf_stream,struct snmp_asn1_tlv * tlv)57*5d5fbe79SDavid van Moolenbroek snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
58*5d5fbe79SDavid van Moolenbroek {
59*5d5fbe79SDavid van Moolenbroek u8_t data;
60*5d5fbe79SDavid van Moolenbroek u8_t length_bytes_required;
61*5d5fbe79SDavid van Moolenbroek
62*5d5fbe79SDavid van Moolenbroek /* write type */
63*5d5fbe79SDavid van Moolenbroek if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
64*5d5fbe79SDavid van Moolenbroek /* extended format is not used by SNMP so we do not accept those values */
65*5d5fbe79SDavid van Moolenbroek return ERR_ARG;
66*5d5fbe79SDavid van Moolenbroek }
67*5d5fbe79SDavid van Moolenbroek if (tlv->type_len != 0) {
68*5d5fbe79SDavid van Moolenbroek /* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */
69*5d5fbe79SDavid van Moolenbroek return ERR_ARG;
70*5d5fbe79SDavid van Moolenbroek }
71*5d5fbe79SDavid van Moolenbroek
72*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type));
73*5d5fbe79SDavid van Moolenbroek tlv->type_len = 1;
74*5d5fbe79SDavid van Moolenbroek
75*5d5fbe79SDavid van Moolenbroek /* write length */
76*5d5fbe79SDavid van Moolenbroek if (tlv->value_len <= 127) {
77*5d5fbe79SDavid van Moolenbroek length_bytes_required = 1;
78*5d5fbe79SDavid van Moolenbroek } else if (tlv->value_len <= 255) {
79*5d5fbe79SDavid van Moolenbroek length_bytes_required = 2;
80*5d5fbe79SDavid van Moolenbroek } else {
81*5d5fbe79SDavid van Moolenbroek length_bytes_required = 3;
82*5d5fbe79SDavid van Moolenbroek }
83*5d5fbe79SDavid van Moolenbroek
84*5d5fbe79SDavid van Moolenbroek /* check for forced min length */
85*5d5fbe79SDavid van Moolenbroek if (tlv->length_len > 0) {
86*5d5fbe79SDavid van Moolenbroek if (tlv->length_len < length_bytes_required) {
87*5d5fbe79SDavid van Moolenbroek /* unable to code requested length in requested number of bytes */
88*5d5fbe79SDavid van Moolenbroek return ERR_ARG;
89*5d5fbe79SDavid van Moolenbroek }
90*5d5fbe79SDavid van Moolenbroek
91*5d5fbe79SDavid van Moolenbroek length_bytes_required = tlv->length_len;
92*5d5fbe79SDavid van Moolenbroek } else {
93*5d5fbe79SDavid van Moolenbroek tlv->length_len = length_bytes_required;
94*5d5fbe79SDavid van Moolenbroek }
95*5d5fbe79SDavid van Moolenbroek
96*5d5fbe79SDavid van Moolenbroek if (length_bytes_required > 1) {
97*5d5fbe79SDavid van Moolenbroek /* multi byte representation required */
98*5d5fbe79SDavid van Moolenbroek length_bytes_required--;
99*5d5fbe79SDavid van Moolenbroek data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */
100*5d5fbe79SDavid van Moolenbroek
101*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
102*5d5fbe79SDavid van Moolenbroek
103*5d5fbe79SDavid van Moolenbroek while (length_bytes_required > 1) {
104*5d5fbe79SDavid van Moolenbroek if (length_bytes_required == 2) {
105*5d5fbe79SDavid van Moolenbroek /* append high byte */
106*5d5fbe79SDavid van Moolenbroek data = (u8_t)(tlv->value_len >> 8);
107*5d5fbe79SDavid van Moolenbroek } else {
108*5d5fbe79SDavid van Moolenbroek /* append leading 0x00 */
109*5d5fbe79SDavid van Moolenbroek data = 0x00;
110*5d5fbe79SDavid van Moolenbroek }
111*5d5fbe79SDavid van Moolenbroek
112*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
113*5d5fbe79SDavid van Moolenbroek length_bytes_required--;
114*5d5fbe79SDavid van Moolenbroek }
115*5d5fbe79SDavid van Moolenbroek }
116*5d5fbe79SDavid van Moolenbroek
117*5d5fbe79SDavid van Moolenbroek /* append low byte */
118*5d5fbe79SDavid van Moolenbroek data = (u8_t)(tlv->value_len & 0xFF);
119*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
120*5d5fbe79SDavid van Moolenbroek
121*5d5fbe79SDavid van Moolenbroek return ERR_OK;
122*5d5fbe79SDavid van Moolenbroek }
123*5d5fbe79SDavid van Moolenbroek
124*5d5fbe79SDavid van Moolenbroek /**
125*5d5fbe79SDavid van Moolenbroek * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
126*5d5fbe79SDavid van Moolenbroek *
127*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
128*5d5fbe79SDavid van Moolenbroek * @param raw_len raw data length
129*5d5fbe79SDavid van Moolenbroek * @param raw points raw data
130*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
131*5d5fbe79SDavid van Moolenbroek */
132*5d5fbe79SDavid van Moolenbroek err_t
snmp_asn1_enc_raw(struct snmp_pbuf_stream * pbuf_stream,const u8_t * raw,u16_t raw_len)133*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len)
134*5d5fbe79SDavid van Moolenbroek {
135*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len));
136*5d5fbe79SDavid van Moolenbroek
137*5d5fbe79SDavid van Moolenbroek return ERR_OK;
138*5d5fbe79SDavid van Moolenbroek }
139*5d5fbe79SDavid van Moolenbroek
140*5d5fbe79SDavid van Moolenbroek /**
141*5d5fbe79SDavid van Moolenbroek * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
142*5d5fbe79SDavid van Moolenbroek *
143*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
144*5d5fbe79SDavid van Moolenbroek * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
145*5d5fbe79SDavid van Moolenbroek * @param value is the host order u32_t value to be encoded
146*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
147*5d5fbe79SDavid van Moolenbroek *
148*5d5fbe79SDavid van Moolenbroek * @see snmp_asn1_enc_u32t_cnt()
149*5d5fbe79SDavid van Moolenbroek */
150*5d5fbe79SDavid van Moolenbroek err_t
snmp_asn1_enc_u32t(struct snmp_pbuf_stream * pbuf_stream,u16_t octets_needed,u32_t value)151*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value)
152*5d5fbe79SDavid van Moolenbroek {
153*5d5fbe79SDavid van Moolenbroek if (octets_needed > 5) {
154*5d5fbe79SDavid van Moolenbroek return ERR_ARG;
155*5d5fbe79SDavid van Moolenbroek }
156*5d5fbe79SDavid van Moolenbroek if (octets_needed == 5) {
157*5d5fbe79SDavid van Moolenbroek /* not enough bits in 'value' add leading 0x00 */
158*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
159*5d5fbe79SDavid van Moolenbroek octets_needed--;
160*5d5fbe79SDavid van Moolenbroek }
161*5d5fbe79SDavid van Moolenbroek
162*5d5fbe79SDavid van Moolenbroek while (octets_needed > 1) {
163*5d5fbe79SDavid van Moolenbroek octets_needed--;
164*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
165*5d5fbe79SDavid van Moolenbroek }
166*5d5fbe79SDavid van Moolenbroek
167*5d5fbe79SDavid van Moolenbroek /* (only) one least significant octet */
168*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
169*5d5fbe79SDavid van Moolenbroek
170*5d5fbe79SDavid van Moolenbroek return ERR_OK;
171*5d5fbe79SDavid van Moolenbroek }
172*5d5fbe79SDavid van Moolenbroek
173*5d5fbe79SDavid van Moolenbroek /**
174*5d5fbe79SDavid van Moolenbroek * Encodes u64_t (counter64) into a pbuf chained ASN1 msg.
175*5d5fbe79SDavid van Moolenbroek *
176*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
177*5d5fbe79SDavid van Moolenbroek * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
178*5d5fbe79SDavid van Moolenbroek * @param value is the host order u32_t value to be encoded
179*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
180*5d5fbe79SDavid van Moolenbroek *
181*5d5fbe79SDavid van Moolenbroek * @see snmp_asn1_enc_u64t_cnt()
182*5d5fbe79SDavid van Moolenbroek */
183*5d5fbe79SDavid van Moolenbroek err_t
snmp_asn1_enc_u64t(struct snmp_pbuf_stream * pbuf_stream,u16_t octets_needed,const u32_t * value)184*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value)
185*5d5fbe79SDavid van Moolenbroek {
186*5d5fbe79SDavid van Moolenbroek if (octets_needed > 9) {
187*5d5fbe79SDavid van Moolenbroek return ERR_ARG;
188*5d5fbe79SDavid van Moolenbroek }
189*5d5fbe79SDavid van Moolenbroek if (octets_needed == 9) {
190*5d5fbe79SDavid van Moolenbroek /* not enough bits in 'value' add leading 0x00 */
191*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
192*5d5fbe79SDavid van Moolenbroek octets_needed--;
193*5d5fbe79SDavid van Moolenbroek }
194*5d5fbe79SDavid van Moolenbroek
195*5d5fbe79SDavid van Moolenbroek while (octets_needed > 4) {
196*5d5fbe79SDavid van Moolenbroek octets_needed--;
197*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> ((octets_needed-4) << 3))));
198*5d5fbe79SDavid van Moolenbroek }
199*5d5fbe79SDavid van Moolenbroek
200*5d5fbe79SDavid van Moolenbroek /* skip to low u32 */
201*5d5fbe79SDavid van Moolenbroek value++;
202*5d5fbe79SDavid van Moolenbroek
203*5d5fbe79SDavid van Moolenbroek while (octets_needed > 1) {
204*5d5fbe79SDavid van Moolenbroek octets_needed--;
205*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> (octets_needed << 3))));
206*5d5fbe79SDavid van Moolenbroek }
207*5d5fbe79SDavid van Moolenbroek
208*5d5fbe79SDavid van Moolenbroek /* always write at least one octet (also in case of value == 0) */
209*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value)));
210*5d5fbe79SDavid van Moolenbroek
211*5d5fbe79SDavid van Moolenbroek return ERR_OK;
212*5d5fbe79SDavid van Moolenbroek }
213*5d5fbe79SDavid van Moolenbroek
214*5d5fbe79SDavid van Moolenbroek /**
215*5d5fbe79SDavid van Moolenbroek * Encodes s32_t integer into a pbuf chained ASN1 msg.
216*5d5fbe79SDavid van Moolenbroek *
217*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
218*5d5fbe79SDavid van Moolenbroek * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
219*5d5fbe79SDavid van Moolenbroek * @param value is the host order s32_t value to be encoded
220*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
221*5d5fbe79SDavid van Moolenbroek *
222*5d5fbe79SDavid van Moolenbroek * @see snmp_asn1_enc_s32t_cnt()
223*5d5fbe79SDavid van Moolenbroek */
224*5d5fbe79SDavid van Moolenbroek err_t
snmp_asn1_enc_s32t(struct snmp_pbuf_stream * pbuf_stream,u16_t octets_needed,s32_t value)225*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value)
226*5d5fbe79SDavid van Moolenbroek {
227*5d5fbe79SDavid van Moolenbroek while (octets_needed > 1) {
228*5d5fbe79SDavid van Moolenbroek octets_needed--;
229*5d5fbe79SDavid van Moolenbroek
230*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
231*5d5fbe79SDavid van Moolenbroek }
232*5d5fbe79SDavid van Moolenbroek
233*5d5fbe79SDavid van Moolenbroek /* (only) one least significant octet */
234*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
235*5d5fbe79SDavid van Moolenbroek
236*5d5fbe79SDavid van Moolenbroek return ERR_OK;
237*5d5fbe79SDavid van Moolenbroek }
238*5d5fbe79SDavid van Moolenbroek
239*5d5fbe79SDavid van Moolenbroek /**
240*5d5fbe79SDavid van Moolenbroek * Encodes object identifier into a pbuf chained ASN1 msg.
241*5d5fbe79SDavid van Moolenbroek *
242*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
243*5d5fbe79SDavid van Moolenbroek * @param oid points to object identifier array
244*5d5fbe79SDavid van Moolenbroek * @param oid_len object identifier array length
245*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
246*5d5fbe79SDavid van Moolenbroek */
247*5d5fbe79SDavid van Moolenbroek err_t
snmp_asn1_enc_oid(struct snmp_pbuf_stream * pbuf_stream,const u32_t * oid,u16_t oid_len)248*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len)
249*5d5fbe79SDavid van Moolenbroek {
250*5d5fbe79SDavid van Moolenbroek if (oid_len > 1) {
251*5d5fbe79SDavid van Moolenbroek /* write compressed first two sub id's */
252*5d5fbe79SDavid van Moolenbroek u32_t compressed_byte = ((oid[0] * 40) + oid[1]);
253*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte));
254*5d5fbe79SDavid van Moolenbroek oid_len -= 2;
255*5d5fbe79SDavid van Moolenbroek oid += 2;
256*5d5fbe79SDavid van Moolenbroek } else {
257*5d5fbe79SDavid van Moolenbroek /* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
258*5d5fbe79SDavid van Moolenbroek /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
259*5d5fbe79SDavid van Moolenbroek return ERR_ARG;
260*5d5fbe79SDavid van Moolenbroek }
261*5d5fbe79SDavid van Moolenbroek
262*5d5fbe79SDavid van Moolenbroek while (oid_len > 0) {
263*5d5fbe79SDavid van Moolenbroek u32_t sub_id;
264*5d5fbe79SDavid van Moolenbroek u8_t shift, tail;
265*5d5fbe79SDavid van Moolenbroek
266*5d5fbe79SDavid van Moolenbroek oid_len--;
267*5d5fbe79SDavid van Moolenbroek sub_id = *oid;
268*5d5fbe79SDavid van Moolenbroek tail = 0;
269*5d5fbe79SDavid van Moolenbroek shift = 28;
270*5d5fbe79SDavid van Moolenbroek while (shift > 0) {
271*5d5fbe79SDavid van Moolenbroek u8_t code;
272*5d5fbe79SDavid van Moolenbroek
273*5d5fbe79SDavid van Moolenbroek code = (u8_t)(sub_id >> shift);
274*5d5fbe79SDavid van Moolenbroek if ((code != 0) || (tail != 0)) {
275*5d5fbe79SDavid van Moolenbroek tail = 1;
276*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80));
277*5d5fbe79SDavid van Moolenbroek }
278*5d5fbe79SDavid van Moolenbroek shift -= 7;
279*5d5fbe79SDavid van Moolenbroek }
280*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F));
281*5d5fbe79SDavid van Moolenbroek
282*5d5fbe79SDavid van Moolenbroek /* proceed to next sub-identifier */
283*5d5fbe79SDavid van Moolenbroek oid++;
284*5d5fbe79SDavid van Moolenbroek }
285*5d5fbe79SDavid van Moolenbroek return ERR_OK;
286*5d5fbe79SDavid van Moolenbroek }
287*5d5fbe79SDavid van Moolenbroek
288*5d5fbe79SDavid van Moolenbroek /**
289*5d5fbe79SDavid van Moolenbroek * Returns octet count for length.
290*5d5fbe79SDavid van Moolenbroek *
291*5d5fbe79SDavid van Moolenbroek * @param length parameter length
292*5d5fbe79SDavid van Moolenbroek * @param octets_needed points to the return value
293*5d5fbe79SDavid van Moolenbroek */
294*5d5fbe79SDavid van Moolenbroek void
snmp_asn1_enc_length_cnt(u16_t length,u8_t * octets_needed)295*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
296*5d5fbe79SDavid van Moolenbroek {
297*5d5fbe79SDavid van Moolenbroek if (length < 0x80U) {
298*5d5fbe79SDavid van Moolenbroek *octets_needed = 1;
299*5d5fbe79SDavid van Moolenbroek } else if (length < 0x100U) {
300*5d5fbe79SDavid van Moolenbroek *octets_needed = 2;
301*5d5fbe79SDavid van Moolenbroek } else {
302*5d5fbe79SDavid van Moolenbroek *octets_needed = 3;
303*5d5fbe79SDavid van Moolenbroek }
304*5d5fbe79SDavid van Moolenbroek }
305*5d5fbe79SDavid van Moolenbroek
306*5d5fbe79SDavid van Moolenbroek /**
307*5d5fbe79SDavid van Moolenbroek * Returns octet count for an u32_t.
308*5d5fbe79SDavid van Moolenbroek *
309*5d5fbe79SDavid van Moolenbroek * @param value value to be encoded
310*5d5fbe79SDavid van Moolenbroek * @param octets_needed points to the return value
311*5d5fbe79SDavid van Moolenbroek *
312*5d5fbe79SDavid van Moolenbroek * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
313*5d5fbe79SDavid van Moolenbroek * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
314*5d5fbe79SDavid van Moolenbroek * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
315*5d5fbe79SDavid van Moolenbroek */
316*5d5fbe79SDavid van Moolenbroek void
snmp_asn1_enc_u32t_cnt(u32_t value,u16_t * octets_needed)317*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
318*5d5fbe79SDavid van Moolenbroek {
319*5d5fbe79SDavid van Moolenbroek if (value < 0x80UL) {
320*5d5fbe79SDavid van Moolenbroek *octets_needed = 1;
321*5d5fbe79SDavid van Moolenbroek } else if (value < 0x8000UL) {
322*5d5fbe79SDavid van Moolenbroek *octets_needed = 2;
323*5d5fbe79SDavid van Moolenbroek } else if (value < 0x800000UL) {
324*5d5fbe79SDavid van Moolenbroek *octets_needed = 3;
325*5d5fbe79SDavid van Moolenbroek } else if (value < 0x80000000UL) {
326*5d5fbe79SDavid van Moolenbroek *octets_needed = 4;
327*5d5fbe79SDavid van Moolenbroek } else {
328*5d5fbe79SDavid van Moolenbroek *octets_needed = 5;
329*5d5fbe79SDavid van Moolenbroek }
330*5d5fbe79SDavid van Moolenbroek }
331*5d5fbe79SDavid van Moolenbroek
332*5d5fbe79SDavid van Moolenbroek /**
333*5d5fbe79SDavid van Moolenbroek * Returns octet count for an u64_t.
334*5d5fbe79SDavid van Moolenbroek *
335*5d5fbe79SDavid van Moolenbroek * @param value value to be encoded
336*5d5fbe79SDavid van Moolenbroek * @param octets_needed points to the return value
337*5d5fbe79SDavid van Moolenbroek *
338*5d5fbe79SDavid van Moolenbroek * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
339*5d5fbe79SDavid van Moolenbroek * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
340*5d5fbe79SDavid van Moolenbroek * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
341*5d5fbe79SDavid van Moolenbroek */
342*5d5fbe79SDavid van Moolenbroek void
snmp_asn1_enc_u64t_cnt(const u32_t * value,u16_t * octets_needed)343*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed)
344*5d5fbe79SDavid van Moolenbroek {
345*5d5fbe79SDavid van Moolenbroek /* check if high u32 is 0 */
346*5d5fbe79SDavid van Moolenbroek if (*value == 0x00) {
347*5d5fbe79SDavid van Moolenbroek /* only low u32 is important */
348*5d5fbe79SDavid van Moolenbroek value++;
349*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_u32t_cnt(*value, octets_needed);
350*5d5fbe79SDavid van Moolenbroek } else {
351*5d5fbe79SDavid van Moolenbroek /* low u32 does not matter for length determination */
352*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_u32t_cnt(*value, octets_needed);
353*5d5fbe79SDavid van Moolenbroek *octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */
354*5d5fbe79SDavid van Moolenbroek }
355*5d5fbe79SDavid van Moolenbroek }
356*5d5fbe79SDavid van Moolenbroek
357*5d5fbe79SDavid van Moolenbroek /**
358*5d5fbe79SDavid van Moolenbroek * Returns octet count for an s32_t.
359*5d5fbe79SDavid van Moolenbroek *
360*5d5fbe79SDavid van Moolenbroek * @param value value to be encoded
361*5d5fbe79SDavid van Moolenbroek * @param octets_needed points to the return value
362*5d5fbe79SDavid van Moolenbroek *
363*5d5fbe79SDavid van Moolenbroek * @note ASN coded integers are _always_ signed.
364*5d5fbe79SDavid van Moolenbroek */
365*5d5fbe79SDavid van Moolenbroek void
snmp_asn1_enc_s32t_cnt(s32_t value,u16_t * octets_needed)366*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
367*5d5fbe79SDavid van Moolenbroek {
368*5d5fbe79SDavid van Moolenbroek if (value < 0) {
369*5d5fbe79SDavid van Moolenbroek value = ~value;
370*5d5fbe79SDavid van Moolenbroek }
371*5d5fbe79SDavid van Moolenbroek if (value < 0x80L) {
372*5d5fbe79SDavid van Moolenbroek *octets_needed = 1;
373*5d5fbe79SDavid van Moolenbroek } else if (value < 0x8000L) {
374*5d5fbe79SDavid van Moolenbroek *octets_needed = 2;
375*5d5fbe79SDavid van Moolenbroek } else if (value < 0x800000L) {
376*5d5fbe79SDavid van Moolenbroek *octets_needed = 3;
377*5d5fbe79SDavid van Moolenbroek } else {
378*5d5fbe79SDavid van Moolenbroek *octets_needed = 4;
379*5d5fbe79SDavid van Moolenbroek }
380*5d5fbe79SDavid van Moolenbroek }
381*5d5fbe79SDavid van Moolenbroek
382*5d5fbe79SDavid van Moolenbroek /**
383*5d5fbe79SDavid van Moolenbroek * Returns octet count for an object identifier.
384*5d5fbe79SDavid van Moolenbroek *
385*5d5fbe79SDavid van Moolenbroek * @param oid points to object identifier array
386*5d5fbe79SDavid van Moolenbroek * @param oid_len object identifier array length
387*5d5fbe79SDavid van Moolenbroek * @param octets_needed points to the return value
388*5d5fbe79SDavid van Moolenbroek */
389*5d5fbe79SDavid van Moolenbroek void
snmp_asn1_enc_oid_cnt(const u32_t * oid,u16_t oid_len,u16_t * octets_needed)390*5d5fbe79SDavid van Moolenbroek snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed)
391*5d5fbe79SDavid van Moolenbroek {
392*5d5fbe79SDavid van Moolenbroek u32_t sub_id;
393*5d5fbe79SDavid van Moolenbroek
394*5d5fbe79SDavid van Moolenbroek *octets_needed = 0;
395*5d5fbe79SDavid van Moolenbroek if (oid_len > 1) {
396*5d5fbe79SDavid van Moolenbroek /* compressed prefix in one octet */
397*5d5fbe79SDavid van Moolenbroek (*octets_needed)++;
398*5d5fbe79SDavid van Moolenbroek oid_len -= 2;
399*5d5fbe79SDavid van Moolenbroek oid += 2;
400*5d5fbe79SDavid van Moolenbroek }
401*5d5fbe79SDavid van Moolenbroek while (oid_len > 0) {
402*5d5fbe79SDavid van Moolenbroek oid_len--;
403*5d5fbe79SDavid van Moolenbroek sub_id = *oid;
404*5d5fbe79SDavid van Moolenbroek
405*5d5fbe79SDavid van Moolenbroek sub_id >>= 7;
406*5d5fbe79SDavid van Moolenbroek (*octets_needed)++;
407*5d5fbe79SDavid van Moolenbroek while (sub_id > 0) {
408*5d5fbe79SDavid van Moolenbroek sub_id >>= 7;
409*5d5fbe79SDavid van Moolenbroek (*octets_needed)++;
410*5d5fbe79SDavid van Moolenbroek }
411*5d5fbe79SDavid van Moolenbroek oid++;
412*5d5fbe79SDavid van Moolenbroek }
413*5d5fbe79SDavid van Moolenbroek }
414*5d5fbe79SDavid van Moolenbroek
415*5d5fbe79SDavid van Moolenbroek /**
416*5d5fbe79SDavid van Moolenbroek * Decodes a TLV from a pbuf stream.
417*5d5fbe79SDavid van Moolenbroek *
418*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
419*5d5fbe79SDavid van Moolenbroek * @param tlv returns decoded TLV
420*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_VAL if we can't decode
421*5d5fbe79SDavid van Moolenbroek */
422*5d5fbe79SDavid van Moolenbroek err_t
snmp_asn1_dec_tlv(struct snmp_pbuf_stream * pbuf_stream,struct snmp_asn1_tlv * tlv)423*5d5fbe79SDavid van Moolenbroek snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
424*5d5fbe79SDavid van Moolenbroek {
425*5d5fbe79SDavid van Moolenbroek u8_t data;
426*5d5fbe79SDavid van Moolenbroek
427*5d5fbe79SDavid van Moolenbroek /* decode type first */
428*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
429*5d5fbe79SDavid van Moolenbroek tlv->type = data;
430*5d5fbe79SDavid van Moolenbroek
431*5d5fbe79SDavid van Moolenbroek if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
432*5d5fbe79SDavid van Moolenbroek /* extended format is not used by SNMP so we do not accept those values */
433*5d5fbe79SDavid van Moolenbroek return ERR_VAL;
434*5d5fbe79SDavid van Moolenbroek }
435*5d5fbe79SDavid van Moolenbroek tlv->type_len = 1;
436*5d5fbe79SDavid van Moolenbroek
437*5d5fbe79SDavid van Moolenbroek /* now, decode length */
438*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
439*5d5fbe79SDavid van Moolenbroek
440*5d5fbe79SDavid van Moolenbroek if (data < 0x80) { /* short form */
441*5d5fbe79SDavid van Moolenbroek tlv->length_len = 1;
442*5d5fbe79SDavid van Moolenbroek tlv->value_len = data;
443*5d5fbe79SDavid van Moolenbroek } else if (data > 0x80) { /* long form */
444*5d5fbe79SDavid van Moolenbroek u8_t length_bytes = data - 0x80;
445*5d5fbe79SDavid van Moolenbroek tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */
446*5d5fbe79SDavid van Moolenbroek tlv->value_len = 0;
447*5d5fbe79SDavid van Moolenbroek
448*5d5fbe79SDavid van Moolenbroek while (length_bytes > 0) {
449*5d5fbe79SDavid van Moolenbroek /* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */
450*5d5fbe79SDavid van Moolenbroek if (tlv->value_len > 0xFF) {
451*5d5fbe79SDavid van Moolenbroek return ERR_VAL;
452*5d5fbe79SDavid van Moolenbroek }
453*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
454*5d5fbe79SDavid van Moolenbroek tlv->value_len <<= 8;
455*5d5fbe79SDavid van Moolenbroek tlv->value_len |= data;
456*5d5fbe79SDavid van Moolenbroek
457*5d5fbe79SDavid van Moolenbroek /* take care for special value used for indefinite length */
458*5d5fbe79SDavid van Moolenbroek if (tlv->value_len == 0xFFFF) {
459*5d5fbe79SDavid van Moolenbroek return ERR_VAL;
460*5d5fbe79SDavid van Moolenbroek }
461*5d5fbe79SDavid van Moolenbroek
462*5d5fbe79SDavid van Moolenbroek length_bytes--;
463*5d5fbe79SDavid van Moolenbroek }
464*5d5fbe79SDavid van Moolenbroek } else { /* data == 0x80 indefinite length form */
465*5d5fbe79SDavid van Moolenbroek /* (not allowed for SNMP; RFC 1157, 3.2.2) */
466*5d5fbe79SDavid van Moolenbroek return ERR_VAL;
467*5d5fbe79SDavid van Moolenbroek }
468*5d5fbe79SDavid van Moolenbroek
469*5d5fbe79SDavid van Moolenbroek return ERR_OK;
470*5d5fbe79SDavid van Moolenbroek }
471*5d5fbe79SDavid van Moolenbroek
472*5d5fbe79SDavid van Moolenbroek /**
473*5d5fbe79SDavid van Moolenbroek * Decodes positive integer (counter, gauge, timeticks) into u32_t.
474*5d5fbe79SDavid van Moolenbroek *
475*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
476*5d5fbe79SDavid van Moolenbroek * @param len length of the coded integer field
477*5d5fbe79SDavid van Moolenbroek * @param value return host order integer
478*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
479*5d5fbe79SDavid van Moolenbroek *
480*5d5fbe79SDavid van Moolenbroek * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
481*5d5fbe79SDavid van Moolenbroek * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
482*5d5fbe79SDavid van Moolenbroek * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
483*5d5fbe79SDavid van Moolenbroek */
484*5d5fbe79SDavid van Moolenbroek err_t
snmp_asn1_dec_u32t(struct snmp_pbuf_stream * pbuf_stream,u16_t len,u32_t * value)485*5d5fbe79SDavid van Moolenbroek snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
486*5d5fbe79SDavid van Moolenbroek {
487*5d5fbe79SDavid van Moolenbroek u8_t data;
488*5d5fbe79SDavid van Moolenbroek
489*5d5fbe79SDavid van Moolenbroek if ((len > 0) && (len <= 5)) {
490*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
491*5d5fbe79SDavid van Moolenbroek
492*5d5fbe79SDavid van Moolenbroek /* expecting sign bit to be zero, only unsigned please! */
493*5d5fbe79SDavid van Moolenbroek if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) {
494*5d5fbe79SDavid van Moolenbroek *value = data;
495*5d5fbe79SDavid van Moolenbroek len--;
496*5d5fbe79SDavid van Moolenbroek
497*5d5fbe79SDavid van Moolenbroek while (len > 0) {
498*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
499*5d5fbe79SDavid van Moolenbroek len--;
500*5d5fbe79SDavid van Moolenbroek
501*5d5fbe79SDavid van Moolenbroek *value <<= 8;
502*5d5fbe79SDavid van Moolenbroek *value |= data;
503*5d5fbe79SDavid van Moolenbroek }
504*5d5fbe79SDavid van Moolenbroek
505*5d5fbe79SDavid van Moolenbroek return ERR_OK;
506*5d5fbe79SDavid van Moolenbroek }
507*5d5fbe79SDavid van Moolenbroek }
508*5d5fbe79SDavid van Moolenbroek
509*5d5fbe79SDavid van Moolenbroek return ERR_VAL;
510*5d5fbe79SDavid van Moolenbroek }
511*5d5fbe79SDavid van Moolenbroek
512*5d5fbe79SDavid van Moolenbroek /**
513*5d5fbe79SDavid van Moolenbroek * Decodes large positive integer (counter64) into 2x u32_t.
514*5d5fbe79SDavid van Moolenbroek *
515*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
516*5d5fbe79SDavid van Moolenbroek * @param len length of the coded integer field
517*5d5fbe79SDavid van Moolenbroek * @param value return host order integer
518*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
519*5d5fbe79SDavid van Moolenbroek *
520*5d5fbe79SDavid van Moolenbroek * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
521*5d5fbe79SDavid van Moolenbroek * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
522*5d5fbe79SDavid van Moolenbroek * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
523*5d5fbe79SDavid van Moolenbroek */
524*5d5fbe79SDavid van Moolenbroek err_t
snmp_asn1_dec_u64t(struct snmp_pbuf_stream * pbuf_stream,u16_t len,u32_t * value)525*5d5fbe79SDavid van Moolenbroek snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
526*5d5fbe79SDavid van Moolenbroek {
527*5d5fbe79SDavid van Moolenbroek u8_t data;
528*5d5fbe79SDavid van Moolenbroek
529*5d5fbe79SDavid van Moolenbroek if (len <= 4) {
530*5d5fbe79SDavid van Moolenbroek /* high u32 is 0 */
531*5d5fbe79SDavid van Moolenbroek *value = 0;
532*5d5fbe79SDavid van Moolenbroek /* directly skip to low u32 */
533*5d5fbe79SDavid van Moolenbroek value++;
534*5d5fbe79SDavid van Moolenbroek }
535*5d5fbe79SDavid van Moolenbroek
536*5d5fbe79SDavid van Moolenbroek if ((len > 0) && (len <= 9)) {
537*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
538*5d5fbe79SDavid van Moolenbroek
539*5d5fbe79SDavid van Moolenbroek /* expecting sign bit to be zero, only unsigned please! */
540*5d5fbe79SDavid van Moolenbroek if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) {
541*5d5fbe79SDavid van Moolenbroek *value = data;
542*5d5fbe79SDavid van Moolenbroek len--;
543*5d5fbe79SDavid van Moolenbroek
544*5d5fbe79SDavid van Moolenbroek while (len > 0) {
545*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
546*5d5fbe79SDavid van Moolenbroek
547*5d5fbe79SDavid van Moolenbroek if (len == 4) {
548*5d5fbe79SDavid van Moolenbroek /* skip to low u32 */
549*5d5fbe79SDavid van Moolenbroek value++;
550*5d5fbe79SDavid van Moolenbroek *value = 0;
551*5d5fbe79SDavid van Moolenbroek } else {
552*5d5fbe79SDavid van Moolenbroek *value <<= 8;
553*5d5fbe79SDavid van Moolenbroek }
554*5d5fbe79SDavid van Moolenbroek
555*5d5fbe79SDavid van Moolenbroek *value |= data;
556*5d5fbe79SDavid van Moolenbroek len--;
557*5d5fbe79SDavid van Moolenbroek }
558*5d5fbe79SDavid van Moolenbroek
559*5d5fbe79SDavid van Moolenbroek return ERR_OK;
560*5d5fbe79SDavid van Moolenbroek }
561*5d5fbe79SDavid van Moolenbroek }
562*5d5fbe79SDavid van Moolenbroek
563*5d5fbe79SDavid van Moolenbroek return ERR_VAL;
564*5d5fbe79SDavid van Moolenbroek }
565*5d5fbe79SDavid van Moolenbroek
566*5d5fbe79SDavid van Moolenbroek /**
567*5d5fbe79SDavid van Moolenbroek * Decodes integer into s32_t.
568*5d5fbe79SDavid van Moolenbroek *
569*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
570*5d5fbe79SDavid van Moolenbroek * @param len length of the coded integer field
571*5d5fbe79SDavid van Moolenbroek * @param value return host order integer
572*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
573*5d5fbe79SDavid van Moolenbroek *
574*5d5fbe79SDavid van Moolenbroek * @note ASN coded integers are _always_ signed!
575*5d5fbe79SDavid van Moolenbroek */
576*5d5fbe79SDavid van Moolenbroek err_t
snmp_asn1_dec_s32t(struct snmp_pbuf_stream * pbuf_stream,u16_t len,s32_t * value)577*5d5fbe79SDavid van Moolenbroek snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value)
578*5d5fbe79SDavid van Moolenbroek {
579*5d5fbe79SDavid van Moolenbroek #if BYTE_ORDER == LITTLE_ENDIAN
580*5d5fbe79SDavid van Moolenbroek u8_t *lsb_ptr = (u8_t*)value;
581*5d5fbe79SDavid van Moolenbroek #endif
582*5d5fbe79SDavid van Moolenbroek #if BYTE_ORDER == BIG_ENDIAN
583*5d5fbe79SDavid van Moolenbroek u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
584*5d5fbe79SDavid van Moolenbroek #endif
585*5d5fbe79SDavid van Moolenbroek u8_t sign;
586*5d5fbe79SDavid van Moolenbroek u8_t data;
587*5d5fbe79SDavid van Moolenbroek
588*5d5fbe79SDavid van Moolenbroek if ((len > 0) && (len < 5)) {
589*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
590*5d5fbe79SDavid van Moolenbroek len--;
591*5d5fbe79SDavid van Moolenbroek
592*5d5fbe79SDavid van Moolenbroek if (data & 0x80) {
593*5d5fbe79SDavid van Moolenbroek /* negative, start from -1 */
594*5d5fbe79SDavid van Moolenbroek *value = -1;
595*5d5fbe79SDavid van Moolenbroek sign = 1;
596*5d5fbe79SDavid van Moolenbroek *lsb_ptr &= data;
597*5d5fbe79SDavid van Moolenbroek } else {
598*5d5fbe79SDavid van Moolenbroek /* positive, start from 0 */
599*5d5fbe79SDavid van Moolenbroek *value = 0;
600*5d5fbe79SDavid van Moolenbroek sign = 0;
601*5d5fbe79SDavid van Moolenbroek *lsb_ptr |= data;
602*5d5fbe79SDavid van Moolenbroek }
603*5d5fbe79SDavid van Moolenbroek
604*5d5fbe79SDavid van Moolenbroek /* OR/AND octets with value */
605*5d5fbe79SDavid van Moolenbroek while (len > 0) {
606*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
607*5d5fbe79SDavid van Moolenbroek len--;
608*5d5fbe79SDavid van Moolenbroek
609*5d5fbe79SDavid van Moolenbroek #if BYTE_ORDER == LITTLE_ENDIAN
610*5d5fbe79SDavid van Moolenbroek *value <<= 8;
611*5d5fbe79SDavid van Moolenbroek #endif
612*5d5fbe79SDavid van Moolenbroek #if BYTE_ORDER == BIG_ENDIAN
613*5d5fbe79SDavid van Moolenbroek *value >>= 8;
614*5d5fbe79SDavid van Moolenbroek #endif
615*5d5fbe79SDavid van Moolenbroek
616*5d5fbe79SDavid van Moolenbroek if (sign) {
617*5d5fbe79SDavid van Moolenbroek *lsb_ptr |= 255;
618*5d5fbe79SDavid van Moolenbroek *lsb_ptr &= data;
619*5d5fbe79SDavid van Moolenbroek } else {
620*5d5fbe79SDavid van Moolenbroek *lsb_ptr |= data;
621*5d5fbe79SDavid van Moolenbroek }
622*5d5fbe79SDavid van Moolenbroek }
623*5d5fbe79SDavid van Moolenbroek
624*5d5fbe79SDavid van Moolenbroek return ERR_OK;
625*5d5fbe79SDavid van Moolenbroek }
626*5d5fbe79SDavid van Moolenbroek
627*5d5fbe79SDavid van Moolenbroek return ERR_VAL;
628*5d5fbe79SDavid van Moolenbroek }
629*5d5fbe79SDavid van Moolenbroek
630*5d5fbe79SDavid van Moolenbroek /**
631*5d5fbe79SDavid van Moolenbroek * Decodes object identifier from incoming message into array of u32_t.
632*5d5fbe79SDavid van Moolenbroek *
633*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
634*5d5fbe79SDavid van Moolenbroek * @param len length of the coded object identifier
635*5d5fbe79SDavid van Moolenbroek * @param oid return decoded object identifier
636*5d5fbe79SDavid van Moolenbroek * @param oid_len return decoded object identifier length
637*5d5fbe79SDavid van Moolenbroek * @param oid_max_len size of oid buffer
638*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
639*5d5fbe79SDavid van Moolenbroek */
640*5d5fbe79SDavid van Moolenbroek err_t
snmp_asn1_dec_oid(struct snmp_pbuf_stream * pbuf_stream,u16_t len,u32_t * oid,u8_t * oid_len,u8_t oid_max_len)641*5d5fbe79SDavid van Moolenbroek snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len)
642*5d5fbe79SDavid van Moolenbroek {
643*5d5fbe79SDavid van Moolenbroek u32_t *oid_ptr;
644*5d5fbe79SDavid van Moolenbroek u8_t data;
645*5d5fbe79SDavid van Moolenbroek
646*5d5fbe79SDavid van Moolenbroek *oid_len = 0;
647*5d5fbe79SDavid van Moolenbroek oid_ptr = oid;
648*5d5fbe79SDavid van Moolenbroek if (len > 0) {
649*5d5fbe79SDavid van Moolenbroek if (oid_max_len < 2) {
650*5d5fbe79SDavid van Moolenbroek return ERR_MEM;
651*5d5fbe79SDavid van Moolenbroek }
652*5d5fbe79SDavid van Moolenbroek
653*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
654*5d5fbe79SDavid van Moolenbroek len--;
655*5d5fbe79SDavid van Moolenbroek
656*5d5fbe79SDavid van Moolenbroek /* first compressed octet */
657*5d5fbe79SDavid van Moolenbroek if (data == 0x2B) {
658*5d5fbe79SDavid van Moolenbroek /* (most) common case 1.3 (iso.org) */
659*5d5fbe79SDavid van Moolenbroek *oid_ptr = 1;
660*5d5fbe79SDavid van Moolenbroek oid_ptr++;
661*5d5fbe79SDavid van Moolenbroek *oid_ptr = 3;
662*5d5fbe79SDavid van Moolenbroek oid_ptr++;
663*5d5fbe79SDavid van Moolenbroek } else if (data < 40) {
664*5d5fbe79SDavid van Moolenbroek *oid_ptr = 0;
665*5d5fbe79SDavid van Moolenbroek oid_ptr++;
666*5d5fbe79SDavid van Moolenbroek *oid_ptr = data;
667*5d5fbe79SDavid van Moolenbroek oid_ptr++;
668*5d5fbe79SDavid van Moolenbroek } else if (data < 80) {
669*5d5fbe79SDavid van Moolenbroek *oid_ptr = 1;
670*5d5fbe79SDavid van Moolenbroek oid_ptr++;
671*5d5fbe79SDavid van Moolenbroek *oid_ptr = data - 40;
672*5d5fbe79SDavid van Moolenbroek oid_ptr++;
673*5d5fbe79SDavid van Moolenbroek } else {
674*5d5fbe79SDavid van Moolenbroek *oid_ptr = 2;
675*5d5fbe79SDavid van Moolenbroek oid_ptr++;
676*5d5fbe79SDavid van Moolenbroek *oid_ptr = data - 80;
677*5d5fbe79SDavid van Moolenbroek oid_ptr++;
678*5d5fbe79SDavid van Moolenbroek }
679*5d5fbe79SDavid van Moolenbroek *oid_len = 2;
680*5d5fbe79SDavid van Moolenbroek } else {
681*5d5fbe79SDavid van Moolenbroek /* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */
682*5d5fbe79SDavid van Moolenbroek return ERR_OK;
683*5d5fbe79SDavid van Moolenbroek }
684*5d5fbe79SDavid van Moolenbroek
685*5d5fbe79SDavid van Moolenbroek while ((len > 0) && (*oid_len < oid_max_len)) {
686*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
687*5d5fbe79SDavid van Moolenbroek len--;
688*5d5fbe79SDavid van Moolenbroek
689*5d5fbe79SDavid van Moolenbroek if ((data & 0x80) == 0x00) {
690*5d5fbe79SDavid van Moolenbroek /* sub-identifier uses single octet */
691*5d5fbe79SDavid van Moolenbroek *oid_ptr = data;
692*5d5fbe79SDavid van Moolenbroek } else {
693*5d5fbe79SDavid van Moolenbroek /* sub-identifier uses multiple octets */
694*5d5fbe79SDavid van Moolenbroek u32_t sub_id = (data & ~0x80);
695*5d5fbe79SDavid van Moolenbroek while ((len > 0) && ((data & 0x80) != 0)) {
696*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
697*5d5fbe79SDavid van Moolenbroek len--;
698*5d5fbe79SDavid van Moolenbroek
699*5d5fbe79SDavid van Moolenbroek sub_id = (sub_id << 7) + (data & ~0x80);
700*5d5fbe79SDavid van Moolenbroek }
701*5d5fbe79SDavid van Moolenbroek
702*5d5fbe79SDavid van Moolenbroek if ((data & 0x80) != 0) {
703*5d5fbe79SDavid van Moolenbroek /* "more bytes following" bit still set at end of len */
704*5d5fbe79SDavid van Moolenbroek return ERR_VAL;
705*5d5fbe79SDavid van Moolenbroek }
706*5d5fbe79SDavid van Moolenbroek *oid_ptr = sub_id;
707*5d5fbe79SDavid van Moolenbroek }
708*5d5fbe79SDavid van Moolenbroek oid_ptr++;
709*5d5fbe79SDavid van Moolenbroek (*oid_len)++;
710*5d5fbe79SDavid van Moolenbroek }
711*5d5fbe79SDavid van Moolenbroek
712*5d5fbe79SDavid van Moolenbroek if (len > 0) {
713*5d5fbe79SDavid van Moolenbroek /* OID to long to fit in our buffer */
714*5d5fbe79SDavid van Moolenbroek return ERR_MEM;
715*5d5fbe79SDavid van Moolenbroek }
716*5d5fbe79SDavid van Moolenbroek
717*5d5fbe79SDavid van Moolenbroek return ERR_OK;
718*5d5fbe79SDavid van Moolenbroek }
719*5d5fbe79SDavid van Moolenbroek
720*5d5fbe79SDavid van Moolenbroek /**
721*5d5fbe79SDavid van Moolenbroek * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
722*5d5fbe79SDavid van Moolenbroek * from incoming message into array.
723*5d5fbe79SDavid van Moolenbroek *
724*5d5fbe79SDavid van Moolenbroek * @param pbuf_stream points to a pbuf stream
725*5d5fbe79SDavid van Moolenbroek * @param len length of the coded raw data (zero is valid, e.g. empty string!)
726*5d5fbe79SDavid van Moolenbroek * @param buf return raw bytes
727*5d5fbe79SDavid van Moolenbroek * @param buf_len returns length of the raw return value
728*5d5fbe79SDavid van Moolenbroek * @param buf_max_len buffer size
729*5d5fbe79SDavid van Moolenbroek * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
730*5d5fbe79SDavid van Moolenbroek */
731*5d5fbe79SDavid van Moolenbroek err_t
snmp_asn1_dec_raw(struct snmp_pbuf_stream * pbuf_stream,u16_t len,u8_t * buf,u16_t * buf_len,u16_t buf_max_len)732*5d5fbe79SDavid van Moolenbroek snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len)
733*5d5fbe79SDavid van Moolenbroek {
734*5d5fbe79SDavid van Moolenbroek if (len > buf_max_len) {
735*5d5fbe79SDavid van Moolenbroek /* not enough dst space */
736*5d5fbe79SDavid van Moolenbroek return ERR_MEM;
737*5d5fbe79SDavid van Moolenbroek }
738*5d5fbe79SDavid van Moolenbroek *buf_len = len;
739*5d5fbe79SDavid van Moolenbroek
740*5d5fbe79SDavid van Moolenbroek while (len > 0) {
741*5d5fbe79SDavid van Moolenbroek PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf));
742*5d5fbe79SDavid van Moolenbroek buf++;
743*5d5fbe79SDavid van Moolenbroek len--;
744*5d5fbe79SDavid van Moolenbroek }
745*5d5fbe79SDavid van Moolenbroek
746*5d5fbe79SDavid van Moolenbroek return ERR_OK;
747*5d5fbe79SDavid van Moolenbroek }
748*5d5fbe79SDavid van Moolenbroek
749*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SNMP */
750