Contiki-NG
snmp-message.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2019 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  * An implementation of the Simple Network Management Protocol (RFC 3411-3418)
36  * \author
37  * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
38  */
39 
40 #include "contiki.h"
41 
42 #include "snmp-message.h"
43 #include "snmp-ber.h"
44 #include "snmp-oid.h"
45 
46 #define LOG_MODULE "SNMP [message]"
47 #define LOG_LEVEL LOG_LEVEL_SNMP
48 
49 unsigned char *
50 snmp_message_encode(unsigned char *out, uint32_t *out_len, snmp_header_t *header,
51  snmp_varbind_t *varbinds, uint32_t varbind_num)
52 {
53  snmp_varbind_t *varbind;
54  uint32_t original_out_len, last_out_len;
55  int8_t i;
56 
57  original_out_len = *out_len;
58  for(i = varbind_num - 1; i >= 0; i--) {
59  varbind = &varbinds[i];
60 
61  last_out_len = *out_len;
62 
63  switch(varbind->value_type) {
64  case BER_DATA_TYPE_INTEGER:
65  out = snmp_ber_encode_integer(out, out_len, varbind->value.integer);
66  break;
67  case SNMP_DATA_TYPE_TIME_TICKS:
68  out = snmp_ber_encode_unsigned_integer(out, out_len, varbind->value_type, varbind->value.integer);
69  break;
70  case BER_DATA_TYPE_OCTET_STRING:
71  out = snmp_ber_encode_string_len(out, out_len, varbind->value.string.string, varbind->value.string.length);
72  break;
73  case BER_DATA_TYPE_OID:
74  out = snmp_oid_encode_oid(out, out_len, varbind->value.oid);
75  break;
76  case BER_DATA_TYPE_NULL:
77  case SNMP_DATA_TYPE_NO_SUCH_INSTANCE:
78  case SNMP_DATA_TYPE_END_OF_MIB_VIEW:
79  out = snmp_ber_encode_null(out, out_len, varbind->value_type);
80  break;
81  default:
82  return NULL;
83  }
84 
85  out = snmp_oid_encode_oid(out, out_len, varbind->oid);
86  out = snmp_ber_encode_length(out, out_len, ((*out_len - last_out_len) & 0xFF));
87  out = snmp_ber_encode_type(out, out_len, BER_DATA_TYPE_SEQUENCE);
88  }
89 
90  out = snmp_ber_encode_length(out, out_len, ((*out_len - original_out_len) & 0xFF));
91  out = snmp_ber_encode_type(out, out_len, BER_DATA_TYPE_SEQUENCE);
92 
93  if(header->pdu_type == SNMP_DATA_TYPE_PDU_GET_BULK) {
94  out = snmp_ber_encode_integer(out, out_len, header->error_index_max_repetitions.max_repetitions);
95  out = snmp_ber_encode_integer(out, out_len, header->error_status_non_repeaters.non_repeaters);
96  } else {
97  out = snmp_ber_encode_integer(out, out_len, header->error_index_max_repetitions.error_index);
98  out = snmp_ber_encode_integer(out, out_len, header->error_status_non_repeaters.error_status);
99  }
100  out = snmp_ber_encode_integer(out, out_len, header->request_id);
101 
102  out = snmp_ber_encode_length(out, out_len, ((*out_len - original_out_len) & 0xFF));
103  out = snmp_ber_encode_type(out, out_len, header->pdu_type);
104 
105  out = snmp_ber_encode_string_len(out, out_len, header->community.community, header->community.length);
106  out = snmp_ber_encode_integer(out, out_len, header->version);
107 
108  out = snmp_ber_encode_length(out, out_len, ((*out_len - original_out_len) & 0xFF));
109  out = snmp_ber_encode_type(out, out_len, BER_DATA_TYPE_SEQUENCE);
110 
111  return out;
112 }
113 uint8_t *
114 snmp_message_decode(uint8_t *buf, uint32_t buf_len, snmp_header_t *header,
115  snmp_varbind_t *varbinds, uint32_t *varbind_num)
116 {
117  uint8_t type, len;
118  uint32_t i, oid_len;
119 
120  buf = snmp_ber_decode_type(buf, &buf_len, &type);
121  if(buf == NULL) {
122  LOG_DBG("Could not decode type\n");
123  return NULL;
124  }
125 
126  if(type != BER_DATA_TYPE_SEQUENCE) {
127  LOG_DBG("Invalid type\n");
128  return NULL;
129  }
130 
131  buf = snmp_ber_decode_length(buf, &buf_len, &len);
132  if(buf == NULL) {
133  LOG_DBG("Could not decode length\n");
134  return NULL;
135  }
136 
137  buf = snmp_ber_decode_integer(buf, &buf_len, &header->version);
138  if(buf == NULL) {
139  LOG_DBG("Could not decode version\n");
140  return NULL;
141  }
142 
143  buf = snmp_ber_decode_string_len_buffer(buf, &buf_len, &header->community.community, &header->community.length);
144  if(buf == NULL) {
145  LOG_DBG("Could not decode community\n");
146  return NULL;
147  }
148 
149  if(header->version != SNMP_VERSION_1 &&
150  header->version != SNMP_VERSION_2C) {
151  LOG_DBG("Invalid version\n");
152  return NULL;
153  }
154 
155  buf = snmp_ber_decode_type(buf, &buf_len, &type);
156  if(buf == NULL) {
157  LOG_DBG("Could not decode type\n");
158  return NULL;
159  }
160 
161  header->pdu_type = type;
162  if(header->pdu_type != SNMP_DATA_TYPE_PDU_GET_REQUEST &&
163  header->pdu_type != SNMP_DATA_TYPE_PDU_GET_NEXT_REQUEST &&
164  header->pdu_type != SNMP_DATA_TYPE_PDU_GET_RESPONSE &&
165  header->pdu_type != SNMP_DATA_TYPE_PDU_SET_REQUEST &&
166  header->pdu_type != SNMP_DATA_TYPE_PDU_GET_BULK) {
167  LOG_DBG("Invalid pdu type\n");
168  return NULL;
169  }
170 
171  buf = snmp_ber_decode_length(buf, &buf_len, &len);
172  if(buf == NULL) {
173  LOG_DBG("Could not decode length\n");
174  return NULL;
175  }
176 
177  buf = snmp_ber_decode_integer(buf, &buf_len, &header->request_id);
178  if(buf == NULL) {
179  LOG_DBG("Could not decode request id\n");
180  return NULL;
181  }
182 
183  if(header->pdu_type == SNMP_DATA_TYPE_PDU_GET_BULK) {
184  buf = snmp_ber_decode_integer(buf, &buf_len, &header->error_status_non_repeaters.non_repeaters);
185  if(buf == NULL) {
186  LOG_DBG("Could not decode error status\n");
187  return NULL;
188  }
189 
190  buf = snmp_ber_decode_integer(buf, &buf_len, &header->error_index_max_repetitions.max_repetitions);
191  if(buf == NULL) {
192  LOG_DBG("Could not decode error index\n");
193  return NULL;
194  }
195  } else {
196  buf = snmp_ber_decode_integer(buf, &buf_len, &header->error_status_non_repeaters.error_status);
197  if(buf == NULL) {
198  LOG_DBG("Could not decode error status\n");
199  return NULL;
200  }
201 
202  buf = snmp_ber_decode_integer(buf, &buf_len, &header->error_index_max_repetitions.error_index);
203  if(buf == NULL) {
204  LOG_DBG("Could not decode error index\n");
205  return NULL;
206  }
207  }
208 
209  buf = snmp_ber_decode_type(buf, &buf_len, &type);
210  if(buf == NULL) {
211  LOG_DBG("Could not decode type\n");
212  return NULL;
213  }
214 
215  if(type != BER_DATA_TYPE_SEQUENCE) {
216  LOG_DBG("Invalid type\n");
217  return NULL;
218  }
219 
220  buf = snmp_ber_decode_length(buf, &buf_len, &len);
221  if(buf == NULL) {
222  LOG_DBG("Could not decode length\n");
223  return NULL;
224  }
225 
226  for(i = 0; buf_len > 0; ++i) {
227 
228  buf = snmp_ber_decode_type(buf, &buf_len, &type);
229  if(buf == NULL) {
230  LOG_DBG("Could not decode type\n");
231  return NULL;
232  }
233 
234  if(type != BER_DATA_TYPE_SEQUENCE) {
235  LOG_DBG("Invalid (%X) type\n", type);
236  return NULL;
237  }
238 
239  buf = snmp_ber_decode_length(buf, &buf_len, &len);
240  if(buf == NULL) {
241  LOG_DBG("Could not decode length\n");
242  return NULL;
243  }
244 
245  buf = snmp_oid_decode_oid(buf, &buf_len, varbinds[i].oid, &oid_len);
246  if(buf == NULL) {
247  LOG_DBG("Could not decode oid\n");
248  return NULL;
249  }
250 
251  varbinds[i].value_type = *buf;
252 
253  switch(varbinds[i].value_type) {
254  case BER_DATA_TYPE_INTEGER:
255  buf = snmp_ber_decode_integer(buf, &buf_len, &varbinds[i].value.integer);
256  break;
257  case SNMP_DATA_TYPE_TIME_TICKS:
258  buf = snmp_ber_decode_unsigned_integer(buf, &buf_len, varbinds[i].value_type, &varbinds[i].value.integer);
259  break;
260  case BER_DATA_TYPE_OCTET_STRING:
261  buf = snmp_ber_decode_string_len_buffer(buf, &buf_len, &varbinds[i].value.string.string, &varbinds[i].value.string.length);
262  break;
263  case BER_DATA_TYPE_NULL:
264  buf = snmp_ber_decode_null(buf, &buf_len);
265  break;
266  default:
267  LOG_DBG("Invalid varbind type\n");
268  return NULL;
269  }
270 
271  if(buf == NULL) {
272  LOG_DBG("Could varbind type\n");
273  return NULL;
274  }
275  }
276 
277  *varbind_num = i;
278 
279  return buf;
280 }
unsigned char * snmp_ber_encode_string_len(unsigned char *out, uint32_t *out_len, const char *str, uint32_t length)
Encodes a string.
Definition: snmp-ber.c:102
uint32_t version
SNMP Version.
Definition: snmp.h:96
const char * community
A pointer to the community.
Definition: snmp.h:106
An implementation of the Simple Network Management Protocol (RFC 3411-3418)
The varbind struct.
Definition: snmp.h:157
uint32_t error_index
The error index.
Definition: snmp.h:146
uint8_t * snmp_oid_decode_oid(uint8_t *buf, uint32_t *buff_len, uint32_t *oid, uint32_t *oid_len)
Decodes a Oid.
Definition: snmp-oid.c:126
uint32_t error_status
The error status.
Definition: snmp.h:131
uint32_t non_repeaters
The non repeaters.
Definition: snmp.h:135
The SNMP header struct.
Definition: snmp.h:92
unsigned char * snmp_ber_decode_type(unsigned char *buff, uint32_t *buff_len, uint8_t *type)
Decodes a type.
Definition: snmp-ber.c:129
An implementation of the Simple Network Management Protocol (RFC 3411-3418)
unsigned char * snmp_ber_encode_null(unsigned char *out, uint32_t *out_len, uint8_t type)
Encodes a null.
Definition: snmp-ber.c:119
#define SNMP_VERSION_1
SNMP Version 1 code.
Definition: snmp.h:71
uint32_t oid[SNMP_MSG_OID_MAX_LEN]
The OID.
Definition: snmp.h:163
uint8_t pdu_type
The PDU type.
Definition: snmp.h:117
unsigned char * snmp_ber_decode_null(unsigned char *buf, uint32_t *buff_len)
Decodes a null.
Definition: snmp-ber.c:264
An implementation of the Simple Network Management Protocol (RFC 3411-3418)
unsigned char * snmp_ber_encode_length(unsigned char *out, uint32_t *out_len, uint8_t length)
Encodes the length.
Definition: snmp-ber.c:58
const char * string
A pointer to the string value from this varbind.
Definition: snmp.h:187
unsigned char * snmp_ber_decode_length(unsigned char *buff, uint32_t *buff_len, uint8_t *length)
Decodes a length.
Definition: snmp-ber.c:138
uint32_t max_repetitions
The max repetitions.
Definition: snmp.h:150
unsigned char * snmp_ber_encode_integer(unsigned char *out, uint32_t *out_len, uint32_t number)
Encodes an integer.
Definition: snmp-ber.c:66
uint8_t value_type
The type in this varbind.
Definition: snmp.h:167
uint32_t * oid
A pointer to the beggining of a oid array.
Definition: snmp.h:198
#define SNMP_VERSION_2C
SNMP Version 2c code.
Definition: snmp.h:75
unsigned char * snmp_ber_decode_unsigned_integer(unsigned char *buf, uint32_t *buff_len, uint8_t expected_type, uint32_t *num)
Decodes an unsigned number.
Definition: snmp-ber.c:183
uint32_t length
The string length.
Definition: snmp.h:112
unsigned char * snmp_ber_encode_unsigned_integer(unsigned char *out, uint32_t *out_len, uint8_t type, uint32_t number)
Encodes an unsigned integer.
Definition: snmp-ber.c:84
unsigned char * snmp_ber_decode_integer(unsigned char *buf, uint32_t *buff_len, uint32_t *num)
Decodes an integer.
Definition: snmp-ber.c:147
unsigned char * snmp_message_encode(unsigned char *out, uint32_t *out_len, snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t varbind_num)
Encodes a SNMP message.
Definition: snmp-message.c:50
uint32_t * oid
A array that represents the OID.
Definition: snmp-mib.h:73
uint32_t request_id
The request ID.
Definition: snmp.h:121
unsigned char * snmp_ber_decode_string_len_buffer(unsigned char *buf, uint32_t *buff_len, const char **str, uint32_t *length)
Decodes a string.
Definition: snmp-ber.c:219
uint32_t integer
The integer value.
Definition: snmp.h:177
unsigned char * snmp_oid_encode_oid(unsigned char *out, uint32_t *out_len, uint32_t *oid)
Encodes a Oid.
Definition: snmp-oid.c:80
uint8_t * snmp_message_decode(uint8_t *buf, uint32_t buf_len, snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t *varbind_num)
Definition: snmp-message.c:114
unsigned char * snmp_ber_encode_type(unsigned char *out, uint32_t *out_len, uint8_t type)
Encodes a type.
Definition: snmp-ber.c:50