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