ReactOS 0.4.16-dev-527-gdad3a09
snmp_asn1.c
Go to the documentation of this file.
1
8/*
9 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without modification,
13 * are permitted provided that the following conditions are met:
14 *
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.
22 *
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
32 * OF SUCH DAMAGE.
33 *
34 * Author: Christiaan Simons <christiaan.simons@axon.tv>
35 * Martin Hentschel <info@cl-soft.de>
36 */
37
38#include "lwip/apps/snmp_opts.h"
39
40#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
41
42#include "snmp_asn1.h"
43
44#define PBUF_OP_EXEC(code) \
45 if ((code) != ERR_OK) { \
46 return ERR_BUF; \
47 }
48
57snmp_ans1_enc_tlv(struct snmp_pbuf_stream *pbuf_stream, struct snmp_asn1_tlv *tlv)
58{
59 u8_t data;
60 u8_t length_bytes_required;
61
62 /* write type */
63 if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
64 /* extended format is not used by SNMP so we do not accept those values */
65 return ERR_ARG;
66 }
67 if (tlv->type_len != 0) {
68 /* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */
69 return ERR_ARG;
70 }
71
72 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type));
73 tlv->type_len = 1;
74
75 /* write length */
76 if (tlv->value_len <= 127) {
77 length_bytes_required = 1;
78 } else if (tlv->value_len <= 255) {
79 length_bytes_required = 2;
80 } else {
81 length_bytes_required = 3;
82 }
83
84 /* check for forced min length */
85 if (tlv->length_len > 0) {
86 if (tlv->length_len < length_bytes_required) {
87 /* unable to code requested length in requested number of bytes */
88 return ERR_ARG;
89 }
90
91 length_bytes_required = tlv->length_len;
92 } else {
93 tlv->length_len = length_bytes_required;
94 }
95
96 if (length_bytes_required > 1) {
97 /* multi byte representation required */
98 length_bytes_required--;
99 data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */
100
101 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
102
103 while (length_bytes_required > 1) {
104 if (length_bytes_required == 2) {
105 /* append high byte */
106 data = (u8_t)(tlv->value_len >> 8);
107 } else {
108 /* append leading 0x00 */
109 data = 0x00;
110 }
111
112 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
113 length_bytes_required--;
114 }
115 }
116
117 /* append low byte */
118 data = (u8_t)(tlv->value_len & 0xFF);
119 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
120
121 return ERR_OK;
122}
123
132err_t
133snmp_asn1_enc_raw(struct snmp_pbuf_stream *pbuf_stream, const u8_t *raw, u16_t raw_len)
134{
135 PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len));
136
137 return ERR_OK;
138}
139
150err_t
151snmp_asn1_enc_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, u32_t value)
152{
153 if (octets_needed > 5) {
154 return ERR_ARG;
155 }
156 if (octets_needed == 5) {
157 /* not enough bits in 'value' add leading 0x00 */
158 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
159 octets_needed--;
160 }
161
162 while (octets_needed > 1) {
163 octets_needed--;
164 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
165 }
166
167 /* (only) one least significant octet */
168 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
169
170 return ERR_OK;
171}
182err_t
183snmp_asn1_enc_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, s32_t value)
184{
185 while (octets_needed > 1) {
186 octets_needed--;
187
188 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
189 }
190
191 /* (only) one least significant octet */
192 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
193
194 return ERR_OK;
195}
196
205err_t
206snmp_asn1_enc_oid(struct snmp_pbuf_stream *pbuf_stream, const u32_t *oid, u16_t oid_len)
207{
208 if (oid_len > 1) {
209 /* write compressed first two sub id's */
210 u32_t compressed_byte = ((oid[0] * 40) + oid[1]);
211 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte));
212 oid_len -= 2;
213 oid += 2;
214 } else {
215 /* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
216 /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
217 return ERR_ARG;
218 }
219
220 while (oid_len > 0) {
221 u32_t sub_id;
222 u8_t shift, tail;
223
224 oid_len--;
225 sub_id = *oid;
226 tail = 0;
227 shift = 28;
228 while (shift > 0) {
229 u8_t code;
230
231 code = (u8_t)(sub_id >> shift);
232 if ((code != 0) || (tail != 0)) {
233 tail = 1;
234 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80));
235 }
236 shift -= 7;
237 }
238 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F));
239
240 /* proceed to next sub-identifier */
241 oid++;
242 }
243 return ERR_OK;
244}
245
252void
253snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
254{
255 if (length < 0x80U) {
256 *octets_needed = 1;
257 } else if (length < 0x100U) {
258 *octets_needed = 2;
259 } else {
260 *octets_needed = 3;
261 }
262}
263
274void
275snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
276{
277 if (value < 0x80UL) {
278 *octets_needed = 1;
279 } else if (value < 0x8000UL) {
280 *octets_needed = 2;
281 } else if (value < 0x800000UL) {
282 *octets_needed = 3;
283 } else if (value < 0x80000000UL) {
284 *octets_needed = 4;
285 } else {
286 *octets_needed = 5;
287 }
288}
289
298void
299snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
300{
301 if (value < 0) {
302 value = ~value;
303 }
304 if (value < 0x80L) {
305 *octets_needed = 1;
306 } else if (value < 0x8000L) {
307 *octets_needed = 2;
308 } else if (value < 0x800000L) {
309 *octets_needed = 3;
310 } else {
311 *octets_needed = 4;
312 }
313}
314
322void
323snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed)
324{
325 u32_t sub_id;
326
327 *octets_needed = 0;
328 if (oid_len > 1) {
329 /* compressed prefix in one octet */
330 (*octets_needed)++;
331 oid_len -= 2;
332 oid += 2;
333 }
334 while (oid_len > 0) {
335 oid_len--;
336 sub_id = *oid;
337
338 sub_id >>= 7;
339 (*octets_needed)++;
340 while (sub_id > 0) {
341 sub_id >>= 7;
342 (*octets_needed)++;
343 }
344 oid++;
345 }
346}
347
355err_t
356snmp_asn1_dec_tlv(struct snmp_pbuf_stream *pbuf_stream, struct snmp_asn1_tlv *tlv)
357{
358 u8_t data;
359
360 /* decode type first */
361 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
362 tlv->type = data;
363
364 if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
365 /* extended format is not used by SNMP so we do not accept those values */
366 return ERR_VAL;
367 }
368 tlv->type_len = 1;
369
370 /* now, decode length */
371 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
372
373 if (data < 0x80) { /* short form */
374 tlv->length_len = 1;
375 tlv->value_len = data;
376 } else if (data > 0x80) { /* long form */
377 u8_t length_bytes = data - 0x80;
378 if (length_bytes > pbuf_stream->length) {
379 return ERR_VAL;
380 }
381 tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */
382 tlv->value_len = 0;
383
384 while (length_bytes > 0) {
385 /* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */
386 if (tlv->value_len > 0xFF) {
387 return ERR_VAL;
388 }
389 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
390 tlv->value_len <<= 8;
391 tlv->value_len |= data;
392
393 /* take care for special value used for indefinite length */
394 if (tlv->value_len == 0xFFFF) {
395 return ERR_VAL;
396 }
397
398 length_bytes--;
399 }
400 } else { /* data == 0x80 indefinite length form */
401 /* (not allowed for SNMP; RFC 1157, 3.2.2) */
402 return ERR_VAL;
403 }
404
405 return ERR_OK;
406}
407
420err_t
421snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
422{
423 u8_t data;
424
425 if ((len > 0) && (len <= 5)) {
426 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
427
428 /* expecting sign bit to be zero, only unsigned please! */
429 if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) {
430 *value = data;
431 len--;
432
433 while (len > 0) {
434 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
435 len--;
436
437 *value <<= 8;
438 *value |= data;
439 }
440
441 return ERR_OK;
442 }
443 }
444
445 return ERR_VAL;
446}
447
458err_t
459snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value)
460{
461 u8_t data;
462
463 if ((len > 0) && (len < 5)) {
464 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
465
466 if (data & 0x80) {
467 /* negative, start from -1 */
468 *value = -1;
469 *value = (*value << 8) | data;
470 } else {
471 /* positive, start from 0 */
472 *value = data;
473 }
474 len--;
475 /* shift in the remaining value */
476 while (len > 0) {
477 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
478 *value = (*value << 8) | data;
479 len--;
480 }
481 return ERR_OK;
482 }
483
484 return ERR_VAL;
485}
486
497err_t
498snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *oid, u8_t *oid_len, u8_t oid_max_len)
499{
500 u32_t *oid_ptr;
501 u8_t data;
502
503 *oid_len = 0;
504 oid_ptr = oid;
505 if (len > 0) {
506 if (oid_max_len < 2) {
507 return ERR_MEM;
508 }
509
510 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
511 len--;
512
513 /* first compressed octet */
514 if (data == 0x2B) {
515 /* (most) common case 1.3 (iso.org) */
516 *oid_ptr = 1;
517 oid_ptr++;
518 *oid_ptr = 3;
519 oid_ptr++;
520 } else if (data < 40) {
521 *oid_ptr = 0;
522 oid_ptr++;
523 *oid_ptr = data;
524 oid_ptr++;
525 } else if (data < 80) {
526 *oid_ptr = 1;
527 oid_ptr++;
528 *oid_ptr = data - 40;
529 oid_ptr++;
530 } else {
531 *oid_ptr = 2;
532 oid_ptr++;
533 *oid_ptr = data - 80;
534 oid_ptr++;
535 }
536 *oid_len = 2;
537 } else {
538 /* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */
539 return ERR_OK;
540 }
541
542 while ((len > 0) && (*oid_len < oid_max_len)) {
543 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
544 len--;
545
546 if ((data & 0x80) == 0x00) {
547 /* sub-identifier uses single octet */
548 *oid_ptr = data;
549 } else {
550 /* sub-identifier uses multiple octets */
551 u32_t sub_id = (data & ~0x80);
552 while ((len > 0) && ((data & 0x80) != 0)) {
553 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
554 len--;
555
556 sub_id = (sub_id << 7) + (data & ~0x80);
557 }
558
559 if ((data & 0x80) != 0) {
560 /* "more bytes following" bit still set at end of len */
561 return ERR_VAL;
562 }
563 *oid_ptr = sub_id;
564 }
565 oid_ptr++;
566 (*oid_len)++;
567 }
568
569 if (len > 0) {
570 /* OID to long to fit in our buffer */
571 return ERR_MEM;
572 }
573
574 return ERR_OK;
575}
576
588err_t
589snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t *buf_len, u16_t buf_max_len)
590{
591 if (len > buf_max_len) {
592 /* not enough dst space */
593 return ERR_MEM;
594 }
595 *buf_len = len;
596
597 while (len > 0) {
598 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf));
599 buf++;
600 len--;
601 }
602
603 return ERR_OK;
604}
605
606#if LWIP_HAVE_INT64
617void
618snmp_asn1_enc_u64t_cnt(u64_t value, u16_t *octets_needed)
619{
620 /* check if high u32 is 0 */
621 if ((value >> 32) == 0) {
622 /* only low u32 is important */
623 snmp_asn1_enc_u32t_cnt((u32_t)value, octets_needed);
624 } else {
625 /* low u32 does not matter for length determination */
626 snmp_asn1_enc_u32t_cnt((u32_t)(value >> 32), octets_needed);
627 *octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */
628 }
629}
630
643err_t
644snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u64_t *value)
645{
646 u8_t data;
647
648 if ((len > 0) && (len <= 9)) {
649 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
650
651 /* expecting sign bit to be zero, only unsigned please! */
652 if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) {
653 *value = data;
654 len--;
655
656 while (len > 0) {
657 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
658 *value <<= 8;
659 *value |= data;
660 len--;
661 }
662
663 return ERR_OK;
664 }
665 }
666
667 return ERR_VAL;
668}
669
680err_t
681snmp_asn1_enc_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, u64_t value)
682{
683 if (octets_needed > 9) {
684 return ERR_ARG;
685 }
686 if (octets_needed == 9) {
687 /* not enough bits in 'value' add leading 0x00 */
688 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
689 octets_needed--;
690 }
691
692 while (octets_needed > 1) {
693 octets_needed--;
694 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
695 }
696
697 /* always write at least one octet (also in case of value == 0) */
698 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value)));
699
700 return ERR_OK;
701}
702#endif
703
704#endif /* LWIP_SNMP */
struct outqueuenode * tail
Definition: adnsresfilter.c:66
#define ERR_MEM
Definition: fontsub.h:52
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLenum GLsizei len
Definition: glext.h:6722
int32_t s32_t
Definition: arch.h:130
uint32_t u32_t
Definition: arch.h:129
uint8_t u8_t
Definition: arch.h:125
uint16_t u16_t
Definition: arch.h:127
s8_t err_t
Definition: err.h:96
@ ERR_OK
Definition: err.h:55
@ ERR_VAL
Definition: err.h:67
@ ERR_ARG
Definition: err.h:88
#define shift
Definition: input.c:1755
Definition: inflate.c:139
Definition: pdh_main.c:94