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