diff --git a/examples/snmp-server/Makefile b/examples/snmp-server/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c2e7b8952dcf472b7c5308be56fb66aa66b62c72 --- /dev/null +++ b/examples/snmp-server/Makefile @@ -0,0 +1,10 @@ +CONTIKI_PROJECT = snmp-server +all: $(CONTIKI_PROJECT) + +MODULES += os/net/app-layer/snmp + +MODULES_REL += ./resources + +CONTIKI = ../.. + +include $(CONTIKI)/Makefile.include diff --git a/examples/snmp-server/project-conf.h b/examples/snmp-server/project-conf.h new file mode 100644 index 0000000000000000000000000000000000000000..724e89485b19ec1a39881e4e87162fede1d2bf0b --- /dev/null +++ b/examples/snmp-server/project-conf.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +#define LOG_CONF_LEVEL_SNMP LOG_LEVEL_DBG diff --git a/examples/snmp-server/resources/snmp-SNMP-MIB-2-System.c b/examples/snmp-server/resources/snmp-SNMP-MIB-2-System.c new file mode 100644 index 0000000000000000000000000000000000000000..f87d2bd2f07c7937279c6ca4e8a99d43dca56183 --- /dev/null +++ b/examples/snmp-server/resources/snmp-SNMP-MIB-2-System.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "snmp-api.h" + +/*---------------------------------------------------------------------------*/ +static void +sysDescr_handler(snmp_varbind_t *varbind, uint32_t *oid); + +MIB_RESOURCE(sysDescr, sysDescr_handler, 1, 3, 6, 1, 2, 1, 1, 1, 0); + +static void +sysDescr_handler(snmp_varbind_t *varbind, uint32_t *oid) +{ + snmp_api_set_string(varbind, oid, CONTIKI_VERSION_STRING); +} +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +static void +sysObjectID_handler(snmp_varbind_t *varbind, uint32_t *oid); + +MIB_RESOURCE(sysObjectID, sysObjectID_handler, 1, 3, 6, 1, 2, 1, 1, 2, 0); + +static void +sysObjectID_handler(snmp_varbind_t *varbind, uint32_t *oid) +{ + OID(sysObjectID_oid, 1, 3, 6, 1, 4, 1, 54352); + snmp_api_set_oid(varbind, oid, sysObjectID_oid); +} +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +static void +sysUpTime_handler(snmp_varbind_t *varbind, uint32_t *oid); + +MIB_RESOURCE(sysUpTime, sysUpTime_handler, 1, 3, 6, 1, 2, 1, 1, 3, 0); + +static void +sysUpTime_handler(snmp_varbind_t *varbind, uint32_t *oid) +{ + snmp_api_set_time_ticks(varbind, oid, clock_seconds() * 100); +} +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +static void +sysContact_handler(snmp_varbind_t *varbind, uint32_t *oid); + +MIB_RESOURCE(sysContact, sysContact_handler, 1, 3, 6, 1, 2, 1, 1, 4, 0); + +static void +sysContact_handler(snmp_varbind_t *varbind, uint32_t *oid) +{ + snmp_api_set_string(varbind, oid, "Contiki-NG, https://github.com/contiki-ng/contiki-ng"); +} +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +static void +sysName_handler(snmp_varbind_t *varbind, uint32_t *oid); + +MIB_RESOURCE(sysName, sysName_handler, 1, 3, 6, 1, 2, 1, 1, 5, 0); + +static void +sysName_handler(snmp_varbind_t *varbind, uint32_t *oid) +{ + snmp_api_set_string(varbind, oid, "Contiki-NG - "CONTIKI_TARGET_STRING); +} +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +static void +sysLocation_handler(snmp_varbind_t *varbind, uint32_t *oid); + +MIB_RESOURCE(sysLocation, sysLocation_handler, 1, 3, 6, 1, 2, 1, 1, 6, 0); + +static void +sysLocation_handler(snmp_varbind_t *varbind, uint32_t *oid) +{ + snmp_api_set_string(varbind, oid, ""); +} +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +static void +sysServices_handler(snmp_varbind_t *varbind, uint32_t *oid); + +MIB_RESOURCE(sysServices, sysServices_handler, 1, 3, 6, 1, 2, 1, 1, 7, 0); + +static void +sysServices_handler(snmp_varbind_t *varbind, uint32_t *oid) +{ + snmp_api_set_time_ticks(varbind, oid, clock_seconds() * 100); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/snmp-server/snmp-server.c b/examples/snmp-server/snmp-server.c new file mode 100644 index 0000000000000000000000000000000000000000..dbc638f05e5e307d30e2fc7eefe552d340a0c764 --- /dev/null +++ b/examples/snmp-server/snmp-server.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "snmp-api.h" + +/*---------------------------------------------------------------------------*/ +PROCESS_NAME(snmp_server_process); +AUTOSTART_PROCESSES(&snmp_server_process); +/*---------------------------------------------------------------------------*/ + +extern snmp_mib_resource_t + sysDescr, + sysObjectID, + sysUpTime, + sysContact, + sysName, + sysLocation, + sysServices; + +/*---------------------------------------------------------------------------*/ + +PROCESS(snmp_server_process, "SNMP Server"); + +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(snmp_server_process, ev, data) +{ + + PROCESS_BEGIN(); + + snmp_api_add_resource(&sysDescr); + snmp_api_add_resource(&sysObjectID); + snmp_api_add_resource(&sysUpTime); + snmp_api_add_resource(&sysContact); + snmp_api_add_resource(&sysName); + snmp_api_add_resource(&sysLocation); + snmp_api_add_resource(&sysServices); + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/os/contiki-main.c b/os/contiki-main.c index 43e3017464a74e73a60b443a992a3f484d66042a..dbeb26e521d72a69a1adfd256b052c954824b0a5 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -50,6 +50,7 @@ #include "net/queuebuf.h" #include "net/app-layer/coap/coap-engine.h" +#include "net/app-layer/snmp/snmp.h" #include "services/rpl-border-router/rpl-border-router.h" #include "services/orchestra/orchestra.h" #include "services/shell/serial-shell.h" @@ -147,6 +148,11 @@ main(void) LOG_DBG("With CoAP\n"); #endif /* BUILD_WITH_SHELL */ +#if BUILD_WITH_SNMP + snmp_init(); + LOG_DBG("With SNMP\n"); +#endif /* BUILD_WITH_SNMP */ + #if BUILD_WITH_SIMPLE_ENERGEST simple_energest_init(); #endif /* BUILD_WITH_SIMPLE_ENERGEST */ diff --git a/os/net/app-layer/snmp/module-macros.h b/os/net/app-layer/snmp/module-macros.h new file mode 100644 index 0000000000000000000000000000000000000000..8396775a76e63231d9991910d14ca3d863a3e694 --- /dev/null +++ b/os/net/app-layer/snmp/module-macros.h @@ -0,0 +1 @@ +#define BUILD_WITH_SNMP 1 diff --git a/os/net/app-layer/snmp/snmp-api.c b/os/net/app-layer/snmp/snmp-api.c new file mode 100644 index 0000000000000000000000000000000000000000..50d252df01812b66c38993c74f620efa9e9d5ef2 --- /dev/null +++ b/os/net/app-layer/snmp/snmp-api.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +#include "contiki.h" + +#include "snmp-api.h" + +#include "snmp-message.h" +#include "snmp-ber.h" +#include "snmp-oid.h" + +static void +snmp_api_replace_oid(snmp_varbind_t *varbind, uint32_t *oid) +{ + uint8_t i; + + i = 0; + while(oid[i] != ((uint32_t)-1)) { + varbind->oid[i] = oid[i]; + i++; + } + varbind->oid[i] = ((uint32_t)-1); +} +/*---------------------------------------------------------------------------*/ +void +snmp_api_set_string(snmp_varbind_t *varbind, uint32_t *oid, char *string) +{ + + snmp_api_replace_oid(varbind, oid); + varbind->value_type = BER_DATA_TYPE_OCTET_STRING; + varbind->value.string.string = string; + varbind->value.string.length = strlen(string); +} +/*---------------------------------------------------------------------------*/ +void +snmp_api_set_time_ticks(snmp_varbind_t *varbind, uint32_t *oid, uint32_t integer) +{ + + snmp_api_replace_oid(varbind, oid); + varbind->value_type = SNMP_DATA_TYPE_TIME_TICKS; + varbind->value.integer = integer; +} +/*---------------------------------------------------------------------------*/ +void +snmp_api_set_oid(snmp_varbind_t *varbind, uint32_t *oid, uint32_t *ret_oid) +{ + + snmp_api_replace_oid(varbind, oid); + varbind->value_type = BER_DATA_TYPE_OID; + varbind->value.oid = ret_oid; +} +/*---------------------------------------------------------------------------*/ +void +snmp_api_add_resource(snmp_mib_resource_t *new_resource) +{ + return snmp_mib_add(new_resource); +} diff --git a/os/net/app-layer/snmp/snmp-api.h b/os/net/app-layer/snmp/snmp-api.h new file mode 100644 index 0000000000000000000000000000000000000000..a82704f946fdaafddf8b7ce4d42de446709c3499 --- /dev/null +++ b/os/net/app-layer/snmp/snmp-api.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * The public API for the Contiki-NG SNMP implementation + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +/** + * \addtogroup snmp + * @{ + */ + +#ifndef SNMP_API_H_ +#define SNMP_API_H_ + +#include "snmp.h" +#include "snmp-mib.h" + +/** + * \defgroup SNMPAPI This is the SNMP Public API + * @{ + * + * This group contains all the functions that can be used outside the OS level. + * The function outside this header can be changed without notice + */ + +/** + * @brief The MIB resource handler typedef + * + * @param varbind The varbind that is being changed + * @param oid The oid from the resource + */ +typedef void (*snmp_mib_resource_handler_t)(snmp_varbind_t *varbind, uint32_t *oid); + +/** + * @brief The MIB Resource struct + */ +typedef struct snmp_mib_resource_s snmp_mib_resource_t; + +/** + * @brief Initializes statically an oid with the "null" terminator + * + * @remarks This should be used inside handlers when declaring an oid + * + * @param name A name for the oid + * @param ... The Oid (comma-separeted) + */ +#define OID(name, ...) \ + static uint32_t name[] = { __VA_ARGS__, -1 }; + +/** + * @brief Declare a MIB resource + * + * @param name A name for the MIB resource + * @param handler The handler function for this resource + * @param ... The OID (comma-separated) + */ +#define MIB_RESOURCE(name, handler, ...) \ + uint32_t name##_oid[] = { __VA_ARGS__, -1 }; \ + snmp_mib_resource_t name = { NULL, name##_oid, handler }; + +/** + * @brief Function to set a varbind with a string + * + * This function should be used inside a handler to set the varbind correctly + * + * @param varbind The varbind from the handler + * @param oid The oid from the handler + * @param string The string + */ +void +snmp_api_set_string(snmp_varbind_t *varbind, uint32_t *oid, char *string); + +/** + * @brief Function to set a varbind with a time tick + * + * This function should be used inside a handler to set the varbind correctly + * + * @param varbind The varbind from the handler + * @param oid The oid from the handler + * @param integer The time tick value + */ +void +snmp_api_set_time_ticks(snmp_varbind_t *varbind, uint32_t *oid, uint32_t integer); + +/** + * @brief Function to set a varbind with a oid + * + * This function should be used inside a handler to set the varbind correctly + * + * @param varbind The varbind from the handler + * @param oid The oid from the handler + * @param ret_oid The oid value + */ +void +snmp_api_set_oid(snmp_varbind_t *varbind, uint32_t *oid, uint32_t *ret_oid); + +/** + * @brief Function to add a new resource + * + * @param new_resource The resource + */ +void +snmp_api_add_resource(snmp_mib_resource_t *new_resource); + +/** @}*/ + +#endif /* SNMP_API_H_ */ +/** @} */ diff --git a/os/net/app-layer/snmp/snmp-ber.c b/os/net/app-layer/snmp/snmp-ber.c new file mode 100644 index 0000000000000000000000000000000000000000..f5c520d0cf34affae3abb98e0e08ac5cf0091c8a --- /dev/null +++ b/os/net/app-layer/snmp/snmp-ber.c @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +#include "contiki.h" + +#include "snmp.h" +#include "snmp-ber.h" + +#define LOG_MODULE "SNMP [ber]" +#define LOG_LEVEL LOG_LEVEL_SNMP + +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_encode_type(unsigned char *out, uint32_t *out_len, uint8_t type) +{ + *out-- = type; + (*out_len)++; + return out; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_encode_length(unsigned char *out, uint32_t *out_len, uint8_t length) +{ + *out-- = length; + (*out_len)++; + return out; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_encode_integer(unsigned char *out, uint32_t *out_len, uint32_t number) +{ + uint32_t original_out_len; + + original_out_len = *out_len; + do { + (*out_len)++; + *out-- = (uint8_t)(number & 0xFF); + number >>= 8; + } while(number); + + out = snmp_ber_encode_length(out, out_len, ((*out_len - original_out_len) & 0xFF)); + out = snmp_ber_encode_type(out, out_len, BER_DATA_TYPE_INTEGER); + + return out; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_encode_unsigned_integer(unsigned char *out, uint32_t *out_len, uint8_t type, uint32_t number) +{ + uint32_t original_out_len; + + original_out_len = *out_len; + do { + (*out_len)++; + *out-- = (uint8_t)(number & 0xFF); + number >>= 8; + } while(number); + + out = snmp_ber_encode_length(out, out_len, ((*out_len - original_out_len) & 0xFF)); + out = snmp_ber_encode_type(out, out_len, type); + + return out; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_encode_string_len(unsigned char *out, uint32_t *out_len, const char *str, uint32_t length) +{ + uint32_t i; + + str += length - 1; + for(i = 0; i < length; ++i) { + (*out_len)++; + *out-- = (uint8_t)*str--; + } + + out = snmp_ber_encode_length(out, out_len, length); + out = snmp_ber_encode_type(out, out_len, BER_DATA_TYPE_OCTET_STRING); + + return out; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_encode_null(unsigned char *out, uint32_t *out_len, uint8_t type) +{ + (*out_len)++; + *out-- = 0x00; + out = snmp_ber_encode_type(out, out_len, type); + + return out; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_decode_type(unsigned char *buff, uint32_t *buff_len, uint8_t *type) +{ + *type = *buff++; + (*buff_len)--; + + return buff; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_decode_length(unsigned char *buff, uint32_t *buff_len, uint8_t *length) +{ + *length = *buff++; + (*buff_len)--; + + return buff; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_decode_integer(unsigned char *buf, uint32_t *buff_len, uint32_t *num) +{ + uint8_t i, len, type; + + buf = snmp_ber_decode_type(buf, buff_len, &type); + + if(type != BER_DATA_TYPE_INTEGER) { + /* + * Sanity check + * Invalid type in buffer + */ + return NULL; + } + + buf = snmp_ber_decode_length(buf, buff_len, &len); + + if(len > 4) { + /* + * Sanity check + * It will not fit in the uint32_t + */ + return NULL; + } + + *num = (uint32_t)(*buf++ & 0xFF); + (*buff_len)--; + for(i = 1; i < len; ++i) { + *num <<= 8; + *num |= (uint8_t)(*buf++ & 0xFF); + (*buff_len)--; + } + + return buf; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_decode_unsigned_integer(unsigned char *buf, uint32_t *buff_len, uint8_t expected_type, uint32_t *num) +{ + uint8_t i, len, type; + + buf = snmp_ber_decode_type(buf, buff_len, &type); + + if(type != expected_type) { + /* + * Sanity check + * Invalid type in buffer + */ + return NULL; + } + + buf = snmp_ber_decode_length(buf, buff_len, &len); + + if(len > 4) { + /* + * Sanity check + * It will not fit in the uint32_t + */ + return NULL; + } + + *num = (uint32_t)(*buf++ & 0xFF); + (*buff_len)--; + for(i = 1; i < len; ++i) { + *num <<= 8; + *num |= (uint8_t)(*buf++ & 0xFF); + (*buff_len)--; + } + + return buf; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_decode_string_len_buffer(unsigned char *buf, uint32_t *buff_len, const char **str, uint32_t *length) +{ + uint8_t type, i, length_bytes; + + buf = snmp_ber_decode_type(buf, buff_len, &type); + + if(type != BER_DATA_TYPE_OCTET_STRING) { + /* + * Sanity check + * Invalid type in buffer + */ + return NULL; + } + + if((*buf & 0x80) == 0) { + *length = (uint32_t)*buf++; + (*buff_len)--; + } else { + + length_bytes = (uint8_t)(*buf++ & 0x7F); + (*buff_len)--; + if(length_bytes > 4) { + /* + * Sanity check + * It will not fit in the uint32_t + */ + return NULL; + } + + *length = (uint32_t)*buf++; + (*buff_len)--; + for(i = 1; i < length_bytes; ++i) { + *length <<= 8; + *length |= *buf++; + (*buff_len)--; + } + } + + *str = (const char *)buf; + *buff_len -= *length; + + return buf + *length; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_ber_decode_null(unsigned char *buf, uint32_t *buff_len) +{ + buf++; + (*buff_len)--; + + buf++; + (*buff_len)--; + + return buf; +} +/*---------------------------------------------------------------------------*/ diff --git a/os/net/app-layer/snmp/snmp-ber.h b/os/net/app-layer/snmp/snmp-ber.h new file mode 100644 index 0000000000000000000000000000000000000000..9111276dec6343de912db802dee1ec57187ef387 --- /dev/null +++ b/os/net/app-layer/snmp/snmp-ber.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +/** + * \addtogroup snmp + * @{ + */ + +#ifndef SNMP_BER_H_ +#define SNMP_BER_H_ + +#define BER_DATA_TYPE_INTEGER 0x02 +#define BER_DATA_TYPE_OCTET_STRING 0x04 +#define BER_DATA_TYPE_NULL 0x05 +#define BER_DATA_TYPE_OID 0x06 +#define BER_DATA_TYPE_SEQUENCE 0x30 + +/** + * @brief Encodes a type + * + * @param out A pointer to the end of the buffer + * @param out_len A pointer to the buffer length + * @param type A type + * + * @return NULL if error or the next entry in the buffer + */ +unsigned char * +snmp_ber_encode_type(unsigned char *out, uint32_t *out_len, uint8_t type); + +/** + * @brief Encodes the length + * + * @param out A pointer to the end of the buffer + * @param out_len A pointer to the buffer length + * @param length A length + * + * @return NULL if error or the next entry in the buffer + */ +unsigned char * +snmp_ber_encode_length(unsigned char *out, uint32_t *out_len, uint8_t length); + +/** + * @brief Encodes an integer + * + * @param out A pointer to the end of the buffer + * @param out_len A pointer to the buffer length + * @param integer A integer + * + * @return NULL if error or the next entry in the buffer + */ +unsigned char * +snmp_ber_encode_integer(unsigned char *out, uint32_t *out_len, uint32_t integer); + +/** + * @brief Encodes an unsigned integer + * + * @param out A pointer to the end of the buffer + * @param out_len A pointer to the buffer length + * @param type A type that represents an unsigned integer + * @param number A number + * + * @return NULL if error or the next entry in the buffer + */ +unsigned char * +snmp_ber_encode_unsigned_integer(unsigned char *out, uint32_t *out_len, uint8_t type, uint32_t number); + +/** + * @brief Encodes a string + * + * @param out A pointer to the end of the buffer + * @param out_len A pointer to the buffer length + * @param str A string + * @param length The string length + * + * @return NULL if error or the next entry in the buffer + */ +unsigned char * +snmp_ber_encode_string_len(unsigned char *out, uint32_t *out_len, const char *str, uint32_t length); + +/** + * @brief Encodes a null + * + * @param out A pointer to the end of the buffer + * @param out_len A pointer to the buffer length + * @param type A type + * + * @return NULL if error or the next entry in the buffer + */ +unsigned char * +snmp_ber_encode_null(unsigned char *out, uint32_t *out_len, uint8_t type); + +/** + * @brief Decodes a type + * + * @param buff A pointer to the beginning of the buffer + * @param buff_len A pointer to the buffer length + * @param type A pointer to the type + * + * @return NULL if error or the first entry after the oid in the buffer + */ +unsigned char * +snmp_ber_decode_type(unsigned char *buff, uint32_t *buff_len, uint8_t *type); + +/** + * @brief Decodes a length + * + * @param buff A pointer to the beginning of the buffer + * @param buff_len A pointer to the buffer length + * @param length A pointer to the length + * + * @return NULL if error or the first entry after the oid in the buffer + */ +unsigned char * +snmp_ber_decode_length(unsigned char *buff, uint32_t *buff_len, uint8_t *length); + +/** + * @brief Decodes an integer + * + * @param buff A pointer to the beginning of the buffer + * @param buff_len A pointer to the buffer length + * @param integer A pointer to the integer + * + * @return NULL if error or the first entry after the oid in the buffer + */ +unsigned char * +snmp_ber_decode_integer(unsigned char *buff, uint32_t *buff_len, uint32_t *integer); + +/** + * @brief Decodes an unsigned number + * + * @param buff A pointer to the beginning of the buffer + * @param buff_len A pointer to the buffer length + * @param expected_type The expected type that represents an unsingned integer + * @param number A pointer to the number + * + * @return NULL if error or the first entry after the oid in the buffer + */ +unsigned char * +snmp_ber_decode_unsigned_integer(unsigned char *buff, uint32_t *buff_len, uint8_t expected_type, uint32_t *number); + +/** + * @brief Decodes a string + * + * @param buff A pointer to the beginning of the buffer + * @param buff_len A pointer to the buffer length + * @param str A pointer to the string + * @param length A pointer to the string length + * + * @return NULL if error or the first entry after the oid in the buffer + */ +unsigned char * +snmp_ber_decode_string_len_buffer(unsigned char *buff, uint32_t *buff_len, const char **str, uint32_t *length); + +/** + * @brief Decodes a null + * + * @param buff A pointer to the beginning of the buffer + * @param buff_len A pointer to the buffer length + * + * @return NULL if error or the first entry after the oid in the buffer + */ +unsigned char * +snmp_ber_decode_null(unsigned char *buff, uint32_t *buff_len); + +#endif /* SNMP_BER_H_ */ +/** @} */ diff --git a/os/net/app-layer/snmp/snmp-conf.h b/os/net/app-layer/snmp/snmp-conf.h new file mode 100644 index 0000000000000000000000000000000000000000..c8a11ddadfb70115b3a60620904f35c2712aef96 --- /dev/null +++ b/os/net/app-layer/snmp/snmp-conf.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * SNMP Configurable Macros + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +/** + * \addtogroup snmp + * @{ + */ + +#ifndef SNMP_CONF_H_ +#define SNMP_CONF_H_ + +/** + * \defgroup SNMPConfs SNMP Configurable Defines + * @{ + */ + +#ifdef SNMP_CONF_COMMUNITY +/** + * \brief Configurable SNMP Community + */ +#define SNMP_COMMUNITY SNMP_CONF_COMMUNITY +#else +/** + * \brief Default SNMP Community + */ +#define SNMP_COMMUNITY "public" +#endif + +#ifdef SNMP_CONF_MSG_OID_MAX_LEN +/** + * \brief Configurable maximum number of IDs in one OID + */ +#define SNMP_MSG_OID_MAX_LEN SNMP_CONF_MSG_OID_MAX_LEN +#else +/** + * \brief Default maximum number of IDs in one OID + */ +#define SNMP_MSG_OID_MAX_LEN 16 +#endif + +#ifdef SNMP_CONF_MAX_NR_VALUES +/** + * \brief Configurable maximum number of OIDs in one response + */ +#define SNMP_MAX_NR_VALUES SNMP_CONF_MAX_NR_VALUES +#else +/** + * \brief Default maximum number of OIDs in one response + */ +#define SNMP_MAX_NR_VALUES 2 +#endif + +#ifdef SNMP_CONF_MAX_PACKET_SIZE +/** + * \brief Configurable maximum size of the packet in bytes + */ +#define SNMP_MAX_PACKET_SIZE SNMP_CONF_MAX_PACKET_SIZE +#else +/** + * \brief Default maximum size of the packet in bytes + */ +#define SNMP_MAX_PACKET_SIZE 512 +#endif + +#ifdef SNMP_CONF_PORT +/** + * \brief Configurable SNMP port + */ +#define SNMP_PORT SNMP_CONF_PORT +#else +/** + * \brief Default SNMP port + */ +#define SNMP_PORT 161 +#endif + +/*@}*/ + +#endif /* SNMP_CONF_H_ */ +/** @} */ diff --git a/os/net/app-layer/snmp/snmp-engine.c b/os/net/app-layer/snmp/snmp-engine.c new file mode 100644 index 0000000000000000000000000000000000000000..22694046654ab791a67b72a76c05f29bd7290ec7 --- /dev/null +++ b/os/net/app-layer/snmp/snmp-engine.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +#include "contiki.h" + +#include "snmp-engine.h" +#include "snmp-message.h" +#include "snmp-mib.h" +#include "snmp-oid.h" + +#define LOG_MODULE "SNMP [engine]" +#define LOG_LEVEL LOG_LEVEL_SNMP + +/*---------------------------------------------------------------------------*/ +int +snmp_engine_get(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t varbinds_length) +{ + snmp_mib_resource_t *resource; + uint32_t i; + + for(i = 0; i < varbinds_length; i++) { + resource = snmp_mib_find(varbinds[i].oid); + if(!resource) { + switch(header->version) { + case SNMP_VERSION_1: + header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME; + /* + * Varbinds are 1 indexed + */ + header->error_index_max_repetitions.error_index = i + 1; + break; + case SNMP_VERSION_2C: + (&varbinds[i])->value_type = SNMP_DATA_TYPE_NO_SUCH_INSTANCE; + break; + default: + header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME; + header->error_index_max_repetitions.error_index = 0; + } + } else { + resource->handler(&varbinds[i], resource->oid); + } + } + + return 0; +} +/*---------------------------------------------------------------------------*/ +int +snmp_engine_get_next(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t varbinds_length) +{ + snmp_mib_resource_t *resource; + uint32_t i; + + for(i = 0; i < varbinds_length; i++) { + resource = snmp_mib_find_next(varbinds[i].oid); + if(!resource) { + switch(header->version) { + case SNMP_VERSION_1: + header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME; + /* + * Varbinds are 1 indexed + */ + header->error_index_max_repetitions.error_index = i + 1; + break; + case SNMP_VERSION_2C: + (&varbinds[i])->value_type = SNMP_DATA_TYPE_END_OF_MIB_VIEW; + break; + default: + header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME; + header->error_index_max_repetitions.error_index = 0; + } + } else { + resource->handler(&varbinds[i], resource->oid); + } + } + + return 0; +} +/*---------------------------------------------------------------------------*/ +int +snmp_engine_get_bulk(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t *varbinds_length) +{ + snmp_mib_resource_t *resource; + uint32_t i, j, original_varbinds_length; + uint32_t oid[SNMP_MAX_NR_VALUES][SNMP_MSG_OID_MAX_LEN]; + uint8_t repeater; + + /* + * A local copy of the requested oids must be kept since + * the varbinds are modified on the fly + */ + original_varbinds_length = *varbinds_length; + for(i = 0; i < original_varbinds_length; i++) { + snmp_oid_copy(oid[i], varbinds[i].oid); + } + + *varbinds_length = 0; + for(i = 0; i < original_varbinds_length; i++) { + if(i >= header->error_status_non_repeaters.non_repeaters) { + break; + } + + resource = snmp_mib_find_next(oid[i]); + if(!resource) { + switch(header->version) { + case SNMP_VERSION_1: + header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME; + /* + * Varbinds are 1 indexed + */ + header->error_index_max_repetitions.error_index = i + 1; + break; + case SNMP_VERSION_2C: + (&varbinds[i])->value_type = SNMP_DATA_TYPE_END_OF_MIB_VIEW; + break; + default: + header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME; + header->error_index_max_repetitions.error_index = 0; + } + } else { + if(*varbinds_length < SNMP_MAX_NR_VALUES) { + resource->handler(&varbinds[*varbinds_length], resource->oid); + (*varbinds_length)++; + } + } + } + + for(i = 0; i < header->error_index_max_repetitions.max_repetitions; i++) { + repeater = 0; + for(j = header->error_status_non_repeaters.non_repeaters; j < original_varbinds_length; j++) { + resource = snmp_mib_find_next(oid[j]); + if(!resource) { + switch(header->version) { + case SNMP_VERSION_1: + header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME; + /* + * Varbinds are 1 indexed + */ + header->error_index_max_repetitions.error_index = *varbinds_length + 1; + break; + case SNMP_VERSION_2C: + if(*varbinds_length < SNMP_MAX_NR_VALUES) { + (&varbinds[*varbinds_length])->value_type = SNMP_DATA_TYPE_END_OF_MIB_VIEW; + snmp_oid_copy((&varbinds[*varbinds_length])->oid, oid[j]); + (*varbinds_length)++; + } + break; + default: + header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME; + header->error_index_max_repetitions.error_index = 0; + } + } else { + if(*varbinds_length < SNMP_MAX_NR_VALUES) { + resource->handler(&varbinds[*varbinds_length], resource->oid); + (*varbinds_length)++; + snmp_oid_copy(oid[j], resource->oid); + repeater++; + } + } + } + if(repeater == 0) { + break; + } + } + + return 0; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_engine(unsigned char *buff, uint32_t buff_len, unsigned char *out, uint32_t *out_len) +{ + static snmp_header_t header; + static snmp_varbind_t varbinds[SNMP_MAX_NR_VALUES]; + static uint32_t varbind_length; + + buff = snmp_message_decode(buff, buff_len, &header, varbinds, &varbind_length); + if(buff == NULL) { + return NULL; + } + + if(header.version != SNMP_VERSION_1) { + if(strncmp(header.community.community, SNMP_COMMUNITY, header.community.length)) { + LOG_ERR("Request with invalid community\n"); + return NULL; + } + } + + /* + * Now handle the SNMP requests depending on their type + */ + switch(header.pdu_type) { + case SNMP_DATA_TYPE_PDU_GET_REQUEST: + if(snmp_engine_get(&header, varbinds, varbind_length) == -1) { + return NULL; + } + break; + + case SNMP_DATA_TYPE_PDU_GET_NEXT_REQUEST: + if(snmp_engine_get_next(&header, varbinds, varbind_length) == -1) { + return NULL; + } + break; + + case SNMP_DATA_TYPE_PDU_GET_BULK: + if(snmp_engine_get_bulk(&header, varbinds, &varbind_length) == -1) { + return NULL; + } + break; + + default: + LOG_ERR("Invalid request type"); + return NULL; + } + + header.pdu_type = SNMP_DATA_TYPE_PDU_GET_RESPONSE; + out = snmp_message_encode(out, out_len, &header, varbinds, varbind_length); + + return ++out; +} diff --git a/os/net/app-layer/snmp/snmp-engine.h b/os/net/app-layer/snmp/snmp-engine.h new file mode 100644 index 0000000000000000000000000000000000000000..d6bc7978e138f186dde79009fa2edfbcef717178 --- /dev/null +++ b/os/net/app-layer/snmp/snmp-engine.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +/** + * \addtogroup snmp + * @{ + */ + +#ifndef SNMP_ENGINE_H_ +#define SNMP_ENGINE_H_ + +#include "snmp.h" + +/** + * @brief Process the SNMP packet and prepares the response + * + * @param buff A pointer to the beginning of the packet buffer + * @param buff_len The packet length + * @param out A pointer to the end of the response buffer + * @param out_len A pointer to the length of the response buffer + * + * @return NULL in case of fail or the first element in the response buffer + */ +unsigned char * +snmp_engine(unsigned char *buff, uint32_t buff_len, unsigned char *out, uint32_t *out_len); + +#endif /* SNMP_ENGINE_H_ */ + +/** @} */ diff --git a/os/net/app-layer/snmp/snmp-message.c b/os/net/app-layer/snmp/snmp-message.c new file mode 100644 index 0000000000000000000000000000000000000000..dd32743c1733d4a3d6caee372eae6d1e64e2e7ce --- /dev/null +++ b/os/net/app-layer/snmp/snmp-message.c @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +#include "contiki.h" + +#include "snmp-message.h" +#include "snmp-ber.h" +#include "snmp-oid.h" + +#define LOG_MODULE "SNMP [message]" +#define LOG_LEVEL LOG_LEVEL_SNMP + +unsigned char * +snmp_message_encode(unsigned char *out, uint32_t *out_len, snmp_header_t *header, + snmp_varbind_t *varbinds, uint32_t varbind_num) +{ + snmp_varbind_t *varbind; + uint32_t original_out_len, last_out_len; + int8_t i; + + original_out_len = *out_len; + for(i = varbind_num - 1; i >= 0; i--) { + varbind = &varbinds[i]; + + last_out_len = *out_len; + + switch(varbind->value_type) { + case BER_DATA_TYPE_INTEGER: + out = snmp_ber_encode_integer(out, out_len, varbind->value.integer); + break; + case SNMP_DATA_TYPE_TIME_TICKS: + out = snmp_ber_encode_unsigned_integer(out, out_len, varbind->value_type, varbind->value.integer); + break; + case BER_DATA_TYPE_OCTET_STRING: + out = snmp_ber_encode_string_len(out, out_len, varbind->value.string.string, varbind->value.string.length); + break; + case BER_DATA_TYPE_OID: + out = snmp_oid_encode_oid(out, out_len, varbind->value.oid); + break; + case BER_DATA_TYPE_NULL: + case SNMP_DATA_TYPE_NO_SUCH_INSTANCE: + case SNMP_DATA_TYPE_END_OF_MIB_VIEW: + out = snmp_ber_encode_null(out, out_len, varbind->value_type); + break; + default: + return NULL; + } + + out = snmp_oid_encode_oid(out, out_len, varbind->oid); + out = snmp_ber_encode_length(out, out_len, ((*out_len - last_out_len) & 0xFF)); + out = snmp_ber_encode_type(out, out_len, BER_DATA_TYPE_SEQUENCE); + } + + out = snmp_ber_encode_length(out, out_len, ((*out_len - original_out_len) & 0xFF)); + out = snmp_ber_encode_type(out, out_len, BER_DATA_TYPE_SEQUENCE); + + if(header->pdu_type == SNMP_DATA_TYPE_PDU_GET_BULK) { + out = snmp_ber_encode_integer(out, out_len, header->error_index_max_repetitions.max_repetitions); + out = snmp_ber_encode_integer(out, out_len, header->error_status_non_repeaters.non_repeaters); + } else { + out = snmp_ber_encode_integer(out, out_len, header->error_index_max_repetitions.error_index); + out = snmp_ber_encode_integer(out, out_len, header->error_status_non_repeaters.error_status); + } + out = snmp_ber_encode_integer(out, out_len, header->request_id); + + out = snmp_ber_encode_length(out, out_len, ((*out_len - original_out_len) & 0xFF)); + out = snmp_ber_encode_type(out, out_len, header->pdu_type); + + out = snmp_ber_encode_string_len(out, out_len, header->community.community, header->community.length); + out = snmp_ber_encode_integer(out, out_len, header->version); + + out = snmp_ber_encode_length(out, out_len, ((*out_len - original_out_len) & 0xFF)); + out = snmp_ber_encode_type(out, out_len, BER_DATA_TYPE_SEQUENCE); + + return out; +} +uint8_t * +snmp_message_decode(uint8_t *buf, uint32_t buf_len, snmp_header_t *header, + snmp_varbind_t *varbinds, uint32_t *varbind_num) +{ + uint8_t type, len; + uint32_t i, oid_len; + + buf = snmp_ber_decode_type(buf, &buf_len, &type); + if(buf == NULL) { + LOG_DBG("Could not decode type\n"); + return NULL; + } + + if(type != BER_DATA_TYPE_SEQUENCE) { + LOG_DBG("Invalid type\n"); + return NULL; + } + + buf = snmp_ber_decode_length(buf, &buf_len, &len); + if(buf == NULL) { + LOG_DBG("Could not decode length\n"); + return NULL; + } + + buf = snmp_ber_decode_integer(buf, &buf_len, &header->version); + if(buf == NULL) { + LOG_DBG("Could not decode version\n"); + return NULL; + } + + buf = snmp_ber_decode_string_len_buffer(buf, &buf_len, &header->community.community, &header->community.length); + if(buf == NULL) { + LOG_DBG("Could not decode community\n"); + return NULL; + } + + if(header->version != SNMP_VERSION_1 && + header->version != SNMP_VERSION_2C) { + LOG_DBG("Invalid version\n"); + return NULL; + } + + buf = snmp_ber_decode_type(buf, &buf_len, &type); + if(buf == NULL) { + LOG_DBG("Could not decode type\n"); + return NULL; + } + + header->pdu_type = type; + if(header->pdu_type != SNMP_DATA_TYPE_PDU_GET_REQUEST && + header->pdu_type != SNMP_DATA_TYPE_PDU_GET_NEXT_REQUEST && + header->pdu_type != SNMP_DATA_TYPE_PDU_GET_RESPONSE && + header->pdu_type != SNMP_DATA_TYPE_PDU_SET_REQUEST && + header->pdu_type != SNMP_DATA_TYPE_PDU_GET_BULK) { + LOG_DBG("Invalid pdu type\n"); + return NULL; + } + + buf = snmp_ber_decode_length(buf, &buf_len, &len); + if(buf == NULL) { + LOG_DBG("Could not decode length\n"); + return NULL; + } + + buf = snmp_ber_decode_integer(buf, &buf_len, &header->request_id); + if(buf == NULL) { + LOG_DBG("Could not decode request id\n"); + return NULL; + } + + if(header->pdu_type == SNMP_DATA_TYPE_PDU_GET_BULK) { + buf = snmp_ber_decode_integer(buf, &buf_len, &header->error_status_non_repeaters.non_repeaters); + if(buf == NULL) { + LOG_DBG("Could not decode error status\n"); + return NULL; + } + + buf = snmp_ber_decode_integer(buf, &buf_len, &header->error_index_max_repetitions.max_repetitions); + if(buf == NULL) { + LOG_DBG("Could not decode error index\n"); + return NULL; + } + } else { + buf = snmp_ber_decode_integer(buf, &buf_len, &header->error_status_non_repeaters.error_status); + if(buf == NULL) { + LOG_DBG("Could not decode error status\n"); + return NULL; + } + + buf = snmp_ber_decode_integer(buf, &buf_len, &header->error_index_max_repetitions.error_index); + if(buf == NULL) { + LOG_DBG("Could not decode error index\n"); + return NULL; + } + } + + buf = snmp_ber_decode_type(buf, &buf_len, &type); + if(buf == NULL) { + LOG_DBG("Could not decode type\n"); + return NULL; + } + + if(type != BER_DATA_TYPE_SEQUENCE) { + LOG_DBG("Invalid type\n"); + return NULL; + } + + buf = snmp_ber_decode_length(buf, &buf_len, &len); + if(buf == NULL) { + LOG_DBG("Could not decode length\n"); + return NULL; + } + + for(i = 0; buf_len > 0; ++i) { + + buf = snmp_ber_decode_type(buf, &buf_len, &type); + if(buf == NULL) { + LOG_DBG("Could not decode type\n"); + return NULL; + } + + if(type != BER_DATA_TYPE_SEQUENCE) { + LOG_DBG("Invalid (%X) type\n", type); + return NULL; + } + + buf = snmp_ber_decode_length(buf, &buf_len, &len); + if(buf == NULL) { + LOG_DBG("Could not decode length\n"); + return NULL; + } + + buf = snmp_oid_decode_oid(buf, &buf_len, varbinds[i].oid, &oid_len); + if(buf == NULL) { + LOG_DBG("Could not decode oid\n"); + return NULL; + } + + varbinds[i].value_type = *buf; + + switch(varbinds[i].value_type) { + case BER_DATA_TYPE_INTEGER: + buf = snmp_ber_decode_integer(buf, &buf_len, &varbinds[i].value.integer); + break; + case SNMP_DATA_TYPE_TIME_TICKS: + buf = snmp_ber_decode_unsigned_integer(buf, &buf_len, varbinds[i].value_type, &varbinds[i].value.integer); + break; + case BER_DATA_TYPE_OCTET_STRING: + buf = snmp_ber_decode_string_len_buffer(buf, &buf_len, &varbinds[i].value.string.string, &varbinds[i].value.string.length); + break; + case BER_DATA_TYPE_NULL: + buf = snmp_ber_decode_null(buf, &buf_len); + break; + default: + LOG_DBG("Invalid varbind type\n"); + return NULL; + } + + if(buf == NULL) { + LOG_DBG("Could varbind type\n"); + return NULL; + } + } + + *varbind_num = i; + + return buf; +} diff --git a/os/net/app-layer/snmp/snmp-message.h b/os/net/app-layer/snmp/snmp-message.h new file mode 100644 index 0000000000000000000000000000000000000000..26436b9b7c8f0265c796d7f92fbfdc08e773bc91 --- /dev/null +++ b/os/net/app-layer/snmp/snmp-message.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +/** + * \addtogroup snmp + * @{ + */ + +#ifndef SNMP_MESSAGE_H_ +#define SNMP_MESSAGE_H_ + +#include "snmp.h" + +#define SNMP_DATA_TYPE_TIME_TICKS 0x43 +#define SNMP_DATA_TYPE_NO_SUCH_INSTANCE 0x81 +#define SNMP_DATA_TYPE_END_OF_MIB_VIEW 0x82 + +#define SNMP_DATA_TYPE_PDU_GET_REQUEST 0xA0 +#define SNMP_DATA_TYPE_PDU_GET_NEXT_REQUEST 0xA1 +#define SNMP_DATA_TYPE_PDU_GET_RESPONSE 0xA2 +#define SNMP_DATA_TYPE_PDU_SET_REQUEST 0xA3 +#define SNMP_DATA_TYPE_PDU_TRAP 0xA4 +#define SNMP_DATA_TYPE_PDU_GET_BULK 0xA5 + +/** + * @brief Encodes a SNMP message + * + * @param out A pointer to the end of the buffer + * @param out_len A pointer to the buffer length + * @param header The SNMP header struct + * @param varbinds The varbinds array + * @param varbinds_length The number of varbinds + * + * @return + */ +unsigned char * +snmp_message_encode(unsigned char *out, uint32_t *out_len, snmp_header_t *header, + snmp_varbind_t *varbinds, uint32_t varbinds_length); +/** + * @brief + * + * @param buf A pointer to the beginning of the buffer + * @param buf_len A pointer to the buffer length + * @param header The SNMP header struct + * @param varbinds The varbinds array + * @param varbinds_length A pointer to the number of varbinds + * + * @return + */ +uint8_t * +snmp_message_decode(uint8_t *buf, uint32_t buf_len, snmp_header_t *header, + snmp_varbind_t *varbinds, uint32_t *varbinds_length); + +#endif /* SNMP_MESSAGE_H_ */ + +/** @} */ diff --git a/os/net/app-layer/snmp/snmp-mib.c b/os/net/app-layer/snmp/snmp-mib.c new file mode 100644 index 0000000000000000000000000000000000000000..fae834af141afe0d5f8c245de7c9f9a53ca5eade --- /dev/null +++ b/os/net/app-layer/snmp/snmp-mib.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +#include "contiki.h" + +#include "snmp-mib.h" +#include "snmp-oid.h" +#include "lib/list.h" + +#define LOG_MODULE "SNMP [mib]" +#define LOG_LEVEL LOG_LEVEL_SNMP + +LIST(snmp_mib); + +snmp_mib_resource_t * +snmp_mib_find(uint32_t *oid) +{ + snmp_mib_resource_t *resource; + + resource = NULL; + for(resource = list_head(snmp_mib); + resource; resource = resource->next) { + + if(!snmp_oid_cmp_oid(oid, resource->oid)) { + return resource; + } + } + + return NULL; +} +snmp_mib_resource_t * +snmp_mib_find_next(uint32_t *oid) +{ + snmp_mib_resource_t *resource; + + resource = NULL; + for(resource = list_head(snmp_mib); + resource; resource = resource->next) { + + if(snmp_oid_cmp_oid(resource->oid, oid) > 0) { + return resource; + } + } + + return NULL; +} +void +snmp_mib_add(snmp_mib_resource_t *new_resource) +{ + snmp_mib_resource_t *resource; + + for(resource = list_head(snmp_mib); + resource; resource = resource->next) { + + if(snmp_oid_cmp_oid(resource->oid, new_resource->oid) > 0) { + break; + } + } + if(resource == NULL) { + list_add(snmp_mib, new_resource); + } else { + list_insert(snmp_mib, new_resource, resource); + } + +#if LOG_LEVEL == LOG_LEVEL_DBG + /* + * We print the entire resource table + */ + LOG_DBG("Table after insert.\n"); + for(resource = list_head(snmp_mib); + resource; resource = resource->next) { + + snmp_oid_print(resource->oid); + } +#endif /* LOG_LEVEL == LOG_LEVEL_DBG */ +} +void +snmp_mib_init(void) +{ + list_init(snmp_mib); +} diff --git a/os/net/app-layer/snmp/snmp-mib.h b/os/net/app-layer/snmp/snmp-mib.h new file mode 100644 index 0000000000000000000000000000000000000000..84115156a0eac33416c925d2d4348cdde4a7c50f --- /dev/null +++ b/os/net/app-layer/snmp/snmp-mib.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +/** + * \addtogroup snmp + * @{ + */ + +#ifndef SNMP_MIB_H_ +#define SNMP_MIB_H_ + +#include "snmp.h" + +/** + * @brief The MIB resource handler typedef + * + * @param varbind The varbind that is being changed + * @param oid The oid from the resource + */ +typedef void (*snmp_mib_resource_handler_t)(snmp_varbind_t *varbind, uint32_t *oid); + +/** + * @brief The MIB Resource struct + */ +typedef struct snmp_mib_resource_s { + /** + * @brief A pointer to the next element in the linked list + * + * @remarks This MUST be the first element in the struct + */ + struct snmp_mib_resource_s *next; + /** + * @brief A array that represents the OID + * + * @remarks This array is "null" terminated. In this case the -1 is used. + */ + uint32_t *oid; + /** + * @brief The function handler that is called for this resource + */ + snmp_mib_resource_handler_t handler; +} snmp_mib_resource_t; + +/** + * @brief Finds the MIB Resource for this OID + * + * @param oid The OID + * + * @return In case of success a pointer to the resouce or NULL in case of fail + */ +snmp_mib_resource_t * +snmp_mib_find(uint32_t *oid); + +/** + * @brief Finds the next MIB Resource after this OID + * + * @param oid The OID + * + * @return In case of success a pointer to the resouce or NULL in case of fail + */ +snmp_mib_resource_t * +snmp_mib_find_next(uint32_t *oid); + +/** + * @brief Adds a resource into the linked list + * + * @param resource The resource + */ +void +snmp_mib_add(snmp_mib_resource_t *resource); + +/** + * @brief Initialize the MIB resources list + */ +void +snmp_mib_init(void); + +#endif /* SNMP_MIB_H_ */ +/** @} */ diff --git a/os/net/app-layer/snmp/snmp-oid.c b/os/net/app-layer/snmp/snmp-oid.c new file mode 100644 index 0000000000000000000000000000000000000000..29e4a2637c5b50b133c9117d972f6a5f1c605228 --- /dev/null +++ b/os/net/app-layer/snmp/snmp-oid.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +#include "contiki.h" + +#include "snmp-oid.h" +#include "snmp-ber.h" + +#define LOG_MODULE "SNMP [oid]" +#define LOG_LEVEL LOG_LEVEL_SNMP + +/*---------------------------------------------------------------------------*/ +int +snmp_oid_cmp_oid(uint32_t *oid1, uint32_t *oid2) +{ + uint8_t i; + + i = 0; + while(oid1[i] != ((uint32_t)-1) && + oid2[i] != ((uint32_t)-1)) { + if(oid1[i] != oid2[i]) { + if(oid1[i] < oid2[i]) { + return -1; + } + return 1; + } + i++; + } + + if(oid1[i] == ((uint32_t)-1) && + oid2[i] != ((uint32_t)-1)) { + return -1; + } + + if(oid1[i] != ((uint32_t)-1) && + oid2[i] == ((uint32_t)-1)) { + return 1; + } + + return 0; +} +/*---------------------------------------------------------------------------*/ +unsigned char * +snmp_oid_encode_oid(unsigned char *out, uint32_t *out_len, uint32_t *oid) +{ + uint32_t original_out_len; + uint32_t *oid_start = oid; + uint32_t num; + + original_out_len = *out_len; + while(*oid != ((uint32_t)-1)) { + ++oid; + } + --oid; + + while(oid != oid_start) { + num = *oid; + (*out_len)++; + *out-- = (uint8_t)(num & 0x7F); + num >>= 7; + + while(num) { + (*out_len)++; + *out-- = (uint8_t)((num & 0x7F) | 0x80); + num >>= 7; + } + --oid; + } + + num = *(out + 1) + 40 * *oid; + (*out_len)--; + out++; + (*out_len)++; + *out-- = (uint8_t)(num & 0x7F); + num >>= 7; + + while(num) { + (*out_len)++; + *out-- = (uint8_t)((num & 0x7F) | 0x80); + num >>= 7; + } + + out = snmp_ber_encode_length(out, out_len, ((*out_len - original_out_len) & 0xFF)); + out = snmp_ber_encode_type(out, out_len, SNMP_DATA_TYPE_OBJECT); + + return out; +} +/*---------------------------------------------------------------------------*/ +uint8_t * +snmp_oid_decode_oid(uint8_t *buf, uint32_t *buff_len, uint32_t *oid, uint32_t *oid_len) +{ + uint32_t *start; + uint8_t *buf_end, type; + uint8_t len; + div_t first; + + start = oid; + + buf = snmp_ber_decode_type(buf, buff_len, &type); + if(buf == NULL) { + return NULL; + } + + if(type != SNMP_DATA_TYPE_OBJECT) { + return NULL; + } + + buf = snmp_ber_decode_length(buf, buff_len, &len); + if(buf == NULL) { + return NULL; + } + + buf_end = buf + len; + + (*buff_len)--; + first = div(*buf++, 40); + *oid++ = (uint32_t)first.quot; + *oid++ = (uint32_t)first.rem; + + while(buf != buf_end) { + --(*oid_len); + if(*oid_len == 0) { + return NULL; + } + + int i; + + *oid = (uint32_t)(*buf & 0x7F); + for(i = 0; i < 4; i++) { + (*buff_len)--; + if((*buf++ & 0x80) == 0) { + break; + } + + *oid <<= 7; + *oid |= (*buf & 0x7F); + } + + ++oid; + } + + *oid++ = ((uint32_t)-1); + *oid_len = (uint32_t)(oid - start); + + return buf; +} +/*---------------------------------------------------------------------------*/ +void +snmp_oid_copy(uint32_t *dst, uint32_t *src) +{ + uint8_t i; + + i = 0; + while(src[i] != ((uint32_t)-1)) { + dst[i] = src[i]; + i++; + } + /* + * Copy the "null" terminator + */ + dst[i] = src[i]; +} +/*---------------------------------------------------------------------------*/ +#if LOG_LEVEL == LOG_LEVEL_DBG +void +snmp_oid_print(uint32_t *oid) +{ + uint8_t i; + + i = 0; + LOG_DBG("{"); + while(oid[i] != ((uint32_t)-1)) { + LOG_DBG_("%lu", (unsigned long)oid[i]); + i++; + if(oid[i] != ((uint32_t)-1)) { + LOG_DBG_("."); + } + } + LOG_DBG_("}\n"); +} +#endif /* LOG_LEVEL == LOG_LEVEL_DBG */ diff --git a/os/net/app-layer/snmp/snmp-oid.h b/os/net/app-layer/snmp/snmp-oid.h new file mode 100644 index 0000000000000000000000000000000000000000..1da2d16d2a9f02abbfa1844372a6e200c6adbbf2 --- /dev/null +++ b/os/net/app-layer/snmp/snmp-oid.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +/** + * \addtogroup snmp + * @{ + */ + +#ifndef SNMP_OID_H_ +#define SNMP_OID_H_ + +#include "snmp.h" + +#define SNMP_DATA_TYPE_OBJECT 0x06 + +/** + * @brief Compares to oids + * + * @param oid1 First Oid + * @param oid2 Second Oid + * + * @return < 0 if oid1 < oid2, > 0 if oid1 > oid2 and 0 if they are equal + */ +int +snmp_oid_cmp_oid(uint32_t *oid1, uint32_t *oid2); + +/** + * @brief Encodes a Oid + * + * @param out A pointer to the end of the buffer + * @param out_len A pointer to the buffer length + * @param oid The Oid + * + * @return NULL if error or the next entry in the buffer + */ +unsigned char * +snmp_oid_encode_oid(unsigned char *out, uint32_t *out_len, uint32_t *oid); + +/** + * @brief Decodes a Oid + * + * @param buf A pointer to the beginning of the buffer + * @param buf_len A pointer to the buffer length + * @param oid A pointer to the oid array + * @param oid_len A pointer to the oid length + * + * @return NULL if error or the first entry after the oid in the buffer + */ +unsigned char * +snmp_oid_decode_oid(unsigned char *buf, uint32_t *buf_len, uint32_t *oid, uint32_t *oid_len); + +/** + * @brief Copies a Oid + * + * @param dst A pointer to the destination array + * @param src A pointer to the source array + */ +void +snmp_oid_copy(uint32_t *dst, uint32_t *src); + +#if LOG_LEVEL == LOG_LEVEL_DBG +/** + * @brief Prints a oid + * + * @param oid A oid + */ +void +snmp_oid_print(uint32_t *oid); +#endif /* LOG_LEVEL == LOG_LEVEL_DBG */ + +#endif /* SNMP_OID_H_ */ +/** @} */ diff --git a/os/net/app-layer/snmp/snmp.c b/os/net/app-layer/snmp/snmp.c new file mode 100644 index 0000000000000000000000000000000000000000..a721129fc5c9eb8381497bce649250af46a92ef6 --- /dev/null +++ b/os/net/app-layer/snmp/snmp.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +#include "contiki.h" + +#include "snmp.h" +#include "snmp-mib.h" +#include "snmp-engine.h" + +#define LOG_MODULE "SNMP" +#define LOG_LEVEL LOG_LEVEL_SNMP + +/*---------------------------------------------------------------------------*/ +#define SNMP_SERVER_PORT UIP_HTONS(SNMP_PORT) +PROCESS(snmp_process, "SNMP Process"); + +static struct uip_udp_conn *snmp_udp_conn = NULL; + +/*---------------------------------------------------------------------------*/ +static void +snmp_process_data(void) +{ + static unsigned char packet[SNMP_MAX_PACKET_SIZE]; + unsigned char *packet_end; + static uint32_t packet_len; + + packet_end = packet + sizeof(packet) - 1; + packet_len = 0; + + LOG_DBG("receiving UDP datagram from ["); + LOG_DBG_6ADDR(&UIP_IP_BUF->srcipaddr); + LOG_DBG_("]:%u", uip_ntohs(UIP_UDP_BUF->srcport)); + LOG_DBG_(" Length: %u\n", uip_datalen()); + + /* + * Handle the request + */ + if((packet_end = snmp_engine(uip_appdata, uip_datalen(), packet_end, &packet_len)) == NULL) { + LOG_DBG("Error while handling the request\n"); + } else { + LOG_DBG("Sending response\n"); + /* + * Send the response + */ + uip_udp_packet_sendto(snmp_udp_conn, packet_end, packet_len, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport); + } +} +/*---------------------------------------------------------------------------*/ +void +snmp_init() +{ + snmp_mib_init(); + process_start(&snmp_process, NULL); +} +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(snmp_process, ev, data) +{ + PROCESS_BEGIN(); + + /* new connection with remote host */ + snmp_udp_conn = udp_new(NULL, 0, NULL); + udp_bind(snmp_udp_conn, SNMP_SERVER_PORT); + LOG_DBG("Listening on port %u\n", uip_ntohs(snmp_udp_conn->lport)); + + while(1) { + PROCESS_YIELD(); + + if(ev == tcpip_event) { + if(uip_newdata()) { + snmp_process_data(); + } + } + } /* while (1) */ + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/os/net/app-layer/snmp/snmp.h b/os/net/app-layer/snmp/snmp.h new file mode 100644 index 0000000000000000000000000000000000000000..f6c4be0667f002bdce94072cfd0c2e424a639c00 --- /dev/null +++ b/os/net/app-layer/snmp/snmp.h @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ + +/** + * \file + * An implementation of the Simple Network Management Protocol (RFC 3411-3418) + * \author + * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br + */ + +/** + * \addtogroup apps + * @{ + * + * \defgroup snmp SNMP (Simple Network Management Protocol) + * @{ + * + * This is an implementation of the Simple Network Management Protocol + */ + +#ifndef SNMP_H_ +#define SNMP_H_ + +#include "contiki.h" +#include "contiki-net.h" + +#include "sys/log.h" + +#include "snmp-conf.h" + +#include <stdlib.h> +#include <stdint.h> + +/** + * \defgroup SNMPDefine SNMP Defines + * @{ + */ + +/** + * @brief SNMP Version 1 code + */ +#define SNMP_VERSION_1 0 +/** + * @brief SNMP Version 2c code + */ +#define SNMP_VERSION_2C 1 + +/** + * @brief SNMP No Such Name error code + */ +#define SNMP_STATUS_NO_SUCH_NAME 2 + +/** @} */ + +/** + * \defgroup SNMPStructs SNMP Structs + * @{ + */ + +/** + * @brief The SNMP header struct + */ +typedef struct snmp_header_s { + /** + * @brief SNMP Version + */ + uint32_t version; + /** + * @brief Struct to wrap the community + */ + struct snmp_msg_community { + /** + * @brief A pointer to the community + * + * @remarks This pointer refers to the beginning of the string in the packet + */ + const char *community; + /** + * @brief The string length + * + * @remarks Do not use strlen on the community pointer since it is not null terminated + */ + uint32_t length; + } community; + /** + * @brief The PDU type + */ + uint8_t pdu_type; + /** + * @brief The request ID + */ + uint32_t request_id; + /** + * @brief Union to hold the error status or the non repeaters + * + * @remarks A union was used since these values cannot co-exist + */ + union error_status_non_repeaters_u { + /** + * @brief The error status + */ + uint32_t error_status; + /** + * @brief The non repeaters + */ + uint32_t non_repeaters; + } error_status_non_repeaters; + /** + * @brief Union to hold the error index or the max repetitions + * + * @remarks A union was used since these values cannot co-exist + */ + union error_index_max_repetitions_u { + /** + * @brief The error index + */ + uint32_t error_index; + /** + * @brief The max repetitions + */ + uint32_t max_repetitions; + } error_index_max_repetitions; +} snmp_header_t; + +/** + * @brief The varbind struct + */ +typedef struct snmp_varbind_s { + /** + * @brief The OID + * + * @remarks The length is configurable + */ + uint32_t oid[SNMP_MSG_OID_MAX_LEN]; + /** + * @brief The type in this varbind + */ + uint8_t value_type; + /** + * @brief A union to represent the value in this varbind + * + * @remarks A union is used since the varbind can only have one value of one type + */ + union snmp_varbind_val_u { + /** + * @brief The integer value + */ + uint32_t integer; + /** + * @brief A struct that contains the string + */ + struct snmp_varbind_string_s { + /** + * @brief A pointer to the string value from this varbind + * + * @remarks This pointer points to a string that cannot be changed + */ + const char *string; + /** + * @brief The string length + * + * @remarks Do not use strlen on the string since it might not be null terminated + */ + uint32_t length; + } string; + /** + * @brief A pointer to the beggining of a oid array + */ + uint32_t *oid; + } value; +} snmp_varbind_t; + +/** @}*/ + +/** + * \defgroup SNMPFunctions SNMP Functions + * @{ + */ + +/** + * @brief Initializes the SNMP engine + */ +void +snmp_init(); + +/** @}*/ + +#endif /* SNMP_H_ */ +/** @} */ +/** @} */ diff --git a/os/net/mac/csma/csma.c b/os/net/mac/csma/csma.c index 40fe4d7b3f4e9a089e25708cabd49d889081f543..3b20d9b988059a2a84c663c4de616c4a8a6d9587 100644 --- a/os/net/mac/csma/csma.c +++ b/os/net/mac/csma/csma.c @@ -177,7 +177,9 @@ max_payload(void) framer_hdrlen = CSMA_MAC_MAX_HEADER; } - return MIN(max_radio_payload_len, PACKETBUF_SIZE) - framer_hdrlen; + return MIN(max_radio_payload_len, PACKETBUF_SIZE) + - framer_hdrlen + - LLSEC802154_PACKETBUF_MIC_LEN(); } /*---------------------------------------------------------------------------*/ const struct mac_driver csma_driver = { diff --git a/os/net/mac/llsec802154.h b/os/net/mac/llsec802154.h index e808fef7a016a1323d545f487b365a22f04a1297..84e8396e765dd4cd8864366f048402f88561fdcd 100644 --- a/os/net/mac/llsec802154.h +++ b/os/net/mac/llsec802154.h @@ -60,8 +60,6 @@ #define LLSEC802154_ENABLED 0 #endif /* LLSEC802154_CONF_ENABLED */ -#define LLSEC802154_MIC_LEN(sec_lvl) (2 << (sec_lvl & 3)) - #ifdef LLSEC802154_CONF_USES_EXPLICIT_KEYS #define LLSEC802154_USES_EXPLICIT_KEYS LLSEC802154_CONF_USES_EXPLICIT_KEYS #else /* LLSEC802154_CONF_USES_EXPLICIT_KEYS */ @@ -88,6 +86,14 @@ #define LLSEC802154_HTONL(n) (((uint32_t)UIP_HTONS(n) << 16) | UIP_HTONS((uint32_t)(n) >> 16)) #endif /* UIP_CONF_BYTE_ORDER == UIP_LITTLE_ENDIAN */ +#define LLSEC802154_MIC_LEN(sec_lvl) (2 << (sec_lvl & 3)) + +#if LLSEC802154_USES_AUX_HEADER +#define LLSEC802154_PACKETBUF_MIC_LEN() LLSEC802154_MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL)) +#else +#define LLSEC802154_PACKETBUF_MIC_LEN() 0 +#endif + #endif /* LLSEC802154_H_ */ /** @} */ diff --git a/os/net/mac/tsch/tsch-packet.c b/os/net/mac/tsch/tsch-packet.c index 133e9a6688af7afa206aa99f47730fa89d8f472a..893aa7e8c76c1bfbcbce261e04b89a24f94d6b4d 100644 --- a/os/net/mac/tsch/tsch-packet.c +++ b/os/net/mac/tsch/tsch-packet.c @@ -74,11 +74,11 @@ static struct packetbuf_attr eackbuf_attrs[PACKETBUF_NUM_ATTRS]; #define IEEE802154_FRAME_PENDING_BIT_OFFSET 4 /*---------------------------------------------------------------------------*/ -static int +void tsch_packet_eackbuf_set_attr(uint8_t type, const packetbuf_attr_t val) { eackbuf_attrs[type].val = val; - return 1; + return; } /*---------------------------------------------------------------------------*/ /* Return the value of a specified attribute */ @@ -124,14 +124,7 @@ tsch_packet_create_eack(uint8_t *buf, uint16_t buf_len, #endif #if LLSEC802154_ENABLED - if(tsch_is_pan_secured) { - tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, - TSCH_SECURITY_KEY_SEC_LEVEL_ACK); - tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, - FRAME802154_1_BYTE_KEY_ID_MODE); - tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, - TSCH_SECURITY_KEY_INDEX_ACK); - } + tsch_security_set_packetbuf_attr(FRAME802154_ACKFRAME); #endif /* LLSEC802154_ENABLED */ framer_802154_setup_params(tsch_packet_eackbuf_attr, 0, ¶ms); @@ -356,14 +349,7 @@ tsch_packet_create_eb(uint8_t *hdr_len, uint8_t *tsch_sync_ie_offset) packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &tsch_eb_address); #if LLSEC802154_ENABLED - if(tsch_is_pan_secured) { - packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, - TSCH_SECURITY_KEY_SEC_LEVEL_EB); - packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, - FRAME802154_1_BYTE_KEY_ID_MODE); - packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, - TSCH_SECURITY_KEY_INDEX_EB); - } + tsch_security_set_packetbuf_attr(FRAME802154_BEACONFRAME); #endif /* LLSEC802154_ENABLED */ if(NETSTACK_FRAMER.create() < 0) { diff --git a/os/net/mac/tsch/tsch-packet.h b/os/net/mac/tsch/tsch-packet.h index cdf7c7bed0111ac6127acaa18a9724d53e06b718..9f110344b717cb38c33dc59a299e1d18b1eea6b1 100644 --- a/os/net/mac/tsch/tsch-packet.h +++ b/os/net/mac/tsch/tsch-packet.h @@ -114,6 +114,19 @@ void tsch_packet_set_frame_pending(uint8_t *buf, int buf_size); * \return The value of the frame pending bit, 1 or 0 */ int tsch_packet_get_frame_pending(uint8_t *buf, int buf_size); +/** + * \brief Set a packet attribute for the current eack. We not use standard + * packetbuf for eacks because these are generated from interrupt context. + * \param type The attribute identifier + * \param val The attribute value + */ +void tsch_packet_eackbuf_set_attr(uint8_t type, const packetbuf_attr_t val); +/** + * \brief Return the value of a specified attribute + * \param type The attribute identifier + * \return The attribute value + */ +packetbuf_attr_t tsch_packet_eackbuf_attr(uint8_t type); #endif /* __TSCH_PACKET_H__ */ /** @} */ diff --git a/os/net/mac/tsch/tsch-security.c b/os/net/mac/tsch/tsch-security.c index 12f0de6d51798811b5061f2cfde451209c0d5a84..8d128427043e3c12ad5d887b4dfa1cf35d3376c1 100644 --- a/os/net/mac/tsch/tsch-security.c +++ b/os/net/mac/tsch/tsch-security.c @@ -271,4 +271,33 @@ tsch_security_parse_frame(const uint8_t *hdr, int hdrlen, int datalen, return 1; } } +/*---------------------------------------------------------------------------*/ +void +tsch_security_set_packetbuf_attr(uint8_t frame_type) +{ +#if LLSEC802154_ENABLED + if(tsch_is_pan_secured) { + /* Set security level, key id and index */ + switch(frame_type) { + case FRAME802154_ACKFRAME: + /* For ACKs, we set attriburtes via tsch_packet_eackbuf_set_attr, as classic + * interrupts can not be used from interrupt context. */ + tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_ACK); + tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); + tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_ACK); + break; + case FRAME802154_BEACONFRAME: + packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_EB); + packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); + packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_EB); + break; + default: + packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_OTHER); + packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); + packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_OTHER); + break; + } + } +#endif /* LLSEC802154_ENABLED */ +} /** @} */ diff --git a/os/net/mac/tsch/tsch-security.h b/os/net/mac/tsch/tsch-security.h index 4320d3a70adf65182a5aca9c9d69d473bc99e3f2..3777a9e0c56d9abc41c514bc2832741574ead7fa 100644 --- a/os/net/mac/tsch/tsch-security.h +++ b/os/net/mac/tsch/tsch-security.h @@ -140,5 +140,11 @@ unsigned int tsch_security_parse_frame(const uint8_t *hdr, int hdrlen, const linkaddr_t *sender, struct tsch_asn_t *asn); +/** + * \brief Set packetbuf (or eackbuf) attributes depending on a given frame type + * \param frame_type The frame type (FRAME802154_BEACONFRAME etc.) + */ +void tsch_security_set_packetbuf_attr(uint8_t frame_type); + #endif /* __TSCH_SECURITY_H__ */ /** @} */ diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index f6f0d4934bc3a18a29a0600d6e5399f9c3fc5f02..3fd02fbefa3bf1f62f0816f1520d03ee7c2457dd 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -1047,12 +1047,7 @@ send_packet(mac_callback_t sent, void *ptr) packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); #if LLSEC802154_ENABLED - if(tsch_is_pan_secured) { - /* Set security level, key id and index */ - packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_OTHER); - packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); /* Use 1-byte key index */ - packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_OTHER); - } + tsch_security_set_packetbuf_attr(FRAME802154_DATAFRAME); #endif /* LLSEC802154_ENABLED */ #if !NETSTACK_CONF_BRIDGE_MODE @@ -1163,6 +1158,7 @@ turn_off(void) static int max_payload(void) { + int framer_hdrlen; radio_value_t max_radio_payload_len; radio_result_t res; @@ -1174,8 +1170,18 @@ max_payload(void) return 0; } + /* Set packetbuf security attributes */ + tsch_security_set_packetbuf_attr(FRAME802154_DATAFRAME); + + framer_hdrlen = NETSTACK_FRAMER.length(); + if(framer_hdrlen < 0) { + return 0; + } + /* Setup security... before. */ - return MIN(max_radio_payload_len, TSCH_PACKET_MAX_LEN) - NETSTACK_FRAMER.length(); + return MIN(max_radio_payload_len, TSCH_PACKET_MAX_LEN) + - framer_hdrlen + - LLSEC802154_PACKETBUF_MIC_LEN(); } /*---------------------------------------------------------------------------*/ const struct mac_driver tschmac_driver = { diff --git a/os/sys/log-conf.h b/os/sys/log-conf.h index 17d8562cc114e75dccff5a77fc4bc0c7ab67863c..f886e78681738d626639639a5509461e4dfb2f67 100644 --- a/os/sys/log-conf.h +++ b/os/sys/log-conf.h @@ -138,6 +138,10 @@ #define LOG_CONF_LEVEL_COAP LOG_LEVEL_NONE #endif /* LOG_CONF_LEVEL_COAP */ +#ifndef LOG_CONF_LEVEL_SNMP +#define LOG_CONF_LEVEL_SNMP LOG_LEVEL_NONE +#endif /* LOG_CONF_LEVEL_COAP */ + #ifndef LOG_CONF_LEVEL_LWM2M #define LOG_CONF_LEVEL_LWM2M LOG_LEVEL_NONE #endif /* LOG_CONF_LEVEL_LWM2M */ diff --git a/os/sys/log.c b/os/sys/log.c index abb960b980cb4535fbc84825d5ea8a9edb33612c..41d0ea734abb8eb283f601d21d873c57f8fd786e 100644 --- a/os/sys/log.c +++ b/os/sys/log.c @@ -62,6 +62,7 @@ int curr_log_level_mac = LOG_CONF_LEVEL_MAC; int curr_log_level_framer = LOG_CONF_LEVEL_FRAMER; int curr_log_level_6top = LOG_CONF_LEVEL_6TOP; int curr_log_level_coap = LOG_CONF_LEVEL_COAP; +int curr_log_level_snmp = LOG_CONF_LEVEL_SNMP; int curr_log_level_lwm2m = LOG_CONF_LEVEL_LWM2M; int curr_log_level_main = LOG_CONF_LEVEL_MAIN; @@ -75,6 +76,7 @@ struct log_module all_modules[] = { {"framer", &curr_log_level_framer, LOG_CONF_LEVEL_FRAMER}, {"6top", &curr_log_level_6top, LOG_CONF_LEVEL_6TOP}, {"coap", &curr_log_level_coap, LOG_CONF_LEVEL_COAP}, + {"snmp", &curr_log_level_snmp, LOG_CONF_LEVEL_SNMP}, {"lwm2m", &curr_log_level_lwm2m, LOG_CONF_LEVEL_LWM2M}, {"main", &curr_log_level_main, LOG_CONF_LEVEL_MAIN}, {NULL, NULL, 0}, diff --git a/os/sys/log.h b/os/sys/log.h index 0f5f840d2e702fd9f6a26edc1ff1ee0b497e5062..a01df9e9149c9662b2b16cb3519e167934cec0e1 100644 --- a/os/sys/log.h +++ b/os/sys/log.h @@ -82,6 +82,7 @@ extern int curr_log_level_mac; extern int curr_log_level_framer; extern int curr_log_level_6top; extern int curr_log_level_coap; +extern int curr_log_level_snmp; extern int curr_log_level_lwm2m; extern int curr_log_level_main; @@ -96,6 +97,7 @@ extern struct log_module all_modules[]; #define LOG_LEVEL_FRAMER MIN((LOG_CONF_LEVEL_FRAMER), curr_log_level_framer) #define LOG_LEVEL_6TOP MIN((LOG_CONF_LEVEL_6TOP), curr_log_level_6top) #define LOG_LEVEL_COAP MIN((LOG_CONF_LEVEL_COAP), curr_log_level_coap) +#define LOG_LEVEL_SNMP MIN((LOG_CONF_LEVEL_SNMP), curr_log_level_snmp) #define LOG_LEVEL_LWM2M MIN((LOG_CONF_LEVEL_LWM2M), curr_log_level_lwm2m) #define LOG_LEVEL_MAIN MIN((LOG_CONF_LEVEL_MAIN), curr_log_level_main) diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index 51e68f9a258cea9c22e13e3e05a7cabdd6ce348b..e7592e824f18353ae4d68135409bcbc50c5686f5 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -32,6 +32,7 @@ coap/coap-example-client/native \ coap/coap-example-server/native \ coap/coap-plugtest-server/native \ sensniff/z1 \ +snmp-server/sky \ TOOLS= diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 43e008c8e8a581b70e0b34177b2e9b471841b622..f94d758e6bcd419d46a47ee0c6656a029b36e9c9 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -98,7 +98,8 @@ platform-specific/nrf52dk/mqtt-demo/nrf52dk \ platform-specific/nrf52dk/blink-hello/nrf52dk \ platform-specific/nrf52dk/timer-test/nrf52dk \ libs/data-structures/nrf52dk \ -libs/logging/nrf52dk +libs/logging/nrf52dk \ +snmp-server/cc2538dk \ TOOLS= diff --git a/tests/08-native-runs/06-snmp-server.sh b/tests/08-native-runs/06-snmp-server.sh new file mode 100644 index 0000000000000000000000000000000000000000..6a6e12f381aed123ad44c90e5d2aea16ea34bbfa --- /dev/null +++ b/tests/08-native-runs/06-snmp-server.sh @@ -0,0 +1,48 @@ +#!/bin/bash +source ../utils.sh + +# Contiki directory +CONTIKI=$1 +# Test basename +BASENAME=$(basename $0 .sh) + +IPADDR=fd00::302:304:506:708 + +# Starting Contiki-NG native node +echo "Starting native node" +make -C $CONTIKI/examples/snmp-server > make.log 2> make.err +sudo $CONTIKI/examples/snmp-server/snmp-server.native > node.log 2> node.err & +CPID=$! +sleep 2 + +# Do Walk +echo "WALK!" +snmpwalk -t 4 -v 2c -c public udp6:[$IPADDR]:161 1 | tee $BASENAME.log +# Fetch snmpwalk status code (not $? because this is piped) +STATUS=${PIPESTATUS[0]} + +echo "Closing native node" +sleep 2 +kill_bg $CPID + +if [ $STATUS -eq 0 ] ; then + cp $BASENAME.log $BASENAME.testlog + printf "%-32s TEST OK\n" "$BASENAME" | tee $BASENAME.testlog; +else + echo "==== make.log ====" ; cat make.log; + echo "==== make.err ====" ; cat make.err; + echo "==== node.log ====" ; cat node.log; + echo "==== node.err ====" ; cat node.err; + echo "==== $BASENAME.log ====" ; cat $BASENAME.log; + + printf "%-32s TEST FAIL\n" "$BASENAME" | tee $BASENAME.testlog; +fi + +rm make.log +rm make.err +rm node.log +rm node.err + +# We do not want Make to stop -> Return 0 +# The Makefile will check if a log contains FAIL at the end +exit 0 diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 56775dc7405f7e5633c45c2c9658a60ffd4f0a4a..89cb36c552ed7b7ad2a8a15083fff70391c74d37 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -31,6 +31,9 @@ RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E03280 unzip \ valgrind \ wget \ + smitools \ + snmp \ + snmp-mibs-downloader \ > /dev/null \ && apt-get -qq clean diff --git a/tools/viewconf/viewconf.c b/tools/viewconf/viewconf.c index 1237061ca7ab992f1f8ab976b8b437139944c620..53a38cf6f3cbd94c1e870d26c0897a5978226770 100644 --- a/tools/viewconf/viewconf.c +++ b/tools/viewconf/viewconf.c @@ -149,5 +149,6 @@ ##### "LOG_CONF_LEVEL_FRAMER": _________________ == LOG_CONF_LEVEL_FRAMER ##### "LOG_CONF_LEVEL_6TOP": ___________________ == LOG_CONF_LEVEL_6TOP ##### "LOG_CONF_LEVEL_COAP": ___________________ == LOG_CONF_LEVEL_COAP +##### "LOG_CONF_LEVEL_SNMP": ___________________ == LOG_CONF_LEVEL_SNMP ##### "LOG_CONF_LEVEL_LWM2M": __________________ == LOG_CONF_LEVEL_LWM2M ##### "LOG_CONF_LEVEL_MAIN": ___________________ == LOG_CONF_LEVEL_MAIN