1 /**
2 * @file
3 * Management Information Base II (RFC1213) INTERFACES objects and functions.
4 */
5
6 /*
7 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30 * OF SUCH DAMAGE.
31 *
32 * Author: Dirk Ziegelmeier <dziegel@gmx.de>
33 * Christiaan Simons <christiaan.simons@axon.tv>
34 */
35
36 #include "lwip/snmp.h"
37 #include "lwip/apps/snmp.h"
38 #include "lwip/apps/snmp_core.h"
39 #include "lwip/apps/snmp_mib2.h"
40 #include "lwip/apps/snmp_table.h"
41 #include "lwip/apps/snmp_scalar.h"
42 #include "lwip/netif.h"
43 #include "lwip/stats.h"
44
45 #include <string.h>
46
47 #if LWIP_SNMP && SNMP_LWIP_MIB2
48
49 #if SNMP_USE_NETCONN
50 #define SYNC_NODE_NAME(node_name) node_name ## _synced
51 #define CREATE_LWIP_SYNC_NODE(oid, node_name) \
52 static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
53 #else
54 #define SYNC_NODE_NAME(node_name) node_name
55 #define CREATE_LWIP_SYNC_NODE(oid, node_name)
56 #endif
57
58
59 /* --- interfaces .1.3.6.1.2.1.2 ----------------------------------------------------- */
60
61 static s16_t
interfaces_get_value(struct snmp_node_instance * instance,void * value)62 interfaces_get_value(struct snmp_node_instance* instance, void* value)
63 {
64 if (instance->node->oid == 1) {
65 s32_t *sint_ptr = (s32_t*)value;
66 s32_t num_netifs = 0;
67
68 struct netif *netif = netif_list;
69 while (netif != NULL) {
70 num_netifs++;
71 netif = netif->next;
72 }
73
74 *sint_ptr = num_netifs;
75 return sizeof(*sint_ptr);
76 }
77
78 return 0;
79 }
80
81 /* list of allowed value ranges for incoming OID */
82 static const struct snmp_oid_range interfaces_Table_oid_ranges[] = {
83 { 1, 0xff } /* netif->num is u8_t */
84 };
85
86 static const u8_t iftable_ifOutQLen = 0;
87
88 static const u8_t iftable_ifOperStatus_up = 1;
89 static const u8_t iftable_ifOperStatus_down = 2;
90
91 static const u8_t iftable_ifAdminStatus_up = 1;
92 static const u8_t iftable_ifAdminStatus_lowerLayerDown = 7;
93 static const u8_t iftable_ifAdminStatus_down = 2;
94
95 static snmp_err_t
interfaces_Table_get_cell_instance(const u32_t * column,const u32_t * row_oid,u8_t row_oid_len,struct snmp_node_instance * cell_instance)96 interfaces_Table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance)
97 {
98 u32_t ifIndex;
99 struct netif *netif;
100
101 LWIP_UNUSED_ARG(column);
102
103 /* check if incoming OID length and if values are in plausible range */
104 if (!snmp_oid_in_range(row_oid, row_oid_len, interfaces_Table_oid_ranges, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges))) {
105 return SNMP_ERR_NOSUCHINSTANCE;
106 }
107
108 /* get netif index from incoming OID */
109 ifIndex = row_oid[0];
110
111 /* find netif with index */
112 netif = netif_list;
113 while (netif != NULL) {
114 if (netif_to_num(netif) == ifIndex) {
115 /* store netif pointer for subsequent operations (get/test/set) */
116 cell_instance->reference.ptr = netif;
117 return SNMP_ERR_NOERROR;
118 }
119 netif = netif->next;
120 }
121
122 /* not found */
123 return SNMP_ERR_NOSUCHINSTANCE;
124 }
125
126 static snmp_err_t
interfaces_Table_get_next_cell_instance(const u32_t * column,struct snmp_obj_id * row_oid,struct snmp_node_instance * cell_instance)127 interfaces_Table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance)
128 {
129 struct netif *netif;
130 struct snmp_next_oid_state state;
131 u32_t result_temp[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)];
132
133 LWIP_UNUSED_ARG(column);
134
135 /* init struct to search next oid */
136 snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges));
137
138 /* iterate over all possible OIDs to find the next one */
139 netif = netif_list;
140 while (netif != NULL) {
141 u32_t test_oid[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)];
142 test_oid[0] = netif_to_num(netif);
143
144 /* check generated OID: is it a candidate for the next one? */
145 snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges), netif);
146
147 netif = netif->next;
148 }
149
150 /* did we find a next one? */
151 if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
152 snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
153 /* store netif pointer for subsequent operations (get/test/set) */
154 cell_instance->reference.ptr = /* (struct netif*) */state.reference;
155 return SNMP_ERR_NOERROR;
156 }
157
158 /* not found */
159 return SNMP_ERR_NOSUCHINSTANCE;
160 }
161
162 static s16_t
interfaces_Table_get_value(struct snmp_node_instance * instance,void * value)163 interfaces_Table_get_value(struct snmp_node_instance* instance, void* value)
164 {
165 struct netif *netif = (struct netif*)instance->reference.ptr;
166 u32_t* value_u32 = (u32_t*)value;
167 s32_t* value_s32 = (s32_t*)value;
168 u16_t value_len;
169
170 switch (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id))
171 {
172 case 1: /* ifIndex */
173 *value_s32 = netif_to_num(netif);
174 value_len = sizeof(*value_s32);
175 break;
176 case 2: /* ifDescr */
177 value_len = sizeof(netif->name);
178 MEMCPY(value, netif->name, value_len);
179 break;
180 case 3: /* ifType */
181 *value_s32 = netif->link_type;
182 value_len = sizeof(*value_s32);
183 break;
184 case 4: /* ifMtu */
185 *value_s32 = netif->mtu;
186 value_len = sizeof(*value_s32);
187 break;
188 case 5: /* ifSpeed */
189 *value_u32 = netif->link_speed;
190 value_len = sizeof(*value_u32);
191 break;
192 case 6: /* ifPhysAddress */
193 value_len = sizeof(netif->hwaddr);
194 MEMCPY(value, &netif->hwaddr, value_len);
195 break;
196 case 7: /* ifAdminStatus */
197 if (netif_is_up(netif)) {
198 *value_s32 = iftable_ifOperStatus_up;
199 } else {
200 *value_s32 = iftable_ifOperStatus_down;
201 }
202 value_len = sizeof(*value_s32);
203 break;
204 case 8: /* ifOperStatus */
205 if (netif_is_up(netif)) {
206 if (netif_is_link_up(netif)) {
207 *value_s32 = iftable_ifAdminStatus_up;
208 } else {
209 *value_s32 = iftable_ifAdminStatus_lowerLayerDown;
210 }
211 } else {
212 *value_s32 = iftable_ifAdminStatus_down;
213 }
214 value_len = sizeof(*value_s32);
215 break;
216 case 9: /* ifLastChange */
217 *value_u32 = netif->ts;
218 value_len = sizeof(*value_u32);
219 break;
220 case 10: /* ifInOctets */
221 *value_u32 = netif->mib2_counters.ifinoctets;
222 value_len = sizeof(*value_u32);
223 break;
224 case 11: /* ifInUcastPkts */
225 *value_u32 = netif->mib2_counters.ifinucastpkts;
226 value_len = sizeof(*value_u32);
227 break;
228 case 12: /* ifInNUcastPkts */
229 *value_u32 = netif->mib2_counters.ifinnucastpkts;
230 value_len = sizeof(*value_u32);
231 break;
232 case 13: /* ifInDiscards */
233 *value_u32 = netif->mib2_counters.ifindiscards;
234 value_len = sizeof(*value_u32);
235 break;
236 case 14: /* ifInErrors */
237 *value_u32 = netif->mib2_counters.ifinerrors;
238 value_len = sizeof(*value_u32);
239 break;
240 case 15: /* ifInUnkownProtos */
241 *value_u32 = netif->mib2_counters.ifinunknownprotos;
242 value_len = sizeof(*value_u32);
243 break;
244 case 16: /* ifOutOctets */
245 *value_u32 = netif->mib2_counters.ifoutoctets;
246 value_len = sizeof(*value_u32);
247 break;
248 case 17: /* ifOutUcastPkts */
249 *value_u32 = netif->mib2_counters.ifoutucastpkts;
250 value_len = sizeof(*value_u32);
251 break;
252 case 18: /* ifOutNUcastPkts */
253 *value_u32 = netif->mib2_counters.ifoutnucastpkts;
254 value_len = sizeof(*value_u32);
255 break;
256 case 19: /* ifOutDiscarts */
257 *value_u32 = netif->mib2_counters.ifoutdiscards;
258 value_len = sizeof(*value_u32);
259 break;
260 case 20: /* ifOutErrors */
261 *value_u32 = netif->mib2_counters.ifouterrors;
262 value_len = sizeof(*value_u32);
263 break;
264 case 21: /* ifOutQLen */
265 *value_u32 = iftable_ifOutQLen;
266 value_len = sizeof(*value_u32);
267 break;
268 /** @note returning zeroDotZero (0.0) no media specific MIB support */
269 case 22: /* ifSpecific */
270 value_len = snmp_zero_dot_zero.len * sizeof(u32_t);
271 MEMCPY(value, snmp_zero_dot_zero.id, value_len);
272 break;
273 default:
274 return 0;
275 }
276
277 return value_len;
278 }
279
280 #if !SNMP_SAFE_REQUESTS
281
282 static snmp_err_t
interfaces_Table_set_test(struct snmp_node_instance * instance,u16_t len,void * value)283 interfaces_Table_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
284 {
285 s32_t *sint_ptr = (s32_t*)value;
286
287 /* stack should never call this method for another column,
288 because all other columns are set to readonly */
289 LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7));
290 LWIP_UNUSED_ARG(len);
291
292 if (*sint_ptr == 1 || *sint_ptr == 2) {
293 return SNMP_ERR_NOERROR;
294 }
295
296 return SNMP_ERR_WRONGVALUE;
297 }
298
299 static snmp_err_t
interfaces_Table_set_value(struct snmp_node_instance * instance,u16_t len,void * value)300 interfaces_Table_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
301 {
302 struct netif *netif = (struct netif*)instance->reference.ptr;
303 s32_t *sint_ptr = (s32_t*)value;
304
305 /* stack should never call this method for another column,
306 because all other columns are set to readonly */
307 LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7));
308 LWIP_UNUSED_ARG(len);
309
310 if (*sint_ptr == 1) {
311 netif_set_up(netif);
312 } else if (*sint_ptr == 2) {
313 netif_set_down(netif);
314 }
315
316 return SNMP_ERR_NOERROR;
317 }
318
319 #endif /* SNMP_SAFE_REQUESTS */
320
321 static const struct snmp_scalar_node interfaces_Number = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_INTEGER, interfaces_get_value);
322
323 static const struct snmp_table_col_def interfaces_Table_columns[] = {
324 { 1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifIndex */
325 { 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifDescr */
326 { 3, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifType */
327 { 4, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifMtu */
328 { 5, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifSpeed */
329 { 6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifPhysAddress */
330 #if !SNMP_SAFE_REQUESTS
331 { 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE }, /* ifAdminStatus */
332 #else
333 { 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifAdminStatus */
334 #endif
335 { 8, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOperStatus */
336 { 9, SNMP_ASN1_TYPE_TIMETICKS, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifLastChange */
337 { 10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInOctets */
338 { 11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUcastPkts */
339 { 12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInNUcastPkts */
340 { 13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInDiscarts */
341 { 14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInErrors */
342 { 15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUnkownProtos */
343 { 16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutOctets */
344 { 17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutUcastPkts */
345 { 18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutNUcastPkts */
346 { 19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutDiscarts */
347 { 20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutErrors */
348 { 21, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutQLen */
349 { 22, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY } /* ifSpecific */
350 };
351
352 #if !SNMP_SAFE_REQUESTS
353 static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE(
354 2, interfaces_Table_columns,
355 interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
356 interfaces_Table_get_value, interfaces_Table_set_test, interfaces_Table_set_value);
357 #else
358 static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE(
359 2, interfaces_Table_columns,
360 interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
361 interfaces_Table_get_value, NULL, NULL);
362 #endif
363
364 /* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
365 CREATE_LWIP_SYNC_NODE(1, interfaces_Number)
366 CREATE_LWIP_SYNC_NODE(2, interfaces_Table)
367
368 static const struct snmp_node* const interface_nodes[] = {
369 &SYNC_NODE_NAME(interfaces_Number).node.node,
370 &SYNC_NODE_NAME(interfaces_Table).node.node
371 };
372
373 const struct snmp_tree_node snmp_mib2_interface_root = SNMP_CREATE_TREE_NODE(2, interface_nodes);
374
375 #endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */
376