1 /** 2 * @file 3 * Management Information Base II (RFC1213) UDP 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/udp.h" 43 #include "lwip/stats.h" 44 45 #include <string.h> 46 47 #if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP 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 /* --- udp .1.3.6.1.2.1.7 ----------------------------------------------------- */ 59 60 static s16_t 61 udp_get_value(struct snmp_node_instance* instance, void* value) 62 { 63 u32_t *uint_ptr = (u32_t*)value; 64 65 switch (instance->node->oid) { 66 case 1: /* udpInDatagrams */ 67 *uint_ptr = STATS_GET(mib2.udpindatagrams); 68 return sizeof(*uint_ptr); 69 case 2: /* udpNoPorts */ 70 *uint_ptr = STATS_GET(mib2.udpnoports); 71 return sizeof(*uint_ptr); 72 case 3: /* udpInErrors */ 73 *uint_ptr = STATS_GET(mib2.udpinerrors); 74 return sizeof(*uint_ptr); 75 case 4: /* udpOutDatagrams */ 76 *uint_ptr = STATS_GET(mib2.udpoutdatagrams); 77 return sizeof(*uint_ptr); 78 case 8: /* udpHCInDatagrams */ 79 memset(value, 0, 2*sizeof(u32_t)); /* not supported */ 80 return 2*sizeof(u32_t); 81 case 9: /* udpHCOutDatagrams */ 82 memset(value, 0, 2*sizeof(u32_t)); /* not supported */ 83 return 2*sizeof(u32_t); 84 default: 85 LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_value(): unknown id: %"S32_F"\n", instance->node->oid)); 86 break; 87 } 88 89 return 0; 90 } 91 92 /* --- udpEndpointTable --- */ 93 94 static snmp_err_t 95 udp_endpointTable_get_cell_value_core(const u32_t* column, union snmp_variant_value* value) 96 { 97 /* all items except udpEndpointProcess are declared as not-accessible */ 98 switch (*column) { 99 case 8: /* udpEndpointProcess */ 100 value->u32 = 0; /* not supported */ 101 break; 102 default: 103 return SNMP_ERR_NOSUCHINSTANCE; 104 } 105 106 return SNMP_ERR_NOERROR; 107 } 108 109 static snmp_err_t 110 udp_endpointTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) 111 { 112 ip_addr_t local_ip, remote_ip; 113 u16_t local_port, remote_port; 114 struct udp_pcb *pcb; 115 u8_t idx = 0; 116 117 LWIP_UNUSED_ARG(value_len); 118 119 /* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */ 120 idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port); 121 if (idx == 0) { 122 return SNMP_ERR_NOSUCHINSTANCE; 123 } 124 125 /* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */ 126 idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &remote_ip, &remote_port); 127 if (idx == 0) { 128 return SNMP_ERR_NOSUCHINSTANCE; 129 } 130 131 /* udpEndpointInstance */ 132 if (row_oid_len < (idx+1)) { 133 return SNMP_ERR_NOSUCHINSTANCE; 134 } 135 if (row_oid[idx] != 0) { 136 return SNMP_ERR_NOSUCHINSTANCE; 137 } 138 139 /* find udp_pcb with requested ip and port*/ 140 pcb = udp_pcbs; 141 while (pcb != NULL) { 142 if (ip_addr_cmp(&local_ip, &pcb->local_ip) && 143 (local_port == pcb->local_port) && 144 ip_addr_cmp(&remote_ip, &pcb->remote_ip) && 145 (remote_port == pcb->remote_port)) { 146 /* fill in object properties */ 147 return udp_endpointTable_get_cell_value_core(column, value); 148 } 149 pcb = pcb->next; 150 } 151 152 /* not found */ 153 return SNMP_ERR_NOSUCHINSTANCE; 154 } 155 156 static snmp_err_t 157 udp_endpointTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) 158 { 159 struct udp_pcb *pcb; 160 struct snmp_next_oid_state state; 161 /* 1x udpEndpointLocalAddressType + 1x OID len + 16x udpEndpointLocalAddress + 1x udpEndpointLocalPort + 162 * 1x udpEndpointRemoteAddressType + 1x OID len + 16x udpEndpointRemoteAddress + 1x udpEndpointRemotePort + 163 * 1x udpEndpointInstance = 39 164 */ 165 u32_t result_temp[39]; 166 167 LWIP_UNUSED_ARG(value_len); 168 169 /* init struct to search next oid */ 170 snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp)); 171 172 /* iterate over all possible OIDs to find the next one */ 173 pcb = udp_pcbs; 174 while (pcb != NULL) { 175 u32_t test_oid[LWIP_ARRAYSIZE(result_temp)]; 176 u8_t idx = 0; 177 178 /* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */ 179 idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]); 180 181 /* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */ 182 idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]); 183 184 test_oid[idx] = 0; /* udpEndpointInstance */ 185 idx++; 186 187 /* check generated OID: is it a candidate for the next one? */ 188 snmp_next_oid_check(&state, test_oid, idx, NULL); 189 190 pcb = pcb->next; 191 } 192 193 /* did we find a next one? */ 194 if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { 195 snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); 196 /* fill in object properties */ 197 return udp_endpointTable_get_cell_value_core(column, value); 198 } else { 199 /* not found */ 200 return SNMP_ERR_NOSUCHINSTANCE; 201 } 202 } 203 204 /* --- udpTable --- */ 205 206 #if LWIP_IPV4 207 208 /* list of allowed value ranges for incoming OID */ 209 static const struct snmp_oid_range udp_Table_oid_ranges[] = { 210 { 0, 0xff }, /* IP A */ 211 { 0, 0xff }, /* IP B */ 212 { 0, 0xff }, /* IP C */ 213 { 0, 0xff }, /* IP D */ 214 { 1, 0xffff } /* Port */ 215 }; 216 217 static snmp_err_t 218 udp_Table_get_cell_value_core(struct udp_pcb *pcb, const u32_t* column, union snmp_variant_value* value, u32_t* value_len) 219 { 220 LWIP_UNUSED_ARG(value_len); 221 222 switch (*column) { 223 case 1: /* udpLocalAddress */ 224 /* set reference to PCB local IP and return a generic node that copies IP4 addresses */ 225 value->u32 = ip_2_ip4(&pcb->local_ip)->addr; 226 break; 227 case 2: /* udpLocalPort */ 228 /* set reference to PCB local port and return a generic node that copies u16_t values */ 229 value->u32 = pcb->local_port; 230 break; 231 default: 232 return SNMP_ERR_NOSUCHINSTANCE; 233 } 234 235 return SNMP_ERR_NOERROR; 236 } 237 238 static snmp_err_t 239 udp_Table_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) 240 { 241 ip4_addr_t ip; 242 u16_t port; 243 struct udp_pcb *pcb; 244 245 /* check if incoming OID length and if values are in plausible range */ 246 if (!snmp_oid_in_range(row_oid, row_oid_len, udp_Table_oid_ranges, LWIP_ARRAYSIZE(udp_Table_oid_ranges))) { 247 return SNMP_ERR_NOSUCHINSTANCE; 248 } 249 250 /* get IP and port from incoming OID */ 251 snmp_oid_to_ip4(&row_oid[0], &ip); /* we know it succeeds because of oid_in_range check above */ 252 port = (u16_t)row_oid[4]; 253 254 /* find udp_pcb with requested ip and port*/ 255 pcb = udp_pcbs; 256 while (pcb != NULL) { 257 if (IP_IS_V4_VAL(pcb->local_ip)) { 258 if (ip4_addr_cmp(&ip, ip_2_ip4(&pcb->local_ip)) && (port == pcb->local_port)) { 259 /* fill in object properties */ 260 return udp_Table_get_cell_value_core(pcb, column, value, value_len); 261 } 262 } 263 pcb = pcb->next; 264 } 265 266 /* not found */ 267 return SNMP_ERR_NOSUCHINSTANCE; 268 } 269 270 static snmp_err_t 271 udp_Table_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) 272 { 273 struct udp_pcb *pcb; 274 struct snmp_next_oid_state state; 275 u32_t result_temp[LWIP_ARRAYSIZE(udp_Table_oid_ranges)]; 276 277 /* init struct to search next oid */ 278 snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(udp_Table_oid_ranges)); 279 280 /* iterate over all possible OIDs to find the next one */ 281 pcb = udp_pcbs; 282 while (pcb != NULL) { 283 u32_t test_oid[LWIP_ARRAYSIZE(udp_Table_oid_ranges)]; 284 285 if (IP_IS_V4_VAL(pcb->local_ip)) { 286 snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]); 287 test_oid[4] = pcb->local_port; 288 289 /* check generated OID: is it a candidate for the next one? */ 290 snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(udp_Table_oid_ranges), pcb); 291 } 292 293 pcb = pcb->next; 294 } 295 296 /* did we find a next one? */ 297 if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { 298 snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); 299 /* fill in object properties */ 300 return udp_Table_get_cell_value_core((struct udp_pcb*)state.reference, column, value, value_len); 301 } else { 302 /* not found */ 303 return SNMP_ERR_NOSUCHINSTANCE; 304 } 305 } 306 307 #endif /* LWIP_IPV4 */ 308 309 static const struct snmp_scalar_node udp_inDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_COUNTER, udp_get_value); 310 static const struct snmp_scalar_node udp_noPorts = SNMP_SCALAR_CREATE_NODE_READONLY(2, SNMP_ASN1_TYPE_COUNTER, udp_get_value); 311 static const struct snmp_scalar_node udp_inErrors = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_COUNTER, udp_get_value); 312 static const struct snmp_scalar_node udp_outDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_COUNTER, udp_get_value); 313 static const struct snmp_scalar_node udp_HCInDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER64, udp_get_value); 314 static const struct snmp_scalar_node udp_HCOutDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_COUNTER64, udp_get_value); 315 316 #if LWIP_IPV4 317 static const struct snmp_table_simple_col_def udp_Table_columns[] = { 318 { 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* udpLocalAddress */ 319 { 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpLocalPort */ 320 }; 321 static const struct snmp_table_simple_node udp_Table = SNMP_TABLE_CREATE_SIMPLE(5, udp_Table_columns, udp_Table_get_cell_value, udp_Table_get_next_cell_instance_and_value); 322 #endif /* LWIP_IPV4 */ 323 324 static const struct snmp_table_simple_col_def udp_endpointTable_columns[] = { 325 /* all items except udpEndpointProcess are declared as not-accessible */ 326 { 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpEndpointProcess */ 327 }; 328 329 static const struct snmp_table_simple_node udp_endpointTable = SNMP_TABLE_CREATE_SIMPLE(7, udp_endpointTable_columns, udp_endpointTable_get_cell_value, udp_endpointTable_get_next_cell_instance_and_value); 330 331 /* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */ 332 CREATE_LWIP_SYNC_NODE(1, udp_inDatagrams) 333 CREATE_LWIP_SYNC_NODE(2, udp_noPorts) 334 CREATE_LWIP_SYNC_NODE(3, udp_inErrors) 335 CREATE_LWIP_SYNC_NODE(4, udp_outDatagrams) 336 #if LWIP_IPV4 337 CREATE_LWIP_SYNC_NODE(5, udp_Table) 338 #endif /* LWIP_IPV4 */ 339 CREATE_LWIP_SYNC_NODE(7, udp_endpointTable) 340 CREATE_LWIP_SYNC_NODE(8, udp_HCInDatagrams) 341 CREATE_LWIP_SYNC_NODE(9, udp_HCOutDatagrams) 342 343 static const struct snmp_node* const udp_nodes[] = { 344 &SYNC_NODE_NAME(udp_inDatagrams).node.node, 345 &SYNC_NODE_NAME(udp_noPorts).node.node, 346 &SYNC_NODE_NAME(udp_inErrors).node.node, 347 &SYNC_NODE_NAME(udp_outDatagrams).node.node, 348 #if LWIP_IPV4 349 &SYNC_NODE_NAME(udp_Table).node.node, 350 #endif /* LWIP_IPV4 */ 351 &SYNC_NODE_NAME(udp_endpointTable).node.node, 352 &SYNC_NODE_NAME(udp_HCInDatagrams).node.node, 353 &SYNC_NODE_NAME(udp_HCOutDatagrams).node.node 354 }; 355 356 const struct snmp_tree_node snmp_mib2_udp_root = SNMP_CREATE_TREE_NODE(7, udp_nodes); 357 #endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP */ 358