3 * Abstract Syntax Notation One (ISO 8824, 8825) encoding
\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 * Returns octet count for length.
\r
46 * @param octets_needed points to the return value
\r
49 snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
\r
55 else if (length < 0x100U)
\r
66 * Returns octet count for an u32_t.
\r
69 * @param octets_needed points to the return value
\r
71 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
\r
72 * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
\r
73 * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
\r
76 snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
\r
82 else if (value < 0x8000UL)
\r
86 else if (value < 0x800000UL)
\r
90 else if (value < 0x80000000UL)
\r
101 * Returns octet count for an s32_t.
\r
104 * @param octets_needed points to the return value
\r
106 * @note ASN coded integers are _always_ signed.
\r
109 snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
\r
117 *octets_needed = 1;
\r
119 else if (value < 0x8000L)
\r
121 *octets_needed = 2;
\r
123 else if (value < 0x800000L)
\r
125 *octets_needed = 3;
\r
129 *octets_needed = 4;
\r
134 * Returns octet count for an object identifier.
\r
136 * @param ident_len object identifier array length
\r
137 * @param ident points to object identifier array
\r
138 * @param octets_needed points to the return value
\r
141 snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed)
\r
149 /* compressed prefix in one octet */
\r
154 while(ident_len > 0)
\r
168 *octets_needed = cnt;
\r
172 * Encodes ASN type field into a pbuf chained ASN1 msg.
\r
174 * @param p points to output pbuf to encode value into
\r
175 * @param ofs points to the offset within the pbuf chain
\r
176 * @param type input ASN1 type
\r
177 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
\r
180 snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)
\r
192 msg_ptr = p->payload;
\r
193 msg_ptr += ofs - base;
\r
199 /* p == NULL, ofs >= plen */
\r
204 * Encodes host order length field into a pbuf chained ASN1 msg.
\r
206 * @param p points to output pbuf to encode length into
\r
207 * @param ofs points to the offset within the pbuf chain
\r
208 * @param length is the host order length to be encoded
\r
209 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
\r
212 snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
\r
224 msg_ptr = p->payload;
\r
225 msg_ptr += ofs - base;
\r
232 else if (length < 0x100)
\r
238 /* next octet in next pbuf */
\r
240 if (p == NULL) { return ERR_ARG; }
\r
241 msg_ptr = p->payload;
\r
245 /* next octet in same pbuf */
\r
255 /* length >= 0x100 && length <= 0xFFFF */
\r
264 /* next octet in next pbuf */
\r
266 if (p == NULL) { return ERR_ARG; }
\r
267 msg_ptr = p->payload;
\r
272 /* next octet in same pbuf */
\r
277 /* least significant length octet */
\r
282 /* most significant length octet */
\r
283 *msg_ptr = length >> 8;
\r
291 /* p == NULL, ofs >= plen */
\r
296 * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
\r
298 * @param p points to output pbuf to encode value into
\r
299 * @param ofs points to the offset within the pbuf chain
\r
300 * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
\r
301 * @param value is the host order u32_t value to be encoded
\r
302 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
\r
304 * @see snmp_asn1_enc_u32t_cnt()
\r
307 snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
\r
319 msg_ptr = p->payload;
\r
320 msg_ptr += ofs - base;
\r
322 if (octets_needed == 5)
\r
324 /* not enough bits in 'value' add leading 0x00 */
\r
330 /* next octet in next pbuf */
\r
332 if (p == NULL) { return ERR_ARG; }
\r
333 msg_ptr = p->payload;
\r
338 /* next octet in same pbuf */
\r
342 while (octets_needed > 1)
\r
345 *msg_ptr = value >> (octets_needed << 3);
\r
349 /* next octet in next pbuf */
\r
351 if (p == NULL) { return ERR_ARG; }
\r
352 msg_ptr = p->payload;
\r
357 /* next octet in same pbuf */
\r
361 /* (only) one least significant octet */
\r
367 /* p == NULL, ofs >= plen */
\r
372 * Encodes s32_t integer into a pbuf chained ASN1 msg.
\r
374 * @param p points to output pbuf to encode value into
\r
375 * @param ofs points to the offset within the pbuf chain
\r
376 * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
\r
377 * @param value is the host order s32_t value to be encoded
\r
378 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
\r
380 * @see snmp_asn1_enc_s32t_cnt()
\r
383 snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)
\r
395 msg_ptr = p->payload;
\r
396 msg_ptr += ofs - base;
\r
398 while (octets_needed > 1)
\r
401 *msg_ptr = value >> (octets_needed << 3);
\r
405 /* next octet in next pbuf */
\r
407 if (p == NULL) { return ERR_ARG; }
\r
408 msg_ptr = p->payload;
\r
413 /* next octet in same pbuf */
\r
417 /* (only) one least significant octet */
\r
423 /* p == NULL, ofs >= plen */
\r
428 * Encodes object identifier into a pbuf chained ASN1 msg.
\r
430 * @param p points to output pbuf to encode oid into
\r
431 * @param ofs points to the offset within the pbuf chain
\r
432 * @param ident_len object identifier array length
\r
433 * @param ident points to object identifier array
\r
434 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
\r
437 snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
\r
449 msg_ptr = p->payload;
\r
450 msg_ptr += ofs - base;
\r
454 if ((ident[0] == 1) && (ident[1] == 3))
\r
456 /* compressed (most common) prefix .iso.org */
\r
461 /* calculate prefix */
\r
462 *msg_ptr = (ident[0] * 40) + ident[1];
\r
467 /* next octet in next pbuf */
\r
469 if (p == NULL) { return ERR_ARG; }
\r
470 msg_ptr = p->payload;
\r
475 /* next octet in same pbuf */
\r
483 /* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
\r
484 /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
\r
487 while (ident_len > 0)
\r
500 code = sub_id >> shift;
\r
501 if ((code != 0) || (tail != 0))
\r
504 *msg_ptr = code | 0x80;
\r
508 /* next octet in next pbuf */
\r
510 if (p == NULL) { return ERR_ARG; }
\r
511 msg_ptr = p->payload;
\r
516 /* next octet in same pbuf */
\r
522 *msg_ptr = (u8_t)sub_id & 0x7F;
\r
528 /* next octet in next pbuf */
\r
530 if (p == NULL) { return ERR_ARG; }
\r
531 msg_ptr = p->payload;
\r
536 /* next octet in same pbuf */
\r
540 /* proceed to next sub-identifier */
\r
547 /* p == NULL, ofs >= plen */
\r
552 * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
\r
554 * @param p points to output pbuf to encode raw data into
\r
555 * @param ofs points to the offset within the pbuf chain
\r
556 * @param raw_len raw data length
\r
557 * @param raw points raw data
\r
558 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
\r
561 snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)
\r
573 msg_ptr = p->payload;
\r
574 msg_ptr += ofs - base;
\r
576 while (raw_len > 1)
\r
578 /* copy raw_len - 1 octets */
\r
585 /* next octet in next pbuf */
\r
587 if (p == NULL) { return ERR_ARG; }
\r
588 msg_ptr = p->payload;
\r
593 /* next octet in same pbuf */
\r
599 /* copy last or single octet */
\r
606 /* p == NULL, ofs >= plen */
\r
610 #endif /* LWIP_SNMP */
\r