3 * Abstract Syntax Notation One (ISO 8824, 8825) decoding
5 * @todo not optimised (yet), favor correctness over speed, favor speed over size
9 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without modification,
13 * are permitted provided that the following conditions are met:
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 * 3. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
26 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
28 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
31 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
34 * Author: Christiaan Simons <christiaan.simons@axon.tv>
40 #include "lwip/snmp_asn1.h"
43 * Retrieves type field from incoming pbuf chain.
45 * @param p points to a pbuf holding an ASN1 coded type field
46 * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field
47 * @param type return ASN1 type
48 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
51 snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
64 msg_ptr += ofs - base;
70 /* p == NULL, ofs >= plen */
75 * Decodes length field from incoming pbuf chain into host length.
77 * @param p points to a pbuf holding an ASN1 coded length
78 * @param ofs points to the offset within the pbuf chain of the ASN1 coded length
79 * @param octets_used returns number of octets used by the length code
80 * @param length return host order length, upto 64k
81 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
84 snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)
97 msg_ptr += ofs - base;
101 /* primitive definite length format */
106 else if (*msg_ptr == 0x80)
108 /* constructed indefinite length format, termination with two zero octets */
124 /* next octet in next pbuf */
126 if (p == NULL) { return ERR_ARG; }
127 msg_ptr = p->payload;
132 /* next octet in same pbuf */
140 /* stop while (i > 0) */
153 else if (*msg_ptr == 0x81)
155 /* constructed definite length format, one octet */
159 /* next octet in next pbuf */
161 if (p == NULL) { return ERR_ARG; }
162 msg_ptr = p->payload;
166 /* next octet in same pbuf */
173 else if (*msg_ptr == 0x82)
177 /* constructed definite length format, two octets */
185 /* next octet in next pbuf */
187 if (p == NULL) { return ERR_ARG; }
188 msg_ptr = p->payload;
193 /* next octet in same pbuf */
198 /* least significant length octet */
203 /* most significant length octet */
204 *length = (*msg_ptr) << 8;
212 /* constructed definite length format 3..127 octets, this is too big (>64k) */
213 /** @todo: do we need to accept inefficient codings with many leading zero's? */
214 *octets_used = 1 + ((*msg_ptr) & 0x7f);
221 /* p == NULL, ofs >= plen */
226 * Decodes positive integer (counter, gauge, timeticks) into u32_t.
228 * @param p points to a pbuf holding an ASN1 coded integer
229 * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
230 * @param len length of the coded integer field
231 * @param value return host order integer
232 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
234 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
235 * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
236 * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
239 snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
251 msg_ptr = p->payload;
252 msg_ptr += ofs - base;
253 if ((len > 0) && (len < 6))
255 /* start from zero */
259 /* negative, expecting zero sign bit! */
265 if ((len > 1) && (*msg_ptr == 0))
267 /* skip leading "sign byte" octet 0x00 */
272 /* next octet in next pbuf */
274 if (p == NULL) { return ERR_ARG; }
275 msg_ptr = p->payload;
280 /* next octet in same pbuf */
285 /* OR octets with value */
294 /* next octet in next pbuf */
296 if (p == NULL) { return ERR_ARG; }
297 msg_ptr = p->payload;
302 /* next octet in same pbuf */
316 /* p == NULL, ofs >= plen */
321 * Decodes integer into s32_t.
323 * @param p points to a pbuf holding an ASN1 coded integer
324 * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
325 * @param len length of the coded integer field
326 * @param value return host order integer
327 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
329 * @note ASN coded integers are _always_ signed!
332 snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
336 u8_t *lsb_ptr = (u8_t*)value;
346 msg_ptr = p->payload;
347 msg_ptr += ofs - base;
348 if ((len > 0) && (len < 5))
352 /* negative, start from -1 */
358 /* positive, start from 0 */
362 /* OR/AND octets with value */
368 *lsb_ptr &= *msg_ptr;
374 *lsb_ptr |= *msg_ptr;
380 /* next octet in next pbuf */
382 if (p == NULL) { return ERR_ARG; }
383 msg_ptr = p->payload;
388 /* next octet in same pbuf */
394 *lsb_ptr &= *msg_ptr;
398 *lsb_ptr |= *msg_ptr;
409 /* p == NULL, ofs >= plen */
414 * Decodes object identifier from incoming message into array of s32_t.
416 * @param p points to a pbuf holding an ASN1 coded object identifier
417 * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier
418 * @param len length of the coded object identifier
419 * @param oid return object identifier struct
420 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
423 snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
436 msg_ptr = p->payload;
437 msg_ptr += ofs - base;
440 oid_ptr = &oid->id[0];
443 /* first compressed octet */
444 if (*msg_ptr == 0x2B)
446 /* (most) common case 1.3 (iso.org) */
452 else if (*msg_ptr < 40)
459 else if (*msg_ptr < 80)
463 *oid_ptr = (*msg_ptr) - 40;
470 *oid_ptr = (*msg_ptr) - 80;
477 /* accepting zero length identifiers e.g. for
478 getnext operation. uncommon but valid */
487 /* next octet in next pbuf */
489 if (p == NULL) { return ERR_ARG; }
490 msg_ptr = p->payload;
495 /* next octet in same pbuf */
499 while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))
501 /* sub-identifier uses multiple octets */
506 while ((*msg_ptr & 0x80) && (len > 1))
509 sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);
513 /* next octet in next pbuf */
515 if (p == NULL) { return ERR_ARG; }
516 msg_ptr = p->payload;
521 /* next octet in same pbuf */
525 if (!(*msg_ptr & 0x80) && (len > 0))
527 /* last octet sub-identifier */
529 sub_id = (sub_id << 7) + *msg_ptr;
535 /* !(*msg_ptr & 0x80) sub-identifier uses single octet */
541 /* remaining oid bytes available ... */
545 /* next octet in next pbuf */
547 if (p == NULL) { return ERR_ARG; }
548 msg_ptr = p->payload;
553 /* next octet in same pbuf */
562 /* len == 0, end of oid */
567 /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */
574 /* p == NULL, ofs >= plen */
579 * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
580 * from incoming message into array.
582 * @param p points to a pbuf holding an ASN1 coded raw data
583 * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data
584 * @param len length of the coded raw data (zero is valid, e.g. empty string!)
585 * @param raw_len length of the raw return value
586 * @param raw return raw bytes
587 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
590 snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)
604 msg_ptr = p->payload;
605 msg_ptr += ofs - base;
610 /* copy len - 1 octets */
617 /* next octet in next pbuf */
619 if (p == NULL) { return ERR_ARG; }
620 msg_ptr = p->payload;
625 /* next octet in same pbuf */
629 /* copy last octet */
635 /* raw_len < len, not enough dst space */
641 /* p == NULL, ofs >= plen */
646 /* len == 0, empty string */
651 #endif /* LWIP_SNMP */