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/*---------------------------------------------------------------------------*/
51static inline int
52snmp_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/*---------------------------------------------------------------------------*/
86static inline int
87snmp_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/*---------------------------------------------------------------------------*/
121static inline int
122snmp_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/*---------------------------------------------------------------------------*/
219int
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}
#define BER_DATA_TYPE_NO_SUCH_INSTANCE
No Such Instance.
Definition: snmp-ber.h:108
#define BER_DATA_TYPE_PDU_GET_BULK
PDU Get Bulk.
Definition: snmp-ber.h:150
#define BER_DATA_TYPE_PDU_GET_RESPONSE
PDU Get Reponse.
Definition: snmp-ber.h:132
#define BER_DATA_TYPE_PDU_GET_NEXT_REQUEST
PDU Get Next Request.
Definition: snmp-ber.h:126
#define BER_DATA_TYPE_PDU_GET_REQUEST
PDU Get Request.
Definition: snmp-ber.h:120
#define BER_DATA_TYPE_EOC
End-of-Content.
Definition: snmp-ber.h:66
#define BER_DATA_TYPE_END_OF_MIB_VIEW
End of MIB View.
Definition: snmp-ber.h:114
#define SNMP_COMMUNITY
Default SNMP Community.
Definition: snmp-conf.h:71
#define SNMP_MAX_NR_VALUES
Default maximum number of OIDs in one response.
Definition: snmp-conf.h:101
#define SNMP_VERSION_2C
SNMP Version 2c code.
Definition: snmp.h:83
#define SNMP_VERSION_1
SNMP Version 1 code.
Definition: snmp.h:79
#define SNMP_STATUS_NO_SUCH_NAME
SNMP No Such Name error code.
Definition: snmp.h:88
int snmp_engine(snmp_packet_t *snmp_packet)
Process the SNMP packet and prepares the response.
Definition: snmp-engine.c:220
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_mib_resource_t * snmp_mib_find(snmp_oid_t *oid)
Finds the MIB Resource for this OID.
Definition: snmp-mib.c:89
int snmp_message_decode(snmp_packet_t *snmp_packet, snmp_header_t *header, snmp_varbind_t *varbinds)
Definition: snmp-message.c:189
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 Implementation of the BER encoding.
SNMP Implementation of the protocol engine.
SNMP Implementation of the messages.
SNMP Implementation of the MIB.
const char * community
A pointer to the community.
Definition: snmp.h:107
uint32_t length
The string length.
Definition: snmp.h:113
The SNMP header struct.
Definition: snmp.h:93
uint8_t pdu_type
The PDU type.
Definition: snmp.h:118
uint32_t error_index
The error index.
Definition: snmp.h:134
uint32_t max_repetitions
The max repetitions.
Definition: snmp.h:138
uint32_t error_status
The error status.
Definition: snmp.h:126
uint32_t version
SNMP Version.
Definition: snmp.h:97
uint32_t non_repeaters
The non repeaters.
Definition: snmp.h:130
The MIB Resource struct.
Definition: snmp-mib.h:75
snmp_oid_t oid
A OID struct.
Definition: snmp-mib.h:85
snmp_mib_resource_handler_t handler
The function handler that is called for this resource.
Definition: snmp-mib.h:89
The OID struct.
Definition: snmp.h:144
The packet struct.
Definition: snmp.h:206
The varbind struct.
Definition: snmp.h:159