Contiki-NG
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 /*---------------------------------------------------------------------------*/
49 static inline int
50 snmp_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 /*---------------------------------------------------------------------------*/
82 int
83 snmp_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 /*---------------------------------------------------------------------------*/
95 int
96 snmp_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 /*---------------------------------------------------------------------------*/
145 int
146 snmp_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 /*---------------------------------------------------------------------------*/
151 int
152 snmp_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 /*---------------------------------------------------------------------------*/
157 int
158 snmp_ber_encode_string_len(snmp_packet_t *snmp_packet, const char *str, uint32_t length)
159 {
160  uint32_t i;
161 
162  str += length - 1;
163  for(i = 0; i < length; ++i) {
164  if(snmp_packet->used == snmp_packet->max) {
165  return 0;
166  }
167 
168  *snmp_packet->out-- = (uint8_t)*str--;
169  snmp_packet->used++;
170  }
171 
172  if(!snmp_ber_encode_length(snmp_packet, length)) {
173  return 0;
174  }
175 
177  return 0;
178  }
179 
180  return 1;
181 }
182 /*---------------------------------------------------------------------------*/
183 int
185 {
186  uint32_t val;
187  uint16_t original_out_len;
188  uint8_t pos;
189 
190  original_out_len = snmp_packet->used;
191 
192  pos = oid->length - 1;
193  while(pos) {
194  val = oid->data[pos];
195 
196  if(snmp_packet->used == snmp_packet->max) {
197  return 0;
198  }
199 
200  *snmp_packet->out-- = (uint8_t)(val & 0x7F);
201  snmp_packet->used++;
202  val >>= 7;
203 
204  while(val) {
205  if(snmp_packet->used == snmp_packet->max) {
206  return 0;
207  }
208 
209  *snmp_packet->out-- = (uint8_t)((val & 0x7F) | 0x80);
210  snmp_packet->used++;
211 
212  val >>= 7;
213  }
214  pos--;
215  }
216 
217  if(snmp_packet->used == snmp_packet->max) {
218  return 0;
219  }
220 
221  val = *(snmp_packet->out + 1) + 40 * oid->data[pos];
222  snmp_packet->used--;
223  snmp_packet->out++;
224 
225  if(snmp_packet->used == snmp_packet->max) {
226  return 0;
227  }
228 
229  *snmp_packet->out-- = (uint8_t)(val & 0x7F);
230  snmp_packet->used++;
231 
232  val >>= 7;
233 
234  while(val) {
235  if(snmp_packet->used == snmp_packet->max) {
236  return 0;
237  }
238 
239  *snmp_packet->out-- = (uint8_t)((val & 0x7F) | 0x80);
240  snmp_packet->used++;
241 
242  val >>= 7;
243  }
244 
245  if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used - original_out_len)) {
246  return 0;
247  }
248 
250  return 0;
251  }
252 
253  return 1;
254 }
255 /*---------------------------------------------------------------------------*/
256 int
257 snmp_ber_encode_null(snmp_packet_t *snmp_packet, uint8_t type)
258 {
259 
260  if(snmp_packet->used == snmp_packet->max) {
261  return 0;
262  }
263 
264  *snmp_packet->out-- = 0x00;
265  snmp_packet->used++;
266 
267  return snmp_ber_encode_type(snmp_packet, type);
268 }
269 /*---------------------------------------------------------------------------*/
270 static inline int
271 snmp_ber_decode_unsigned_integer(snmp_packet_t *snmp_packet, uint8_t expected_type, uint32_t *num)
272 {
273  uint8_t i, len, type;
274 
275  if(!snmp_ber_decode_type(snmp_packet, &type)) {
276  return 0;
277  }
278 
279  if(type != expected_type) {
280  /*
281  * Sanity check
282  * Invalid type in buffer
283  */
284  return 0;
285  }
286 
287  if(!snmp_ber_decode_length(snmp_packet, &len)) {
288  return 0;
289  }
290 
291  if(len > 4) {
292  /*
293  * Sanity check
294  * It will not fit in the uint32_t
295  */
296  return 0;
297  }
298 
299  if(snmp_packet->used == 0) {
300  return 0;
301  }
302 
303  *num = (uint32_t)(*snmp_packet->in++ & 0xFF);
304  snmp_packet->used--;
305 
306  for(i = 1; i < len; ++i) {
307  *num <<= 8;
308  if(snmp_packet->used == 0) {
309  return 0;
310  }
311  *num |= (uint8_t)(*snmp_packet->in++ & 0xFF);
312  snmp_packet->used--;
313  }
314 
315  return 1;
316 }
317 /*---------------------------------------------------------------------------*/
318 int
319 snmp_ber_decode_type(snmp_packet_t *snmp_packet, uint8_t *type)
320 {
321  if(snmp_packet->used == 0) {
322  return 0;
323  }
324 
325  *type = *snmp_packet->in++;
326  snmp_packet->used--;
327 
328  return 1;
329 }
330 /*---------------------------------------------------------------------------*/
331 int
332 snmp_ber_decode_length(snmp_packet_t *snmp_packet, uint8_t *length)
333 {
334  if(snmp_packet->used == 0) {
335  return 0;
336  }
337 
338  *length = *snmp_packet->in++;
339  snmp_packet->used--;
340 
341  return 1;
342 }
343 /*---------------------------------------------------------------------------*/
344 int
345 snmp_ber_decode_timeticks(snmp_packet_t *snmp_packet, uint32_t *timeticks)
346 {
347  return snmp_ber_decode_unsigned_integer(snmp_packet, BER_DATA_TYPE_TIMETICKS, timeticks);
348 }
349 /*---------------------------------------------------------------------------*/
350 int
351 snmp_ber_decode_integer(snmp_packet_t *snmp_packet, uint32_t *num)
352 {
353  return snmp_ber_decode_unsigned_integer(snmp_packet, BER_DATA_TYPE_INTEGER, num);
354 }
355 /*---------------------------------------------------------------------------*/
356 int
357 snmp_ber_decode_string_len_buffer(snmp_packet_t *snmp_packet, const char **str, uint32_t *length)
358 {
359  uint8_t type, i, length_bytes;
360 
361  if(!snmp_ber_decode_type(snmp_packet, &type)) {
362  return 0;
363  }
364 
365  if(type != BER_DATA_TYPE_OCTET_STRING) {
366  /*
367  * Sanity check
368  * Invalid type in buffer
369  */
370  return 0;
371  }
372 
373  if((*snmp_packet->in & 0x80) == 0) {
374 
375  if(snmp_packet->used == 0) {
376  return 0;
377  }
378 
379  *length = (uint32_t)*snmp_packet->in++;
380  snmp_packet->used--;
381  } else {
382 
383  if(snmp_packet->used == 0) {
384  return 0;
385  }
386 
387  length_bytes = (uint8_t)(*snmp_packet->in++ & 0x7F);
388  snmp_packet->used--;
389 
390  if(length_bytes > 4) {
391  /*
392  * Sanity check
393  * It will not fit in the uint32_t
394  */
395  return 0;
396  }
397 
398  if(snmp_packet->used == 0) {
399  return 0;
400  }
401 
402  *length = (uint32_t)*snmp_packet->in++;
403  snmp_packet->used--;
404 
405  for(i = 1; i < length_bytes; ++i) {
406  *length <<= 8;
407 
408  if(snmp_packet->used == 0) {
409  return 0;
410  }
411 
412  *length |= *snmp_packet->in++;
413  snmp_packet->used--;
414  }
415  }
416 
417  *str = (const char *)snmp_packet->in;
418 
419  if(snmp_packet->used == 0 || snmp_packet->used - *length <= 0) {
420  return 0;
421  }
422 
423  snmp_packet->used -= *length;
424  snmp_packet->in += *length;
425 
426  return 1;
427 }
428 /*---------------------------------------------------------------------------*/
429 int
431 {
432  uint8_t *buf_end, type;
433  uint8_t len, j;
434  div_t first;
435 
436  if(!snmp_ber_decode_type(snmp_packet, &type)) {
437  return 0;
438  }
439 
440  if(type != BER_DATA_TYPE_OBJECT_IDENTIFIER) {
441  return 0;
442  }
443 
444  if(!snmp_ber_decode_length(snmp_packet, &len)) {
445  return 0;
446  }
447 
448  buf_end = snmp_packet->in + len;
449 
450  if(snmp_packet->used == 0) {
451  return 0;
452  }
453 
454  snmp_packet->used--;
455  first = div(*snmp_packet->in++, 40);
456 
457  oid->length = 0;
458 
459  oid->data[oid->length++] = (uint32_t)first.quot;
460  oid->data[oid->length++] = (uint32_t)first.rem;
461 
462  while(snmp_packet->in != buf_end) {
463  if(oid->length >= SNMP_MSG_OID_MAX_LEN) {
464  return 0;
465  }
466 
467  if(snmp_packet->used == 0) {
468  return 0;
469  }
470  oid->data[oid->length] = (uint32_t)(*snmp_packet->in & 0x7F);
471  for(j = 0; j < 4; j++) {
472  snmp_packet->used--;
473  if((*snmp_packet->in++ & 0x80) == 0) {
474  break;
475  }
476 
477  if(snmp_packet->used == 0) {
478  return 0;
479  }
480 
481  oid->data[oid->length] <<= 7;
482  oid->data[oid->length] |= (*snmp_packet->in & 0x7F);
483  }
484 
485  oid->length++;
486  }
487 
488  return 1;
489 }
490 /*---------------------------------------------------------------------------*/
491 int
493 {
494  if(snmp_packet->used == 0) {
495  return 0;
496  }
497 
498  snmp_packet->in++;
499  snmp_packet->used--;
500 
501  if(snmp_packet->used == 0) {
502  return 0;
503  }
504 
505  snmp_packet->in++;
506  snmp_packet->used--;
507 
508  return 1;
509 }
510 /*---------------------------------------------------------------------------*/
SNMP Implementation of the process
#define BER_DATA_TYPE_TIMETICKS
TimeTicks.
Definition: snmp-ber.h:102
int snmp_ber_decode_null(snmp_packet_t *snmp_packet)
Decodes a null.
Definition: snmp-ber.c:492
The packet struct.
Definition: snmp.h:206
int snmp_ber_decode_integer(snmp_packet_t *snmp_packet, uint32_t *num)
Decodes an integer.
Definition: snmp-ber.c:351
int snmp_ber_decode_type(snmp_packet_t *snmp_packet, uint8_t *type)
Decodes a type.
Definition: snmp-ber.c:319
int snmp_ber_encode_integer(snmp_packet_t *snmp_packet, uint32_t number)
Encodes an integer.
Definition: snmp-ber.c:152
#define BER_DATA_TYPE_OCTET_STRING
Octet String.
Definition: snmp-ber.h:78
int snmp_ber_encode_timeticks(snmp_packet_t *snmp_packet, uint32_t timeticks)
Encodes a timeticks.
Definition: snmp-ber.c:146
SNMP Implementation of the BER encoding
int snmp_ber_encode_type(snmp_packet_t *snmp_packet, uint8_t type)
Encodes a type.
Definition: snmp-ber.c:83
int snmp_ber_decode_length(snmp_packet_t *snmp_packet, uint8_t *length)
Decodes a length.
Definition: snmp-ber.c:332
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:357
int snmp_ber_decode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid)
Decodes an OID.
Definition: snmp-ber.c:430
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
uint8_t * in
The pointer used for the incoming packet.
Definition: snmp.h:221
int snmp_ber_encode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid)
Encodes a Oid.
Definition: snmp-ber.c:184
uint8_t * out
The pointer used for the outgoing packet.
Definition: snmp.h:226
The OID struct.
Definition: snmp.h:144
int snmp_ber_encode_length(snmp_packet_t *snmp_packet, uint16_t length)
Encodes the length.
Definition: snmp-ber.c:96
#define SNMP_MSG_OID_MAX_LEN
Default maximum number of IDs in one OID.
Definition: snmp-conf.h:86
uint32_t data[SNMP_MSG_OID_MAX_LEN]
The OID.
Definition: snmp.h:148
uint16_t used
The number os bytes used.
Definition: snmp.h:211
#define BER_DATA_TYPE_INTEGER
Integer.
Definition: snmp-ber.h:72
uint16_t max
The maximum number of bytes.
Definition: snmp.h:216
snmp_oid_t oid
A OID struct.
Definition: snmp-mib.h:85
#define BER_DATA_TYPE_OBJECT_IDENTIFIER
Object Identifier.
Definition: snmp-ber.h:90
int snmp_ber_encode_null(snmp_packet_t *snmp_packet, uint8_t type)
Encodes a null.
Definition: snmp-ber.c:257
int snmp_ber_decode_timeticks(snmp_packet_t *snmp_packet, uint32_t *timeticks)
Decodes a timeticks.
Definition: snmp-ber.c:345
uint8_t length
The OID length.
Definition: snmp.h:153