Contiki-NG
Loading...
Searching...
No Matches
snmp-ber.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31/*---------------------------------------------------------------------------*/
32
33/**
34 * \file
35 * SNMP Implementation of the BER encoding
36 * \author
37 * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
38 */
39
40#include "contiki.h"
41
42#include "snmp.h"
43#include "snmp-ber.h"
44
45#define LOG_MODULE "SNMP [ber]"
46#define LOG_LEVEL LOG_LEVEL_SNMP
47
48/*---------------------------------------------------------------------------*/
49static inline int
50snmp_ber_encode_unsigned_integer(snmp_packet_t *snmp_packet, uint8_t type, uint32_t number)
51{
52 uint16_t original_out_len;
53
54 original_out_len = snmp_packet->used;
55 do {
56 if(snmp_packet->used == snmp_packet->max) {
57 return 0;
58 }
59
60 *snmp_packet->out-- = (uint8_t)number & 0xFF;
61 snmp_packet->used++;
62 /* I'm not sure why but on MSPGCC the >> 8 operation goes haywire here */
63#ifdef __MSPGCC__
64 number >>= 4;
65 number >>= 4;
66#else /* __MSPGCC__ */
67 number >>= 8;
68#endif /* __MSPGCC__ */
69 } while(number);
70
71 if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used - original_out_len)) {
72 return 0;
73 }
74
75 if(!snmp_ber_encode_type(snmp_packet, type)) {
76 return 0;
77 }
78
79 return 1;
80}
81/*---------------------------------------------------------------------------*/
82int
83snmp_ber_encode_type(snmp_packet_t *snmp_packet, uint8_t type)
84{
85 if(snmp_packet->used == snmp_packet->max) {
86 return 0;
87 }
88
89 *snmp_packet->out-- = type;
90 snmp_packet->used++;
91
92 return 1;
93}
94/*---------------------------------------------------------------------------*/
95int
96snmp_ber_encode_length(snmp_packet_t *snmp_packet, uint16_t length)
97{
98 if(length > 0xFF) {
99 if(snmp_packet->used == snmp_packet->max) {
100 return 0;
101 }
102
103 *snmp_packet->out-- = (uint8_t)length & 0xFF;
104 snmp_packet->used++;
105
106 if(snmp_packet->used == snmp_packet->max) {
107 return 0;
108 }
109
110 *snmp_packet->out-- = (uint8_t)(length >> 8) & 0xFF;
111 snmp_packet->used++;
112
113 if(snmp_packet->used == snmp_packet->max) {
114 return 0;
115 }
116
117 *snmp_packet->out-- = 0x82;
118 snmp_packet->used++;
119 } else if(length > 0x7F) {
120 if(snmp_packet->used == snmp_packet->max) {
121 return 0;
122 }
123
124 *snmp_packet->out-- = (uint8_t)length & 0xFF;
125 snmp_packet->used++;
126
127 if(snmp_packet->used == snmp_packet->max) {
128 return 0;
129 }
130
131 *snmp_packet->out-- = 0x81;
132 snmp_packet->used++;
133 } else {
134 if(snmp_packet->used == snmp_packet->max) {
135 return 0;
136 }
137
138 *snmp_packet->out-- = (uint8_t)length & 0x7F;
139 snmp_packet->used++;
140 }
141
142 return 1;
143}
144/*---------------------------------------------------------------------------*/
145int
146snmp_ber_encode_timeticks(snmp_packet_t *snmp_packet, uint32_t timeticks)
147{
148 return snmp_ber_encode_unsigned_integer(snmp_packet, BER_DATA_TYPE_TIMETICKS, timeticks);
149}
150/*---------------------------------------------------------------------------*/
151int
152snmp_ber_encode_integer(snmp_packet_t *snmp_packet, uint32_t number)
153{
154 return snmp_ber_encode_unsigned_integer(snmp_packet, BER_DATA_TYPE_INTEGER, number);
155}
156/*---------------------------------------------------------------------------*/
157int
158snmp_ber_encode_string_len(snmp_packet_t *snmp_packet, const char *str, uint32_t length)
159{
160 uint32_t i;
161
162 if(length > 0) {
163 str += length - 1;
164 for(i = 0; i < length; ++i) {
165 if(snmp_packet->used == snmp_packet->max) {
166 return 0;
167 }
168
169 *snmp_packet->out-- = (uint8_t)*str--;
170 snmp_packet->used++;
171 }
172 }
173
174 if(!snmp_ber_encode_length(snmp_packet, length)) {
175 return 0;
176 }
177
179 return 0;
180 }
181
182 return 1;
183}
184/*---------------------------------------------------------------------------*/
185int
187{
188 uint32_t val;
189 uint16_t original_out_len;
190 uint8_t pos;
191
192 original_out_len = snmp_packet->used;
193
194 pos = oid->length - 1;
195 while(pos) {
196 val = oid->data[pos];
197
198 if(snmp_packet->used == snmp_packet->max) {
199 return 0;
200 }
201
202 *snmp_packet->out-- = (uint8_t)(val & 0x7F);
203 snmp_packet->used++;
204 val >>= 7;
205
206 while(val) {
207 if(snmp_packet->used == snmp_packet->max) {
208 return 0;
209 }
210
211 *snmp_packet->out-- = (uint8_t)((val & 0x7F) | 0x80);
212 snmp_packet->used++;
213
214 val >>= 7;
215 }
216 pos--;
217 }
218
219 if(snmp_packet->used == snmp_packet->max) {
220 return 0;
221 }
222
223 val = *(snmp_packet->out + 1) + 40 * oid->data[pos];
224 snmp_packet->used--;
225 snmp_packet->out++;
226
227 if(snmp_packet->used == snmp_packet->max) {
228 return 0;
229 }
230
231 *snmp_packet->out-- = (uint8_t)(val & 0x7F);
232 snmp_packet->used++;
233
234 val >>= 7;
235
236 while(val) {
237 if(snmp_packet->used == snmp_packet->max) {
238 return 0;
239 }
240
241 *snmp_packet->out-- = (uint8_t)((val & 0x7F) | 0x80);
242 snmp_packet->used++;
243
244 val >>= 7;
245 }
246
247 if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used - original_out_len)) {
248 return 0;
249 }
250
252 return 0;
253 }
254
255 return 1;
256}
257/*---------------------------------------------------------------------------*/
258int
259snmp_ber_encode_null(snmp_packet_t *snmp_packet, uint8_t type)
260{
261
262 if(snmp_packet->used == snmp_packet->max) {
263 return 0;
264 }
265
266 *snmp_packet->out-- = 0x00;
267 snmp_packet->used++;
268
269 return snmp_ber_encode_type(snmp_packet, type);
270}
271/*---------------------------------------------------------------------------*/
272static inline int
273snmp_ber_decode_unsigned_integer(snmp_packet_t *snmp_packet, uint8_t expected_type, uint32_t *num)
274{
275 uint8_t i, len, type;
276
277 if(!snmp_ber_decode_type(snmp_packet, &type)) {
278 return 0;
279 }
280
281 if(type != expected_type) {
282 /*
283 * Sanity check
284 * Invalid type in buffer
285 */
286 return 0;
287 }
288
289 if(!snmp_ber_decode_length(snmp_packet, &len)) {
290 return 0;
291 }
292
293 if(len > 4) {
294 /*
295 * Sanity check
296 * It will not fit in the uint32_t
297 */
298 return 0;
299 }
300
301 if(snmp_packet->used == 0) {
302 return 0;
303 }
304
305 *num = (uint32_t)(*snmp_packet->in++ & 0xFF);
306 snmp_packet->used--;
307
308 for(i = 1; i < len; ++i) {
309 *num <<= 8;
310 if(snmp_packet->used == 0) {
311 return 0;
312 }
313 *num |= (uint8_t)(*snmp_packet->in++ & 0xFF);
314 snmp_packet->used--;
315 }
316
317 return 1;
318}
319/*---------------------------------------------------------------------------*/
320int
321snmp_ber_decode_type(snmp_packet_t *snmp_packet, uint8_t *type)
322{
323 if(snmp_packet->used == 0) {
324 return 0;
325 }
326
327 *type = *snmp_packet->in++;
328 snmp_packet->used--;
329
330 return 1;
331}
332/*---------------------------------------------------------------------------*/
333int
334snmp_ber_decode_length(snmp_packet_t *snmp_packet, uint8_t *length)
335{
336 if(snmp_packet->used == 0) {
337 return 0;
338 }
339
340 *length = *snmp_packet->in++;
341 snmp_packet->used--;
342
343 return 1;
344}
345/*---------------------------------------------------------------------------*/
346int
347snmp_ber_decode_timeticks(snmp_packet_t *snmp_packet, uint32_t *timeticks)
348{
349 return snmp_ber_decode_unsigned_integer(snmp_packet, BER_DATA_TYPE_TIMETICKS, timeticks);
350}
351/*---------------------------------------------------------------------------*/
352int
353snmp_ber_decode_integer(snmp_packet_t *snmp_packet, uint32_t *num)
354{
355 return snmp_ber_decode_unsigned_integer(snmp_packet, BER_DATA_TYPE_INTEGER, num);
356}
357/*---------------------------------------------------------------------------*/
358int
359snmp_ber_decode_string_len_buffer(snmp_packet_t *snmp_packet, const char **str, uint32_t *length)
360{
361 uint8_t type, i, length_bytes;
362
363 if(!snmp_ber_decode_type(snmp_packet, &type)) {
364 return 0;
365 }
366
367 if(type != BER_DATA_TYPE_OCTET_STRING) {
368 /*
369 * Sanity check
370 * Invalid type in buffer
371 */
372 return 0;
373 }
374
375 if((*snmp_packet->in & 0x80) == 0) {
376
377 if(snmp_packet->used == 0) {
378 return 0;
379 }
380
381 *length = (uint32_t)*snmp_packet->in++;
382 snmp_packet->used--;
383 } else {
384
385 if(snmp_packet->used == 0) {
386 return 0;
387 }
388
389 length_bytes = (uint8_t)(*snmp_packet->in++ & 0x7F);
390 snmp_packet->used--;
391
392 if(length_bytes > 4) {
393 /*
394 * Sanity check
395 * It will not fit in the uint32_t
396 */
397 return 0;
398 }
399
400 if(snmp_packet->used == 0) {
401 return 0;
402 }
403
404 *length = (uint32_t)*snmp_packet->in++;
405 snmp_packet->used--;
406
407 for(i = 1; i < length_bytes; ++i) {
408 *length <<= 8;
409
410 if(snmp_packet->used == 0) {
411 return 0;
412 }
413
414 *length |= *snmp_packet->in++;
415 snmp_packet->used--;
416 }
417 }
418
419 *str = (const char *)snmp_packet->in;
420
421 if(snmp_packet->used == 0 || snmp_packet->used < *length) {
422 return 0;
423 }
424
425 snmp_packet->used -= *length;
426 snmp_packet->in += *length;
427
428 return 1;
429}
430/*---------------------------------------------------------------------------*/
431int
433{
434 uint8_t *buf_end, type;
435 uint8_t len, j;
436 div_t first;
437
438 if(!snmp_ber_decode_type(snmp_packet, &type)) {
439 return 0;
440 }
441
443 return 0;
444 }
445
446 if(!snmp_ber_decode_length(snmp_packet, &len)) {
447 return 0;
448 }
449
450 buf_end = snmp_packet->in + len;
451
452 if(snmp_packet->used == 0) {
453 return 0;
454 }
455
456 snmp_packet->used--;
457 first = div(*snmp_packet->in++, 40);
458
459 oid->length = 0;
460
461 oid->data[oid->length++] = (uint32_t)first.quot;
462 oid->data[oid->length++] = (uint32_t)first.rem;
463
464 while(snmp_packet->in != buf_end) {
465 if(oid->length >= SNMP_MSG_OID_MAX_LEN) {
466 return 0;
467 }
468
469 if(snmp_packet->used == 0) {
470 return 0;
471 }
472 oid->data[oid->length] = (uint32_t)(*snmp_packet->in & 0x7F);
473 for(j = 0; j < 4; j++) {
474 snmp_packet->used--;
475 if((*snmp_packet->in++ & 0x80) == 0) {
476 break;
477 }
478
479 if(snmp_packet->used == 0) {
480 return 0;
481 }
482
483 oid->data[oid->length] <<= 7;
484 oid->data[oid->length] |= (*snmp_packet->in & 0x7F);
485 }
486
487 oid->length++;
488 }
489
490 return 1;
491}
492/*---------------------------------------------------------------------------*/
493int
495{
496 if(snmp_packet->used == 0) {
497 return 0;
498 }
499
500 snmp_packet->in++;
501 snmp_packet->used--;
502
503 if(snmp_packet->used == 0) {
504 return 0;
505 }
506
507 snmp_packet->in++;
508 snmp_packet->used--;
509
510 return 1;
511}
512/*---------------------------------------------------------------------------*/
#define BER_DATA_TYPE_INTEGER
Integer.
Definition snmp-ber.h:72
int snmp_ber_encode_string_len(snmp_packet_t *snmp_packet, const char *str, uint32_t length)
Encodes a string.
Definition snmp-ber.c:158
int snmp_ber_encode_timeticks(snmp_packet_t *snmp_packet, uint32_t timeticks)
Encodes a timeticks.
Definition snmp-ber.c:146
#define BER_DATA_TYPE_OBJECT_IDENTIFIER
Object Identifier.
Definition snmp-ber.h:90
int snmp_ber_encode_integer(snmp_packet_t *snmp_packet, uint32_t number)
Encodes an integer.
Definition snmp-ber.c:152
int snmp_ber_decode_null(snmp_packet_t *snmp_packet)
Decodes a null.
Definition snmp-ber.c:494
#define BER_DATA_TYPE_TIMETICKS
TimeTicks.
Definition snmp-ber.h:102
int snmp_ber_decode_type(snmp_packet_t *snmp_packet, uint8_t *type)
Decodes a type.
Definition snmp-ber.c:321
int snmp_ber_encode_null(snmp_packet_t *snmp_packet, uint8_t type)
Encodes a null.
Definition snmp-ber.c:259
int snmp_ber_encode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid)
Encodes a Oid.
Definition snmp-ber.c:186
int snmp_ber_decode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid)
Decodes an OID.
Definition snmp-ber.c:432
int snmp_ber_decode_length(snmp_packet_t *snmp_packet, uint8_t *length)
Decodes a length.
Definition snmp-ber.c:334
int snmp_ber_decode_integer(snmp_packet_t *snmp_packet, uint32_t *num)
Decodes an integer.
Definition snmp-ber.c:353
int snmp_ber_encode_type(snmp_packet_t *snmp_packet, uint8_t type)
Encodes a type.
Definition snmp-ber.c:83
int snmp_ber_encode_length(snmp_packet_t *snmp_packet, uint16_t length)
Encodes the length.
Definition snmp-ber.c:96
#define BER_DATA_TYPE_OCTET_STRING
Octet String.
Definition snmp-ber.h:78
int snmp_ber_decode_string_len_buffer(snmp_packet_t *snmp_packet, const char **str, uint32_t *length)
Decodes a string.
Definition snmp-ber.c:359
int snmp_ber_decode_timeticks(snmp_packet_t *snmp_packet, uint32_t *timeticks)
Decodes a timeticks.
Definition snmp-ber.c:347
#define SNMP_MSG_OID_MAX_LEN
Default maximum number of IDs in one OID.
Definition snmp-conf.h:86
SNMP Implementation of the BER encoding.
SNMP Implementation of the process.
The OID struct.
Definition snmp.h:144
uint8_t length
The OID length.
Definition snmp.h:153
uint32_t data[16]
The OID.
Definition snmp.h:148
The packet struct.
Definition snmp.h:206
uint8_t * in
The pointer used for the incoming packet.
Definition snmp.h:221
uint8_t * out
The pointer used for the outgoing packet.
Definition snmp.h:226
uint16_t max
The maximum number of bytes.
Definition snmp.h:216
uint16_t used
The number of bytes used.
Definition snmp.h:211