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(varbinds[i].value_type != BER_DATA_TYPE_EOC && i < SNMP_MAX_NR_VALUES) {
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(varbinds[i].value_type != BER_DATA_TYPE_EOC && i < SNMP_MAX_NR_VALUES) {
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(varbinds[original_varbinds_length].value_type != BER_DATA_TYPE_EOC && original_varbinds_length < SNMP_MAX_NR_VALUES) {
136  memcpy(&oids[original_varbinds_length], &varbinds[original_varbinds_length].oid, sizeof(snmp_oid_t));
137  original_varbinds_length++;
138  }
139 
140  varbinds_length = 0;
141  for(i = 0; i < original_varbinds_length; i++) {
142  if(i >= header->non_repeaters) {
143  break;
144  }
145 
146  resource = snmp_mib_find_next(&oids[i]);
147  if(!resource) {
148  switch(header->version) {
149  case SNMP_VERSION_1:
151  /*
152  * Varbinds are 1 indexed
153  */
154  header->error_index = i + 1;
155  break;
156  case SNMP_VERSION_2C:
157  (&varbinds[i])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
158  break;
159  default:
161  header->error_index = 0;
162  }
163  } else {
164  if(varbinds_length < SNMP_MAX_NR_VALUES) {
165  resource->handler(&varbinds[varbinds_length], &resource->oid);
166  (varbinds_length)++;
167  } else {
168  return -1;
169  }
170  }
171  }
172 
173  for(i = 0; i < header->max_repetitions; i++) {
174  repeater = 0;
175  for(j = header->non_repeaters; j < original_varbinds_length; j++) {
176  resource = snmp_mib_find_next(&oids[j]);
177  if(!resource) {
178  switch(header->version) {
179  case SNMP_VERSION_1:
181  /*
182  * Varbinds are 1 indexed
183  */
184  header->error_index = varbinds_length + 1;
185  break;
186  case SNMP_VERSION_2C:
187  if(varbinds_length < SNMP_MAX_NR_VALUES) {
188  (&varbinds[varbinds_length])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
189  memcpy(&varbinds[varbinds_length].oid, &oids[j], sizeof(snmp_oid_t));
190  (varbinds_length)++;
191  } else {
192  return -1;
193  }
194  break;
195  default:
197  header->error_index = 0;
198  }
199  } else {
200  if(varbinds_length < SNMP_MAX_NR_VALUES) {
201  resource->handler(&varbinds[varbinds_length], &resource->oid);
202  (varbinds_length)++;
203  memcpy(&oids[j], &resource->oid, sizeof(snmp_oid_t));
204  repeater++;
205  } else {
206  return -1;
207  }
208  }
209  }
210  if(repeater == 0) {
211  break;
212  }
213  }
214 
215  return 0;
216 }
217 /*---------------------------------------------------------------------------*/
218 int
220 {
221  snmp_header_t header;
223 
224  memset(&header, 0, sizeof(header));
225  memset(varbinds, 0, sizeof(varbinds));
226 
227  if(!snmp_message_decode(snmp_packet, &header, varbinds)) {
228  return 0;
229  }
230 
231  if(header.version != SNMP_VERSION_1) {
232  if(strncmp(header.community.community, SNMP_COMMUNITY, header.community.length)) {
233  LOG_ERR("Request with invalid community\n");
234  return 0;
235  }
236  }
237 
238  /*
239  * Now handle the SNMP requests depending on their type
240  */
241  switch(header.pdu_type) {
243  if(snmp_engine_get(&header, varbinds) == -1) {
244  return 0;
245  }
246  break;
247 
249  if(snmp_engine_get_next(&header, varbinds) == -1) {
250  return 0;
251  }
252  break;
253 
255  if(snmp_engine_get_bulk(&header, varbinds) == -1) {
256  return 0;
257  }
258  break;
259 
260  default:
261  LOG_ERR("Invalid request type");
262  return 0;
263  }
264 
266 
267  return snmp_message_encode(snmp_packet, &header, varbinds);
268 }
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:219