Contiki-NG
snmp-engine.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 protocol engine
36  * \author
37  * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
38  */
39 
40 #include "contiki.h"
41 
42 #include "snmp-engine.h"
43 #include "snmp-message.h"
44 #include "snmp-mib.h"
45 #include "snmp-ber.h"
46 
47 #define LOG_MODULE "SNMP [engine]"
48 #define LOG_LEVEL LOG_LEVEL_SNMP
49 
50 /*---------------------------------------------------------------------------*/
51 static inline int
52 snmp_engine_get(snmp_header_t *header, snmp_varbind_t *varbinds)
53 {
54  snmp_mib_resource_t *resource;
55  uint8_t i;
56 
57  i = 0;
58  while(i < SNMP_MAX_NR_VALUES && varbinds[i].value_type != BER_DATA_TYPE_EOC) {
59  resource = snmp_mib_find(&varbinds[i].oid);
60  if(!resource) {
61  switch(header->version) {
62  case SNMP_VERSION_1:
64  /*
65  * Varbinds are 1 indexed
66  */
67  header->error_index = i + 1;
68  break;
69  case SNMP_VERSION_2C:
70  (&varbinds[i])->value_type = BER_DATA_TYPE_NO_SUCH_INSTANCE;
71  break;
72  default:
74  header->error_index = 0;
75  }
76  } else {
77  resource->handler(&varbinds[i], &resource->oid);
78  }
79 
80  i++;
81  }
82 
83  return 0;
84 }
85 /*---------------------------------------------------------------------------*/
86 static inline int
87 snmp_engine_get_next(snmp_header_t *header, snmp_varbind_t *varbinds)
88 {
89  snmp_mib_resource_t *resource;
90  uint8_t i;
91 
92  i = 0;
93  while(i < SNMP_MAX_NR_VALUES && varbinds[i].value_type != BER_DATA_TYPE_EOC) {
94  resource = snmp_mib_find_next(&varbinds[i].oid);
95  if(!resource) {
96  switch(header->version) {
97  case SNMP_VERSION_1:
99  /*
100  * Varbinds are 1 indexed
101  */
102  header->error_index = i + 1;
103  break;
104  case SNMP_VERSION_2C:
105  (&varbinds[i])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
106  break;
107  default:
109  header->error_index = 0;
110  }
111  } else {
112  resource->handler(&varbinds[i], &resource->oid);
113  }
114 
115  i++;
116  }
117 
118  return 0;
119 }
120 /*---------------------------------------------------------------------------*/
121 static inline int
122 snmp_engine_get_bulk(snmp_header_t *header, snmp_varbind_t *varbinds)
123 {
124  snmp_mib_resource_t *resource;
126  uint32_t j, original_varbinds_length;
127  uint8_t repeater;
128  uint8_t i, varbinds_length;
129 
130  /*
131  * A local copy of the requested oids must be kept since
132  * the varbinds are modified on the fly
133  */
134  original_varbinds_length = 0;
135  while(original_varbinds_length < SNMP_MAX_NR_VALUES &&
136  varbinds[original_varbinds_length].value_type != BER_DATA_TYPE_EOC) {
137  memcpy(&oids[original_varbinds_length], &varbinds[original_varbinds_length].oid, sizeof(snmp_oid_t));
138  original_varbinds_length++;
139  }
140 
141  varbinds_length = 0;
142  for(i = 0; i < original_varbinds_length; i++) {
143  if(i >= header->non_repeaters) {
144  break;
145  }
146 
147  resource = snmp_mib_find_next(&oids[i]);
148  if(!resource) {
149  switch(header->version) {
150  case SNMP_VERSION_1:
152  /*
153  * Varbinds are 1 indexed
154  */
155  header->error_index = i + 1;
156  break;
157  case SNMP_VERSION_2C:
158  (&varbinds[i])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
159  break;
160  default:
162  header->error_index = 0;
163  }
164  } else {
165  if(varbinds_length < SNMP_MAX_NR_VALUES) {
166  resource->handler(&varbinds[varbinds_length], &resource->oid);
167  (varbinds_length)++;
168  } else {
169  return -1;
170  }
171  }
172  }
173 
174  for(i = 0; i < header->max_repetitions; i++) {
175  repeater = 0;
176  for(j = header->non_repeaters; j < original_varbinds_length; j++) {
177  resource = snmp_mib_find_next(&oids[j]);
178  if(!resource) {
179  switch(header->version) {
180  case SNMP_VERSION_1:
182  /*
183  * Varbinds are 1 indexed
184  */
185  header->error_index = varbinds_length + 1;
186  break;
187  case SNMP_VERSION_2C:
188  if(varbinds_length < SNMP_MAX_NR_VALUES) {
189  (&varbinds[varbinds_length])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
190  memcpy(&varbinds[varbinds_length].oid, &oids[j], sizeof(snmp_oid_t));
191  (varbinds_length)++;
192  } else {
193  return -1;
194  }
195  break;
196  default:
198  header->error_index = 0;
199  }
200  } else {
201  if(varbinds_length < SNMP_MAX_NR_VALUES) {
202  resource->handler(&varbinds[varbinds_length], &resource->oid);
203  (varbinds_length)++;
204  memcpy(&oids[j], &resource->oid, sizeof(snmp_oid_t));
205  repeater++;
206  } else {
207  return -1;
208  }
209  }
210  }
211  if(repeater == 0) {
212  break;
213  }
214  }
215 
216  return 0;
217 }
218 /*---------------------------------------------------------------------------*/
219 int
221 {
222  snmp_header_t header;
224 
225  memset(&header, 0, sizeof(header));
226  memset(varbinds, 0, sizeof(varbinds));
227 
228  if(!snmp_message_decode(snmp_packet, &header, varbinds)) {
229  return 0;
230  }
231 
232  if(header.version != SNMP_VERSION_1) {
233  if(strncmp(header.community.community, SNMP_COMMUNITY, header.community.length)) {
234  LOG_ERR("Request with invalid community\n");
235  return 0;
236  }
237  }
238 
239  /*
240  * Now handle the SNMP requests depending on their type
241  */
242  switch(header.pdu_type) {
244  if(snmp_engine_get(&header, varbinds) == -1) {
245  return 0;
246  }
247  break;
248 
250  if(snmp_engine_get_next(&header, varbinds) == -1) {
251  return 0;
252  }
253  break;
254 
256  if(snmp_engine_get_bulk(&header, varbinds) == -1) {
257  return 0;
258  }
259  break;
260 
261  default:
262  LOG_ERR("Invalid request type");
263  return 0;
264  }
265 
267 
268  return snmp_message_encode(snmp_packet, &header, varbinds);
269 }
uint32_t error_status
The error status.
Definition: snmp.h:126
uint32_t version
SNMP Version.
Definition: snmp.h:97
uint32_t error_index
The error index.
Definition: snmp.h:134
snmp_mib_resource_handler_t handler
The function handler that is called for this resource.
Definition: snmp-mib.h:89
const char * community
A pointer to the community.
Definition: snmp.h:107
The packet struct.
Definition: snmp.h:206
#define SNMP_COMMUNITY
Default SNMP Community.
Definition: snmp-conf.h:71
The varbind struct.
Definition: snmp.h:159
uint32_t max_repetitions
The max repetitions.
Definition: snmp.h:138
The MIB Resource struct.
Definition: snmp-mib.h:75
#define SNMP_VERSION_1
SNMP Version 1 code.
Definition: snmp.h:79
The SNMP header struct.
Definition: snmp.h:93
SNMP Implementation of the BER encoding
#define BER_DATA_TYPE_NO_SUCH_INSTANCE
No Such Instance.
Definition: snmp-ber.h:108
#define BER_DATA_TYPE_EOC
End-of-Content.
Definition: snmp-ber.h:66
The OID struct.
Definition: snmp.h:144
uint8_t pdu_type
The PDU type.
Definition: snmp.h:118
int snmp_message_decode(snmp_packet_t *snmp_packet, snmp_header_t *header, snmp_varbind_t *varbinds)
Definition: snmp-message.c:189
SNMP Implementation of the messages
#define BER_DATA_TYPE_PDU_GET_NEXT_REQUEST
PDU Get Next Request.
Definition: snmp-ber.h:126
#define BER_DATA_TYPE_END_OF_MIB_VIEW
End of MIB View.
Definition: snmp-ber.h:114
uint32_t length
The string length.
Definition: snmp.h:113
int snmp_message_encode(snmp_packet_t *snmp_packet, snmp_header_t *header, snmp_varbind_t *varbinds)
Encodes a SNMP message.
Definition: snmp-message.c:49
snmp_mib_resource_t * snmp_mib_find(snmp_oid_t *oid)
Finds the MIB Resource for this OID.
Definition: snmp-mib.c:89
#define SNMP_STATUS_NO_SUCH_NAME
SNMP No Such Name error code.
Definition: snmp.h:88
#define SNMP_VERSION_2C
SNMP Version 2c code.
Definition: snmp.h:83
#define BER_DATA_TYPE_PDU_GET_REQUEST
PDU Get Request.
Definition: snmp-ber.h:120
uint32_t non_repeaters
The non repeaters.
Definition: snmp.h:130
snmp_oid_t oid
A OID struct.
Definition: snmp-mib.h:85
#define BER_DATA_TYPE_PDU_GET_RESPONSE
PDU Get Reponse.
Definition: snmp-ber.h:132
#define SNMP_MAX_NR_VALUES
Default maximum number of OIDs in one response.
Definition: snmp-conf.h:101
SNMP Implementation of the MIB
snmp_mib_resource_t * snmp_mib_find_next(snmp_oid_t *oid)
Finds the next MIB Resource after this OID.
Definition: snmp-mib.c:106
SNMP Implementation of the protocol engine
#define BER_DATA_TYPE_PDU_GET_BULK
PDU Get Bulk.
Definition: snmp-ber.h:150
int snmp_engine(snmp_packet_t *snmp_packet)
Process the SNMP packet and prepares the response.
Definition: snmp-engine.c:220