CVE-2020-12141: Out-of-bounds Read (CWE-125)
value: An out-of-bounds read in the SNMP stack in Contiki-NG 4.4 and earlier allows an attacker to cause a denial of service and potentially disclose information via crafted SNMP packets to snmp_ber_decode_string_len_buffer in os/net/app-layer/snmp/snmp-ber.c.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 9.1
Published: 2021-10-19T16:15Z
Repository: https://github.com/contiki-ng/contiki-ng
Language: C
Files changed: examples/snmp-server/project-conf.h, examples/snmp-server/resources/snmp-SNMP-MIB-2-System.c, examples/snmp-server/snmp-server.c, os/net/app-layer/snmp/snmp-api.c, os/net/app-layer/snmp/snmp-api.h, os/net/app-layer/snmp/snmp-ber.c, os/net/app-layer/snmp/snmp-ber.h, os/net/app-layer/snmp/snmp-conf.h, os/net/app-layer/snmp/snmp-engine.c, os/net/app-layer/snmp/snmp-engine.h, os/net/app-layer/snmp/snmp-message.c, os/net/app-layer/snmp/snmp-message.h, os/net/app-layer/snmp/snmp-mib.c, os/net/app-layer/snmp/snmp-mib.h, os/net/app-layer/snmp/snmp.c, os/net/app-layer/snmp/snmp.h, tests/08-native-runs/10-snmp-server.sh
Commit date: 2020-10-18 14:16:37 +0200
Commit message: Refactored SNMP engine after vulnerabilities

Diff: diff --git a/examples/snmp-server/project-conf.h b/examples/snmp-server/project-conf.h
index 744067b11..5017a2ee6 100644
--- a/examples/snmp-server/project-conf.h
+++ b/examples/snmp-server/project-conf.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -28,6 +28,11 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 /*---------------------------------------------------------------------------*/
 
+/*
+ * In order to test SNMP compliance,
+ * at least three OID's in the same package are necessary
+ */
+#define SNMP_CONF_MAX_NR_VALUES 3
 #define LOG_CONF_LEVEL_SNMP     LOG_LEVEL_NONE
diff --git a/examples/snmp-server/resources/snmp-SNMP-MIB-2-System.c b/examples/snmp-server/resources/snmp-SNMP-MIB-2-System.c
index f87d2bd2f..0a80416a4 100644
--- a/examples/snmp-server/resources/snmp-SNMP-MIB-2-System.c
+++ b/examples/snmp-server/resources/snmp-SNMP-MIB-2-System.c
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -31,94 +31,94 @@
 
 #include "snmp-api.h"
 
 /*---------------------------------------------------------------------------*/
 static void
-sysDescr_handler(snmp_varbind_t *varbind, uint32_t *oid);
+sysDescr_handler(snmp_varbind_t *varbind, snmp_oid_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)
+sysDescr_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
 {
   snmp_api_set_string(varbind, oid, CONTIKI_VERSION_STRING);
 }
 /*---------------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------------*/
 static void
-sysObjectID_handler(snmp_varbind_t *varbind, uint32_t *oid);
+sysObjectID_handler(snmp_varbind_t *varbind, snmp_oid_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)
+sysObjectID_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
 {
   OID(sysObjectID_oid, 1, 3, 6, 1, 4, 1, 54352);
-  snmp_api_set_oid(varbind, oid, sysObjectID_oid);
+  snmp_api_set_oid(varbind, oid, &sysObjectID_oid);
 }
 /*---------------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------------*/
 static void
-sysUpTime_handler(snmp_varbind_t *varbind, uint32_t *oid);
+sysUpTime_handler(snmp_varbind_t *varbind, snmp_oid_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)
+sysUpTime_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
 {
   snmp_api_set_time_ticks(varbind, oid, clock_seconds() * 100);
 }
 /*---------------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------------*/
 static void
-sysContact_handler(snmp_varbind_t *varbind, uint32_t *oid);
+sysContact_handler(snmp_varbind_t *varbind, snmp_oid_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)
+sysContact_handler(snmp_varbind_t *varbind, snmp_oid_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);
+sysName_handler(snmp_varbind_t *varbind, snmp_oid_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)
+sysName_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
 {
   snmp_api_set_string(varbind, oid, "Contiki-NG - "CONTIKI_TARGET_STRING);
 }
 /*---------------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------------*/
 static void
-sysLocation_handler(snmp_varbind_t *varbind, uint32_t *oid);
+sysLocation_handler(snmp_varbind_t *varbind, snmp_oid_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)
+sysLocation_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
 {
   snmp_api_set_string(varbind, oid, "");
 }
 /*---------------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------------*/
 static void
-sysServices_handler(snmp_varbind_t *varbind, uint32_t *oid);
+sysServices_handler(snmp_varbind_t *varbind, snmp_oid_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)
+sysServices_handler(snmp_varbind_t *varbind, snmp_oid_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
index dbc638f05..342beaa81 100644
--- a/examples/snmp-server/snmp-server.c
+++ b/examples/snmp-server/snmp-server.c
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
diff --git a/os/net/app-layer/snmp/snmp-api.c b/os/net/app-layer/snmp/snmp-api.c
index 50d252df0..47ee9af1c 100644
--- a/os/net/app-layer/snmp/snmp-api.c
+++ b/os/net/app-layer/snmp/snmp-api.c
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,62 +30,46 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the public API
  * \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_set_string(snmp_varbind_t *varbind, snmp_oid_t *oid, char *string)
 {
-
-  snmp_api_replace_oid(varbind, oid);
+  memcpy(&varbind->oid, oid, sizeof(snmp_oid_t));
   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_set_time_ticks(snmp_varbind_t *varbind, snmp_oid_t *oid, uint32_t integer)
 {
-
-  snmp_api_replace_oid(varbind, oid);
-  varbind->value_type = SNMP_DATA_TYPE_TIME_TICKS;
+  memcpy(&varbind->oid, oid, sizeof(snmp_oid_t));
+  varbind->value_type = BER_DATA_TYPE_TIMETICKS;
   varbind->value.integer = integer;
 }
 /*---------------------------------------------------------------------------*/
 void
-snmp_api_set_oid(snmp_varbind_t *varbind, uint32_t *oid, uint32_t *ret_oid)
+snmp_api_set_oid(snmp_varbind_t *varbind, snmp_oid_t *oid, snmp_oid_t *ret_oid)
 {
-
-  snmp_api_replace_oid(varbind, oid);
-  varbind->value_type = BER_DATA_TYPE_OID;
-  varbind->value.oid = ret_oid;
+  memcpy(&varbind->oid, oid, sizeof(snmp_oid_t));
+  varbind->value_type = BER_DATA_TYPE_OBJECT_IDENTIFIER;
+  memcpy(&varbind->value.oid, ret_oid, sizeof(snmp_oid_t));
 }
 /*---------------------------------------------------------------------------*/
 void
 snmp_api_add_resource(snmp_mib_resource_t *new_resource)
 {
diff --git a/os/net/app-layer/snmp/snmp-api.h b/os/net/app-layer/snmp/snmp-api.h
index a82704f94..a5eb844a0 100644
--- a/os/net/app-layer/snmp/snmp-api.h
+++ b/os/net/app-layer/snmp/snmp-api.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,11 +30,11 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      The public API for the Contiki-NG SNMP implementation
+ *      SNMP Implementation of the public API
  * \author
  *      Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
  */
 
 /**
@@ -47,24 +47,23 @@
 
 #include "snmp.h"
 #include "snmp-mib.h"
 
 /**
- * \defgroup SNMPAPI This is the SNMP Public API
+ * \addtogroup SNMPAPI 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);
+typedef void (*snmp_mib_resource_handler_t)(snmp_varbind_t *varbind, snmp_oid_t *oid);
 
 /**
  * @brief The MIB Resource struct
  */
 typedef struct snmp_mib_resource_s snmp_mib_resource_t;
@@ -76,22 +75,31 @@ typedef struct snmp_mib_resource_s snmp_mib_resource_t;
  *
  * @param name A name for the oid
  * @param ... The Oid (comma-separeted)
  */
 #define OID(name, ...) \
-  static uint32_t name[] = { __VA_ARGS__, -1 };
+  static snmp_oid_t name = { \
+    .data = __VA_ARGS__, \
+    .length = (sizeof((uint32_t[]){ __VA_ARGS__ }) / sizeof(uint32_t)) \
+  };
 
 /**
  * @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 };
+  snmp_mib_resource_t name = { \
+    NULL, \
+    { \
+      .data = __VA_ARGS__, \
+      .length = (sizeof((uint32_t[]){ __VA_ARGS__ }) / sizeof(uint32_t)) \
+    }, \
+    handler \
+  };
 
 /**
  * @brief Function to set a varbind with a string
  *
  * This function should be used inside a handler to set the varbind correctly
@@ -99,11 +107,11 @@ typedef struct snmp_mib_resource_s snmp_mib_resource_t;
  * @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);
+snmp_api_set_string(snmp_varbind_t *varbind, snmp_oid_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
@@ -111,11 +119,11 @@ snmp_api_set_string(snmp_varbind_t *varbind, uint32_t *oid, char *string);
  * @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);
+snmp_api_set_time_ticks(snmp_varbind_t *varbind, snmp_oid_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
@@ -123,11 +131,11 @@ snmp_api_set_time_ticks(snmp_varbind_t *varbind, uint32_t *oid, uint32_t integer
  * @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);
+snmp_api_set_oid(snmp_varbind_t *varbind, snmp_oid_t *oid, snmp_oid_t *ret_oid);
 
 /**
  * @brief Function to add a new resource
  *
  * @param new_resource The resource
diff --git a/os/net/app-layer/snmp/snmp-ber.c b/os/net/app-layer/snmp/snmp-ber.c
index 182877ea3..58c1429ff 100644
--- a/os/net/app-layer/snmp/snmp-ber.c
+++ b/os/net/app-layer/snmp/snmp-ber.c
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,11 +30,11 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the BER encoding
  * \author
  *      Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
  */
 
 #include "contiki.h"
@@ -44,247 +44,467 @@
 
 #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)
+static inline int
+snmp_ber_encode_unsigned_integer(snmp_packet_t *snmp_packet, uint8_t type, uint32_t number)
 {
-  *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;
+  uint16_t original_out_len;
 
-  original_out_len = *out_len;
+  original_out_len = snmp_packet->used;
   do {
-    (*out_len)++;
-    *out-- = (uint8_t)(number & 0xFF);
+    if(snmp_packet->used == snmp_packet->max) {
+      return 0;
+    }
+
+    *snmp_packet->out-- = (uint8_t)number & 0xFF;
+    snmp_packet->used++;
+    /* I'm not sure why but on MSPGCC the >> 8 operation goes haywire here */
+#ifdef __MSPGCC__
+    number >>= 4;
+    number >>= 4;
+#else /* __MSPGCC__ */
     number >>= 8;
+#endif /* __MSPGCC__ */
   } 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);
+  if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used - original_out_len)) {
+    return 0;
+  }
+
+  if(!snmp_ber_encode_type(snmp_packet, type)) {
+    return 0;
+  }
 
-  return out;
+  return 1;
 }
 /*---------------------------------------------------------------------------*/
-unsigned char *
-snmp_ber_encode_unsigned_integer(unsigned char *out, uint32_t *out_len, uint8_t type, uint32_t number)
+int
+snmp_ber_encode_type(snmp_packet_t *snmp_packet, uint8_t type)
 {
-  uint32_t original_out_len;
+  if(snmp_packet->used == snmp_packet->max) {
+    return 0;
+  }
 
-  original_out_len = *out_len;
-  do {
-    (*out_len)++;
-    *out-- = (uint8_t)(number & 0xFF);
-    number >>= 8;
-  } while(number);
+  *snmp_packet->out-- = type;
+  snmp_packet->used++;
+
+  return 1;
+}
+/*---------------------------------------------------------------------------*/
+int
+snmp_ber_encode_length(snmp_packet_t *snmp_packet, uint16_t length)
+{
+  if(length > 0xFF) {
+    if(snmp_packet->used == snmp_packet->max) {
+      return 0;
+    }
+
+    *snmp_packet->out-- = (uint8_t)length & 0xFF;
+    snmp_packet->used++;
+
+    if(snmp_packet->used == snmp_packet->max) {
+      return 0;
+    }
+
+    *snmp_packet->out-- = (uint8_t)(length >> 8) & 0xFF;
+    snmp_packet->used++;
+
+    if(snmp_packet->used == snmp_packet->max) {
+      return 0;
+    }
+
+    *snmp_packet->out-- = 0x82;
+    snmp_packet->used++;
+  } else if(length > 0x7F) {
+    if(snmp_packet->used == snmp_packet->max) {
+      return 0;
+    }
+
+    *snmp_packet->out-- = (uint8_t)length & 0xFF;
+    snmp_packet->used++;
 
-  out = snmp_ber_encode_length(out, out_len, ((*out_len - original_out_len) & 0xFF));
-  out = snmp_ber_encode_type(out, out_len, type);
+    if(snmp_packet->used == snmp_packet->max) {
+      return 0;
+    }
 
-  return out;
+    *snmp_packet->out-- = 0x81;
+    snmp_packet->used++;
+  } else {
+    if(snmp_packet->used == snmp_packet->max) {
+      return 0;
+    }
+
+    *snmp_packet->out-- = (uint8_t)length & 0x7F;
+    snmp_packet->used++;
+  }
+
+  return 1;
+}
+/*---------------------------------------------------------------------------*/
+int
+snmp_ber_encode_timeticks(snmp_packet_t *snmp_packet, uint32_t timeticks)
+{
+  return snmp_ber_encode_unsigned_integer(snmp_packet, BER_DATA_TYPE_TIMETICKS, timeticks);
+}
+/*---------------------------------------------------------------------------*/
+int
+snmp_ber_encode_integer(snmp_packet_t *snmp_packet, uint32_t number)
+{
+  return snmp_ber_encode_unsigned_integer(snmp_packet, BER_DATA_TYPE_INTEGER, number);
 }
 /*---------------------------------------------------------------------------*/
-unsigned char *
-snmp_ber_encode_string_len(unsigned char *out, uint32_t *out_len, const char *str, uint32_t length)
+int
+snmp_ber_encode_string_len(snmp_packet_t *snmp_packet, const char *str, uint32_t length)
 {
   uint32_t i;
 
   str += length - 1;
   for(i = 0; i < length; ++i) {
-    (*out_len)++;
-    *out-- = (uint8_t)*str--;
+    if(snmp_packet->used == snmp_packet->max) {
+      return 0;
+    }
+
+    *snmp_packet->out-- = (uint8_t)*str--;
+    snmp_packet->used++;
   }
 
-  out = snmp_ber_encode_length(out, out_len, length);
-  out = snmp_ber_encode_type(out, out_len, BER_DATA_TYPE_OCTET_STRING);
+  if(!snmp_ber_encode_length(snmp_packet, length)) {
+    return 0;
+  }
 
-  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);
+  if(!snmp_ber_encode_type(snmp_packet, BER_DATA_TYPE_OCTET_STRING)) {
+    return 0;
+  }
 
-  return out;
+  return 1;
 }
 /*---------------------------------------------------------------------------*/
-unsigned char *
-snmp_ber_decode_type(unsigned char *buff, uint32_t *buff_len, uint8_t *type)
+int
+snmp_ber_encode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid)
 {
-  if(*buff_len == 0) {
-    return NULL;
+  uint32_t val;
+  uint16_t original_out_len;
+  uint8_t pos;
+
+  original_out_len = snmp_packet->used;
+
+  pos = oid->length - 1;
+  while(pos) {
+    val = oid->data[pos];
+
+    if(snmp_packet->used == snmp_packet->max) {
+      return 0;
+    }
+
+    *snmp_packet->out-- = (uint8_t)(val & 0x7F);
+    snmp_packet->used++;
+    val >>= 7;
+
+    while(val) {
+      if(snmp_packet->used == snmp_packet->max) {
+        return 0;
+      }
+
+      *snmp_packet->out-- = (uint8_t)((val & 0x7F) | 0x80);
+      snmp_packet->used++;
+
+      val >>= 7;
+    }
+    pos--;
+  }
+
+  if(snmp_packet->used == snmp_packet->max) {
+    return 0;
+  }
+
+  val = *(snmp_packet->out + 1) + 40 * oid->data[pos];
+  snmp_packet->used--;
+  snmp_packet->out++;
+
+  if(snmp_packet->used == snmp_packet->max) {
+    return 0;
+  }
+
+  *snmp_packet->out-- = (uint8_t)(val & 0x7F);
+  snmp_packet->used++;
+
+  val >>= 7;
+
+  while(val) {
+    if(snmp_packet->used == snmp_packet->max) {
+      return 0;
+    }
+
+    *snmp_packet->out-- = (uint8_t)((val & 0x7F) | 0x80);
+    snmp_packet->used++;
+
+    val >>= 7;
+  }
+
+  if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used - original_out_len)) {
+    return 0;
   }
 
-  *type = *buff++;
-  (*buff_len)--;
+  if(!snmp_ber_encode_type(snmp_packet, BER_DATA_TYPE_OBJECT_IDENTIFIER)) {
+    return 0;
+  }
 
-  return buff;
+  return 1;
 }
 /*---------------------------------------------------------------------------*/
-unsigned char *
-snmp_ber_decode_length(unsigned char *buff, uint32_t *buff_len, uint8_t *length)
+int
+snmp_ber_encode_null(snmp_packet_t *snmp_packet, uint8_t type)
 {
-  if(*buff_len == 0) {
-    return NULL;
+
+  if(snmp_packet->used == snmp_packet->max) {
+    return 0;
   }
 
-  *length = *buff++;
-  (*buff_len)--;
+  *snmp_packet->out-- = 0x00;
+  snmp_packet->used++;
 
-  return buff;
+  return snmp_ber_encode_type(snmp_packet, type);
 }
 /*---------------------------------------------------------------------------*/
-unsigned char *
-snmp_ber_decode_integer(unsigned char *buf, uint32_t *buff_len, uint32_t *num)
+static inline int
+snmp_ber_decode_unsigned_integer(snmp_packet_t *snmp_packet, uint8_t expected_type, uint32_t *num)
 {
   uint8_t i, len, type;
 
-  buf = snmp_ber_decode_type(buf, buff_len, &type);
+  if(!snmp_ber_decode_type(snmp_packet, &type)) {
+    return 0;
+  }
 
-  if(buf == NULL || type != BER_DATA_TYPE_INTEGER) {
+  if(type != expected_type) {
     /*
      * Sanity check
      * Invalid type in buffer
      */
-    return NULL;
+    return 0;
   }
 
-  buf = snmp_ber_decode_length(buf, buff_len, &len);
+  if(!snmp_ber_decode_length(snmp_packet, &len)) {
+    return 0;
+  }
 
-  if(buf == NULL || len > 4) {
+  if(len > 4) {
     /*
      * Sanity check
      * It will not fit in the uint32_t
      */
-    return NULL;
+    return 0;
   }
 
-  if(*buff_len < len) {
-    return NULL;
+  if(snmp_packet->used == 0) {
+    return 0;
   }
 
-  *num = (uint32_t)(*buf++ & 0xFF);
-  (*buff_len)--;
+  *num = (uint32_t)(*snmp_packet->in++ & 0xFF);
+  snmp_packet->used--;
+
   for(i = 1; i < len; ++i) {
     *num <<= 8;
-    *num |= (uint8_t)(*buf++ & 0xFF);
-    (*buff_len)--;
+    if(snmp_packet->used == 0) {
+      return 0;
+    }
+    *num |= (uint8_t)(*snmp_packet->in++ & 0xFF);
+    snmp_packet->used--;
   }
 
-  return buf;
+  return 1;
 }
 /*---------------------------------------------------------------------------*/
-unsigned char *
-snmp_ber_decode_unsigned_integer(unsigned char *buf, uint32_t *buff_len, uint8_t expected_type, uint32_t *num)
+int
+snmp_ber_decode_type(snmp_packet_t *snmp_packet, uint8_t *type)
 {
-  uint8_t i, len, type;
-
-  buf = snmp_ber_decode_type(buf, buff_len, &type);
-
-  if(buf == NULL || type != expected_type) {
-    /*
-     * Sanity check
-     * Invalid type in buffer
-     */
-    return NULL;
+  if(snmp_packet->used == 0) {
+    return 0;
   }
 
-  buf = snmp_ber_decode_length(buf, buff_len, &len);
-
-  if(buf == NULL || len > 4) {
-    /*
-     * Sanity check
-     * It will not fit in the uint32_t
-     */
-    return NULL;
-  }
+  *type = *snmp_packet->in++;
+  snmp_packet->used--;
 
-  if(*buff_len < len) {
-    return NULL;
+  return 1;
+}
+/*---------------------------------------------------------------------------*/
+int
+snmp_ber_decode_length(snmp_packet_t *snmp_packet, uint8_t *length)
+{
+  if(snmp_packet->used == 0) {
+    return 0;
   }
 
-  *num = (uint32_t)(*buf++ & 0xFF);
-  (*buff_len)--;
-  for(i = 1; i < len; ++i) {
-    *num <<= 8;
-    *num |= (uint8_t)(*buf++ & 0xFF);
-    (*buff_len)--;
-  }
+  *length = *snmp_packet->in++;
+  snmp_packet->used--;
 
-  return buf;
+  return 1;
+}
+/*---------------------------------------------------------------------------*/
+int
+snmp_ber_decode_timeticks(snmp_packet_t *snmp_packet, uint32_t *timeticks)
+{
+  return snmp_ber_decode_unsigned_integer(snmp_packet, BER_DATA_TYPE_TIMETICKS, timeticks);
 }
 /*---------------------------------------------------------------------------*/
-unsigned char *
-snmp_ber_decode_string_len_buffer(unsigned char *buf, uint32_t *buff_len, const char **str, uint32_t *length)
+int
+snmp_ber_decode_integer(snmp_packet_t *snmp_packet, uint32_t *num)
+{
+  return snmp_ber_decode_unsigned_integer(snmp_packet, BER_DATA_TYPE_INTEGER, num);
+}
+/*---------------------------------------------------------------------------*/
+int
+snmp_ber_decode_string_len_buffer(snmp_packet_t *snmp_packet, const char **str, uint32_t *length)
 {
   uint8_t type, i, length_bytes;
 
-  buf = snmp_ber_decode_type(buf, buff_len, &type);
+  if(!snmp_ber_decode_type(snmp_packet, &type)) {
+    return 0;
+  }
 
-  if(buf == NULL || type != BER_DATA_TYPE_OCTET_STRING) {
+  if(type != BER_DATA_TYPE_OCTET_STRING) {
     /*
      * Sanity check
      * Invalid type in buffer
      */
-    return NULL;
+    return 0;
   }
 
-  if((*buf & 0x80) == 0) {
-    *length = (uint32_t)*buf++;
-    (*buff_len)--;
+  if((*snmp_packet->in & 0x80) == 0) {
+
+    if(snmp_packet->used == 0) {
+      return 0;
+    }
+
+    *length = (uint32_t)*snmp_packet->in++;
+    snmp_packet->used--;
   } else {
 
-    length_bytes = (uint8_t)(*buf++ & 0x7F);
-    (*buff_len)--;
+    if(snmp_packet->used == 0) {
+      return 0;
+    }
+
+    length_bytes = (uint8_t)(*snmp_packet->in++ & 0x7F);
+    snmp_packet->used--;
+
     if(length_bytes > 4) {
       /*
        * Sanity check
        * It will not fit in the uint32_t
        */
-      return NULL;
+      return 0;
+    }
+
+    if(snmp_packet->used == 0) {
+      return 0;
     }
 
-    *length = (uint32_t)*buf++;
-    (*buff_len)--;
+    *length = (uint32_t)*snmp_packet->in++;
+    snmp_packet->used--;
+
     for(i = 1; i < length_bytes; ++i) {
       *length <<= 8;
-      *length |= *buf++;
-      (*buff_len)--;
+
+      if(snmp_packet->used == 0) {
+        return 0;
+      }
+
+      *length |= *snmp_packet->in++;
+      snmp_packet->used--;
     }
   }
 
-  *str = (const char *)buf;
-  *buff_len -= *length;
+  *str = (const char *)snmp_packet->in;
+
+  if(snmp_packet->used == 0 || snmp_packet->used - *length <= 0) {
+    return 0;
+  }
+
+  snmp_packet->used -= *length;
+  snmp_packet->in += *length;
+
+  return 1;
+}
+/*---------------------------------------------------------------------------*/
+int
+snmp_ber_decode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid)
+{
+  uint8_t *buf_end, type;
+  uint8_t len, j;
+  div_t first;
+
+  if(!snmp_ber_decode_type(snmp_packet, &type)) {
+    return 0;
+  }
+
+  if(type != BER_DATA_TYPE_OBJECT_IDENTIFIER) {
+    return 0;
+  }
+
+  if(!snmp_ber_decode_length(snmp_packet, &len)) {
+    return 0;
+  }
+
+  buf_end = snmp_packet->in + len;
+
+  if(snmp_packet->used == 0) {
+    return 0;
+  }
+
+  snmp_packet->used--;
+  first = div(*snmp_packet->in++, 40);
+
+  oid->length = 0;
+
+  oid->data[oid->length++] = (uint32_t)first.quot;
+  oid->data[oid->length++] = (uint32_t)first.rem;
+
+  while(snmp_packet->in != buf_end) {
+    if(oid->length >= SNMP_MSG_OID_MAX_LEN) {
+      return 0;
+    }
 
-  return buf + *length;
+    if(snmp_packet->used == 0) {
+      return 0;
+    }
+    oid->data[oid->length] = (uint32_t)(*snmp_packet->in & 0x7F);
+    for(j = 0; j < 4; j++) {
+      snmp_packet->used--;
+      if((*snmp_packet->in++ & 0x80) == 0) {
+        break;
+      }
+
+      if(snmp_packet->used == 0) {
+        return 0;
+      }
+
+      oid->data[oid->length] <<= 7;
+      oid->data[oid->length] |= (*snmp_packet->in & 0x7F);
+    }
+
+    oid->length++;
+  }
+
+  return 1;
 }
 /*---------------------------------------------------------------------------*/
-unsigned char *
-snmp_ber_decode_null(unsigned char *buf, uint32_t *buff_len)
+int
+snmp_ber_decode_null(snmp_packet_t *snmp_packet)
 {
-  buf++;
-  (*buff_len)--;
+  if(snmp_packet->used == 0) {
+    return 0;
+  }
+
+  snmp_packet->in++;
+  snmp_packet->used--;
+
+  if(snmp_packet->used == 0) {
+    return 0;
+  }
 
-  buf++;
-  (*buff_len)--;
+  snmp_packet->in++;
+  snmp_packet->used--;
 
-  return buf;
+  return 1;
 }
 /*---------------------------------------------------------------------------*/
diff --git a/os/net/app-layer/snmp/snmp-ber.h b/os/net/app-layer/snmp/snmp-ber.h
index 9111276de..2493e6420 100644
--- a/os/net/app-layer/snmp/snmp-ber.h
+++ b/os/net/app-layer/snmp/snmp-ber.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,11 +30,11 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the BER encoding
  * \author
  *      Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
  */
 
 /**
@@ -43,160 +43,271 @@
  */
 
 #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
+/**
+ * \addtogroup SNMPInternal SNMP Internal API
+ * @{
+ *
+ * This group contains all the functions that can be used inside the OS level.
+ */
+
+/**
+ * \addtogroup SNMPBER SNMP BER
+ * @{
+ *
+ * This group contains the BER implementation
+ */
+
+/**
+ * @brief End-of-Content
+ *
+ */
+#define BER_DATA_TYPE_EOC                   0x00
+
+/**
+ * @brief Integer
+ *
+ */
+#define BER_DATA_TYPE_INTEGER               0x02
+
+/**
+ * @brief Octet String
+ *
+ */
+#define BER_DATA_TYPE_OCTET_STRING          0x04
+
+/**
+ * @brief Null
+ *
+ */
+#define BER_DATA_TYPE_NULL                  0x05
+
+/**
+ * @brief Object Identifier
+ *
+ */
+#define BER_DATA_TYPE_OBJECT_IDENTIFIER     0x06
+
+/**
+ * @brief Sequence
+ *
+ */
+#define BER_DATA_TYPE_SEQUENCE              0x30
+
+/**
+ * @brief TimeTicks
+ *
+ */
+#define BER_DATA_TYPE_TIMETICKS             0x43
+
+/**
+ * @brief No Such Instance
+ *
+ */
+#define BER_DATA_TYPE_NO_SUCH_INSTANCE      0x81
+
+/**
+ * @brief End of MIB View
+ *
+ */
+#define BER_DATA_TYPE_END_OF_MIB_VIEW       0x82
+
+/**
+ * @brief PDU Get Request
+ *
+ */
+#define BER_DATA_TYPE_PDU_GET_REQUEST       0xA0
+
+/**
+ * @brief PDU Get Next Request
+ *
+ */
+#define BER_DATA_TYPE_PDU_GET_NEXT_REQUEST  0xA1
+
+/**
+ * @brief PDU Get Reponse
+ *
+ */
+#define BER_DATA_TYPE_PDU_GET_RESPONSE      0xA2
+
+/**
+ * @brief PDU Set Request
+ *
+ */
+#define BER_DATA_TYPE_PDU_SET_REQUEST       0xA3
+
+/**
+ * @brief PDU Trap
+ *
+ */
+#define BER_DATA_TYPE_PDU_TRAP              0xA4
+
+/**
+ * @brief PDU Get Bulk
+ *
+ */
+#define BER_DATA_TYPE_PDU_GET_BULK          0xA5
 
 /**
  * @brief Encodes a type
  *
- * @param out A pointer to the end of the buffer
- * @param out_len A pointer to the buffer length
+ * @param snmp_packet A pointer to the snmp packet
  * @param type A type
  *
- * @return NULL if error or the next entry in the buffer
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_encode_type(unsigned char *out, uint32_t *out_len, uint8_t type);
+int
+snmp_ber_encode_type(snmp_packet_t *snmp_packet, 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 snmp_packet A pointer to the snmp packet
  * @param length A length
  *
- * @return NULL if error or the next entry in the buffer
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_encode_length(unsigned char *out, uint32_t *out_len, uint8_t length);
+int
+snmp_ber_encode_length(snmp_packet_t *snmp_packet, uint16_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 snmp_packet A pointer to the snmp packet
  * @param integer A integer
  *
- * @return NULL if error or the next entry in the buffer
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_encode_integer(unsigned char *out, uint32_t *out_len, uint32_t integer);
+int
+snmp_ber_encode_integer(snmp_packet_t *snmp_packet, uint32_t integer);
 
 /**
- * @brief Encodes an unsigned integer
+ * @brief Encodes a timeticks
  *
- * @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
+ * @param snmp_packet A pointer to the snmp packet
+ * @param timeticks A TimeTicks
  *
- * @return NULL if error or the next entry in the buffer
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_encode_unsigned_integer(unsigned char *out, uint32_t *out_len, uint8_t type, uint32_t number);
+int
+snmp_ber_encode_timeticks(snmp_packet_t *snmp_packet, uint32_t timeticks);
 
 /**
  * @brief Encodes a string
  *
- * @param out A pointer to the end of the buffer
- * @param out_len A pointer to the buffer length
+ * @param snmp_packet A pointer to the snmp packet
  * @param str A string
  * @param length The string length
  *
- * @return NULL if error or the next entry in the buffer
+ * @return 0 if error or 1 if success
+ */
+int
+snmp_ber_encode_string_len(snmp_packet_t *snmp_packet, const char *str, uint32_t length);
+
+/**
+ * @brief Encodes a Oid
+ *
+ * @param snmp_packet A pointer to the snmp packet
+ * @param oid A OID
+ *
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_encode_string_len(unsigned char *out, uint32_t *out_len, const char *str, uint32_t length);
+int
+snmp_ber_encode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid);
 
 /**
  * @brief Encodes a null
  *
- * @param out A pointer to the end of the buffer
- * @param out_len A pointer to the buffer length
+ * @param snmp_packet A pointer to the snmp packet
  * @param type A type
  *
- * @return NULL if error or the next entry in the buffer
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_encode_null(unsigned char *out, uint32_t *out_len, uint8_t type);
+int
+snmp_ber_encode_null(snmp_packet_t *snmp_packet, 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 snmp_packet A pointer to the snmp packet
  * @param type A pointer to the type
  *
- * @return NULL if error or the first entry after the oid in the buffer
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_decode_type(unsigned char *buff, uint32_t *buff_len, uint8_t *type);
+int
+snmp_ber_decode_type(snmp_packet_t *snmp_packet, 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 snmp_packet A pointer to the snmp packet
  * @param length A pointer to the length
  *
- * @return NULL if error or the first entry after the oid in the buffer
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_decode_length(unsigned char *buff, uint32_t *buff_len, uint8_t *length);
+int
+snmp_ber_decode_length(snmp_packet_t *snmp_packet, 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 snmp_packet A pointer to the snmp packet
  * @param integer A pointer to the integer
  *
- * @return NULL if error or the first entry after the oid in the buffer
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_decode_integer(unsigned char *buff, uint32_t *buff_len, uint32_t *integer);
+int
+snmp_ber_decode_integer(snmp_packet_t *snmp_packet, uint32_t *integer);
 
 /**
- * @brief Decodes an unsigned number
+ * @brief Decodes a timeticks
  *
- * @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
+ * @param snmp_packet A pointer to the snmp packet
+ * @param timeticks A pointer to the timeticks
  *
- * @return NULL if error or the first entry after the oid in the buffer
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_decode_unsigned_integer(unsigned char *buff, uint32_t *buff_len, uint8_t expected_type, uint32_t *number);
+int
+snmp_ber_decode_timeticks(snmp_packet_t *snmp_packet, uint32_t *timeticks);
 
 /**
  * @brief Decodes a string
  *
- * @param buff A pointer to the beginning of the buffer
- * @param buff_len A pointer to the buffer length
+ * @param snmp_packet A pointer to the snmp packet
  * @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
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_decode_string_len_buffer(unsigned char *buff, uint32_t *buff_len, const char **str, uint32_t *length);
+int
+snmp_ber_decode_string_len_buffer(snmp_packet_t *snmp_packet, 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
+ * @param snmp_packet A pointer to the snmp packet
  *
- * @return NULL if error or the first entry after the oid in the buffer
+ * @return 0 if error or 1 if success
  */
-unsigned char *
-snmp_ber_decode_null(unsigned char *buff, uint32_t *buff_len);
+int
+snmp_ber_decode_null(snmp_packet_t *snmp_packet);
+
+/**
+ * @brief Decodes an OID
+ *
+ * @param snmp_packet  pointer to the snmp packet
+ * @param oid A pointer to the OID
+ *
+ * @return 0 if error or 1 if success
+ */
+int
+snmp_ber_decode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid);
+
+/** @} */
+
+/** @} */
 
 #endif /* SNMP_BER_H_ */
+
 /** @} */
diff --git a/os/net/app-layer/snmp/snmp-conf.h b/os/net/app-layer/snmp/snmp-conf.h
index c8a11ddad..2c9f54fdd 100644
--- a/os/net/app-layer/snmp/snmp-conf.h
+++ b/os/net/app-layer/snmp/snmp-conf.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,11 +30,11 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      SNMP Configurable Macros
+ *      SNMP Implementation of the configurable macros
  * \author
  *      Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
  */
 
 /**
@@ -44,12 +44,21 @@
 
 #ifndef SNMP_CONF_H_
 #define SNMP_CONF_H_
 
 /**
- * \defgroup SNMPConfs SNMP Configurable Defines
+ * \addtogroup SNMPInternal SNMP Internal API
  * @{
+ *
+ * This group contains all the functions that can be used inside the OS level.
+ */
+
+/**
+ * \addtogroup SNMPConfs SNMP Configurable
+ * @{
+ *
+ * This group contains all the defines that can be configurable following the Contiki standard
  */
 
 #ifdef SNMP_CONF_COMMUNITY
 /**
  * \brief Configurable SNMP Community
@@ -61,10 +70,13 @@
  */
 #define SNMP_COMMUNITY "public"
 #endif
 
 #ifdef SNMP_CONF_MSG_OID_MAX_LEN
+#if SNMP_CONF_MSG_OID_MAX_LEN > 128
+#error "OID is limited to 128 in the standard"
+#endif
 /**
  * \brief Configurable maximum number of IDs in one OID
  */
 #define SNMP_MSG_OID_MAX_LEN SNMP_CONF_MSG_OID_MAX_LEN
 #else
@@ -73,10 +85,13 @@
  */
 #define SNMP_MSG_OID_MAX_LEN 16
 #endif
 
 #ifdef SNMP_CONF_MAX_NR_VALUES
+#if SNMP_CONF_MAX_NR_VALUES > 255
+#error "Number of OID's per packet is limited to 255 in this implementation"
+#endif
 /**
  * \brief Configurable maximum number of OIDs in one response
  */
 #define SNMP_MAX_NR_VALUES SNMP_CONF_MAX_NR_VALUES
 #else
@@ -85,20 +100,12 @@
  */
 #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
+#error "SNMP_CONF_MAX_PACKET_SIZE is obsolete. Use UIP_CONF_BUFFER_SIZE"
+#endif /* SNMP_CONF_MAX_PACKET_SIZE */
 
 #ifdef SNMP_CONF_PORT
 /**
  * \brief Configurable SNMP port
  */
@@ -108,9 +115,12 @@
  * \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
index f9baed4b1..04af0a363 100644
--- a/os/net/app-layer/snmp/snmp-engine.c
+++ b/os/net/app-layer/snmp/snmp-engine.c
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,168 +30,182 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the protocol engine
  * \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"
+#include "snmp-ber.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)
+static inline int
+snmp_engine_get(snmp_header_t *header, snmp_varbind_t *varbinds)
 {
   snmp_mib_resource_t *resource;
-  uint32_t i;
+  uint8_t i;
 
-  for(i = 0; i < varbinds_length; i++) {
-    resource = snmp_mib_find(varbinds[i].oid);
+  i = 0;
+  while(varbinds[i].value_type != BER_DATA_TYPE_EOC && i < SNMP_MAX_NR_VALUES) {
+    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;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
         /*
          * Varbinds are 1 indexed
          */
-        header->error_index_max_repetitions.error_index = i + 1;
+        header->error_index = i + 1;
         break;
       case SNMP_VERSION_2C:
-        (&varbinds[i])->value_type = SNMP_DATA_TYPE_NO_SUCH_INSTANCE;
+        (&varbinds[i])->value_type = BER_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;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
+        header->error_index = 0;
       }
     } else {
-      resource->handler(&varbinds[i], resource->oid);
+      resource->handler(&varbinds[i], &resource->oid);
     }
+
+    i++;
   }
 
   return 0;
 }
 /*---------------------------------------------------------------------------*/
-int
-snmp_engine_get_next(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t varbinds_length)
+static inline int
+snmp_engine_get_next(snmp_header_t *header, snmp_varbind_t *varbinds)
 {
   snmp_mib_resource_t *resource;
-  uint32_t i;
+  uint8_t i;
 
-  for(i = 0; i < varbinds_length; i++) {
-    resource = snmp_mib_find_next(varbinds[i].oid);
+  i = 0;
+  while(varbinds[i].value_type != BER_DATA_TYPE_EOC && i < SNMP_MAX_NR_VALUES) {
+    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;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
         /*
          * Varbinds are 1 indexed
          */
-        header->error_index_max_repetitions.error_index = i + 1;
+        header->error_index = i + 1;
         break;
       case SNMP_VERSION_2C:
-        (&varbinds[i])->value_type = SNMP_DATA_TYPE_END_OF_MIB_VIEW;
+        (&varbinds[i])->value_type = BER_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;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
+        header->error_index = 0;
       }
     } else {
-      resource->handler(&varbinds[i], resource->oid);
+      resource->handler(&varbinds[i], &resource->oid);
     }
+
+    i++;
   }
 
   return 0;
 }
 /*---------------------------------------------------------------------------*/
-int
-snmp_engine_get_bulk(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t *varbinds_length)
+static inline int
+snmp_engine_get_bulk(snmp_header_t *header, snmp_varbind_t *varbinds)
 {
   snmp_mib_resource_t *resource;
-  uint32_t i, j, original_varbinds_length;
-  uint32_t oid[SNMP_MAX_NR_VALUES][SNMP_MSG_OID_MAX_LEN];
+  snmp_oid_t oids[SNMP_MAX_NR_VALUES];
+  uint32_t j, original_varbinds_length;
   uint8_t repeater;
+  uint8_t i, varbinds_length;
 
   /*
    * 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);
+  original_varbinds_length = 0;
+  while(varbinds[original_varbinds_length].value_type != BER_DATA_TYPE_EOC && original_varbinds_length < SNMP_MAX_NR_VALUES) {
+    memcpy(&oids[original_varbinds_length], &varbinds[original_varbinds_length].oid, sizeof(snmp_oid_t));
+    original_varbinds_length++;
   }
 
-  *varbinds_length = 0;
+  varbinds_length = 0;
   for(i = 0; i < original_varbinds_length; i++) {
-    if(i >= header->error_status_non_repeaters.non_repeaters) {
+    if(i >= header->non_repeaters) {
       break;
     }
 
-    resource = snmp_mib_find_next(oid[i]);
+    resource = snmp_mib_find_next(&oids[i]);
     if(!resource) {
       switch(header->version) {
       case SNMP_VERSION_1:
-        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
         /*
          * Varbinds are 1 indexed
          */
-        header->error_index_max_repetitions.error_index = i + 1;
+        header->error_index = i + 1;
         break;
       case SNMP_VERSION_2C:
-        (&varbinds[i])->value_type = SNMP_DATA_TYPE_END_OF_MIB_VIEW;
+        (&varbinds[i])->value_type = BER_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;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
+        header->error_index = 0;
       }
     } else {
-      if(*varbinds_length < SNMP_MAX_NR_VALUES) {
-        resource->handler(&varbinds[*varbinds_length], resource->oid);
-        (*varbinds_length)++;
+      if(varbinds_length < SNMP_MAX_NR_VALUES) {
+        resource->handler(&varbinds[varbinds_length], &resource->oid);
+        (varbinds_length)++;
+      } else {
+        return -1;
       }
     }
   }
 
-  for(i = 0; i < header->error_index_max_repetitions.max_repetitions; i++) {
+  for(i = 0; i < header->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]);
+    for(j = header->non_repeaters; j < original_varbinds_length; j++) {
+      resource = snmp_mib_find_next(&oids[j]);
       if(!resource) {
         switch(header->version) {
         case SNMP_VERSION_1:
-          header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
+          header->error_status = SNMP_STATUS_NO_SUCH_NAME;
           /*
            * Varbinds are 1 indexed
            */
-          header->error_index_max_repetitions.error_index = *varbinds_length + 1;
+          header->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)++;
+          if(varbinds_length < SNMP_MAX_NR_VALUES) {
+            (&varbinds[varbinds_length])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
+            memcpy(&varbinds[varbinds_length].oid, &oids[j], sizeof(snmp_oid_t));
+            (varbinds_length)++;
+          } else {
+            return -1;
           }
           break;
         default:
-          header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
-          header->error_index_max_repetitions.error_index = 0;
+          header->error_status = SNMP_STATUS_NO_SUCH_NAME;
+          header->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);
+        if(varbinds_length < SNMP_MAX_NR_VALUES) {
+          resource->handler(&varbinds[varbinds_length], &resource->oid);
+          (varbinds_length)++;
+          memcpy(&oids[j], &resource->oid, sizeof(snmp_oid_t));
           repeater++;
+        } else {
+          return -1;
         }
       }
     }
     if(repeater == 0) {
       break;
@@ -199,56 +213,56 @@ snmp_engine_get_bulk(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t *
   }
 
   return 0;
 }
 /*---------------------------------------------------------------------------*/
-unsigned char *
-snmp_engine(unsigned char *buff, uint32_t buff_len, unsigned char *out, uint32_t *out_len)
+int
+snmp_engine(snmp_packet_t *snmp_packet)
 {
-  static snmp_header_t header;
-  static snmp_varbind_t varbinds[SNMP_MAX_NR_VALUES];
-  static uint32_t varbind_length = SNMP_MAX_NR_VALUES;
+  snmp_header_t header;
+  snmp_varbind_t varbinds[SNMP_MAX_NR_VALUES];
+
+  memset(&header, 0, sizeof(header));
+  memset(varbinds, 0, sizeof(varbinds));
 
-  buff = snmp_message_decode(buff, buff_len, &header, varbinds, &varbind_length);
-  if(buff == NULL) {
-    return NULL;
+  if(!snmp_message_decode(snmp_packet, &header, varbinds)) {
+    return 0;
   }
 
   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;
+      return 0;
     }
   }
 
   /*
    * 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;
+  case BER_DATA_TYPE_PDU_GET_REQUEST:
+    if(snmp_engine_get(&header, varbinds) == -1) {
+      return 0;
     }
     break;
 
-  case SNMP_DATA_TYPE_PDU_GET_NEXT_REQUEST:
-    if(snmp_engine_get_next(&header, varbinds, varbind_length) == -1) {
-      return NULL;
+  case BER_DATA_TYPE_PDU_GET_NEXT_REQUEST:
+    if(snmp_engine_get_next(&header, varbinds) == -1) {
+      return 0;
     }
     break;
 
-  case SNMP_DATA_TYPE_PDU_GET_BULK:
-    if(snmp_engine_get_bulk(&header, varbinds, &varbind_length) == -1) {
-      return NULL;
+  case BER_DATA_TYPE_PDU_GET_BULK:
+    if(snmp_engine_get_bulk(&header, varbinds) == -1) {
+      return 0;
     }
     break;
 
   default:
     LOG_ERR("Invalid request type");
-    return NULL;
+    return 0;
   }
 
-  header.pdu_type = SNMP_DATA_TYPE_PDU_GET_RESPONSE;
-  out = snmp_message_encode(out, out_len, &header, varbinds, varbind_length);
+  header.pdu_type = BER_DATA_TYPE_PDU_GET_RESPONSE;
 
-  return ++out;
+  return snmp_message_encode(snmp_packet, &header, varbinds);
 }
diff --git a/os/net/app-layer/snmp/snmp-engine.h b/os/net/app-layer/snmp/snmp-engine.h
index d6bc7978e..ccf5b966d 100644
--- a/os/net/app-layer/snmp/snmp-engine.h
+++ b/os/net/app-layer/snmp/snmp-engine.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,11 +30,11 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the protocol engine
  * \author
  *      Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
  */
 
 /**
@@ -43,23 +43,35 @@
  */
 
 #ifndef SNMP_ENGINE_H_
 #define SNMP_ENGINE_H_
 
+/**
+ * \addtogroup SNMPInternal SNMP Internal API
+ * @{
+ *
+ * This group contains all the functions that can be used inside the OS level.
+ */
 #include "snmp.h"
 
 /**
- * @brief Process the SNMP packet and prepares the response
+ * \addtogroup SNMPEngine SNMP Engine
+ * @{
  *
- * @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
+ * This group contains the Engine implementation
+ */
+
+/**
+ * @brief Process the SNMP packet and prepares the response
  *
- * @return NULL in case of fail or the first element in the response buffer
+ * @param snmp_packet A pointer to the snmp packet
  */
-unsigned char *
-snmp_engine(unsigned char *buff, uint32_t buff_len, unsigned char *out, uint32_t *out_len);
+int
+snmp_engine(snmp_packet_t *snmp_packet);
+
+/** @} */
+
+/** @} */
 
 #endif /* SNMP_ENGINE_H_ */
 
 /** @} */
diff --git a/os/net/app-layer/snmp/snmp-message.c b/os/net/app-layer/snmp/snmp-message.c
index 931bc2563..fac4704c4 100644
--- a/os/net/app-layer/snmp/snmp-message.c
+++ b/os/net/app-layer/snmp/snmp-message.c
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,254 +30,325 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the messages
  * \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)
+int
+snmp_message_encode(snmp_packet_t *snmp_packet, snmp_header_t *header, snmp_varbind_t *varbinds)
 {
-  snmp_varbind_t *varbind;
-  uint32_t original_out_len, last_out_len;
+  uint32_t last_out_len;
   int8_t i;
 
-  original_out_len = *out_len;
-  for(i = varbind_num - 1; i >= 0; i--) {
-    varbind = &varbinds[i];
+  for(i = SNMP_MAX_NR_VALUES - 1; i >= 0; i--) {
+    if(varbinds[i].value_type == BER_DATA_TYPE_EOC) {
+      continue;
+    }
 
-    last_out_len = *out_len;
+    last_out_len = snmp_packet->used;
 
-    switch(varbind->value_type) {
+    switch(varbinds[i].value_type) {
     case BER_DATA_TYPE_INTEGER:
-      out = snmp_ber_encode_integer(out, out_len, varbind->value.integer);
+      if(!snmp_ber_encode_integer(snmp_packet, varbinds[i].value.integer)) {
+        LOG_DBG("Could not encode integer type\n");
+        return 0;
+      }
       break;
-    case SNMP_DATA_TYPE_TIME_TICKS:
-      out = snmp_ber_encode_unsigned_integer(out, out_len, varbind->value_type, varbind->value.integer);
+    case BER_DATA_TYPE_TIMETICKS:
+      if(!snmp_ber_encode_timeticks(snmp_packet, varbinds[i].value.integer)) {
+        LOG_DBG("Could not encode timeticks type\n");
+        return 0;
+      }
       break;
     case BER_DATA_TYPE_OCTET_STRING:
-      out = snmp_ber_encode_string_len(out, out_len, varbind->value.string.string, varbind->value.string.length);
+      if(!snmp_ber_encode_string_len(snmp_packet, varbinds[i].value.string.string, varbinds[i].value.string.length)) {
+        LOG_DBG("Could not encode octet string type\n");
+        return 0;
+      }
       break;
-    case BER_DATA_TYPE_OID:
-      out = snmp_oid_encode_oid(out, out_len, varbind->value.oid);
+    case BER_DATA_TYPE_OBJECT_IDENTIFIER:
+      if(!snmp_ber_encode_oid(snmp_packet, &varbinds[i].value.oid)) {
+        LOG_DBG("Could not encode oid type\n");
+        return 0;
+      }
       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);
+    case BER_DATA_TYPE_NO_SUCH_INSTANCE:
+    case BER_DATA_TYPE_END_OF_MIB_VIEW:
+      if(!snmp_ber_encode_null(snmp_packet, varbinds[i].value_type)) {
+        LOG_DBG("Could not encode null type\n");
+        return 0;
+      }
       break;
     default:
-      return NULL;
+      LOG_DBG("Could not encode invlid type\n");
+      return 0;
+    }
+
+    if(!snmp_ber_encode_oid(snmp_packet, &varbinds[i].oid)) {
+      LOG_DBG("Could not encode oid\n");
+      return 0;
+    }
+
+    if(!snmp_ber_encode_length(snmp_packet, (snmp_packet->used - last_out_len))) {
+      LOG_DBG("Could not encode length\n");
+      return 0;
     }
 
-    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);
+    if(!snmp_ber_encode_type(snmp_packet, BER_DATA_TYPE_SEQUENCE)) {
+      LOG_DBG("Could not encode type\n");
+      return 0;
+    }
   }
 
-  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(!snmp_ber_encode_length(snmp_packet, snmp_packet->used)) {
+    LOG_DBG("Could not encode length\n");
+    return 0;
+  }
+  if(!snmp_ber_encode_type(snmp_packet, BER_DATA_TYPE_SEQUENCE)) {
+    LOG_DBG("Could not encode type\n");
+    return 0;
+  }
 
-  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);
+  switch(header->pdu_type) {
+  case BER_DATA_TYPE_PDU_GET_BULK:
+    if(!snmp_ber_encode_integer(snmp_packet, header->max_repetitions)) {
+      LOG_DBG("Could not encode max repetition\n");
+      return 0;
+    }
+
+    if(!snmp_ber_encode_integer(snmp_packet, header->non_repeaters)) {
+      LOG_DBG("Could not encode non repeaters\n");
+      return 0;
+    }
+    break;
+  default:
+    if(!snmp_ber_encode_integer(snmp_packet, header->error_index)) {
+      LOG_DBG("Could not encode error index\n");
+      return 0;
+    }
+
+    if(!snmp_ber_encode_integer(snmp_packet, header->error_status)) {
+      LOG_DBG("Could not encode error status\n");
+      return 0;
+    }
+    break;
   }
-  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);
+  if(!snmp_ber_encode_integer(snmp_packet, header->request_id)) {
+    LOG_DBG("Could not encode request id\n");
+    return 0;
+  }
 
-  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);
+  if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used)) {
+    LOG_DBG("Could not encode length\n");
+    return 0;
+  }
 
-  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(!snmp_ber_encode_type(snmp_packet, header->pdu_type)) {
+    LOG_DBG("Could not encode pdu type\n");
+    return 0;
+  }
 
-  return out;
+  if(!snmp_ber_encode_string_len(snmp_packet, header->community.community, header->community.length)) {
+    LOG_DBG("Could not encode community\n");
+    return 0;
+  }
+
+  if(!snmp_ber_encode_integer(snmp_packet, header->version)) {
+    LOG_DBG("Could not encode version\n");
+    return 0;
+  }
+
+  if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used)) {
+    LOG_DBG("Could not encode length\n");
+    return 0;
+  }
+
+  if(!snmp_ber_encode_type(snmp_packet, BER_DATA_TYPE_SEQUENCE)) {
+    LOG_DBG("Could not encode type\n");
+    return 0;
+  }
+
+  /* Move the pointer to the last position */
+  snmp_packet->out++;
+  return 1;
 }
-uint8_t *
-snmp_message_decode(uint8_t *buf, uint32_t buf_len, snmp_header_t *header,
-                    snmp_varbind_t *varbinds, uint32_t *varbind_num)
+int
+snmp_message_decode(snmp_packet_t *snmp_packet, snmp_header_t *header, snmp_varbind_t *varbinds)
 {
-  uint8_t type, len;
-  uint32_t i, oid_len = SNMP_MSG_OID_MAX_LEN;
+  uint8_t type, len, i;
 
-  buf = snmp_ber_decode_type(buf, &buf_len, &type);
-  if(buf == NULL) {
+  if(!snmp_ber_decode_type(snmp_packet, &type)) {
     LOG_DBG("Could not decode type\n");
-    return NULL;
+    return 0;
   }
 
   if(type != BER_DATA_TYPE_SEQUENCE) {
     LOG_DBG("Invalid type\n");
-    return NULL;
+    return 0;
   }
 
-  buf = snmp_ber_decode_length(buf, &buf_len, &len);
-  if(buf == NULL) {
+  if(!snmp_ber_decode_length(snmp_packet, &len)) {
     LOG_DBG("Could not decode length\n");
-    return NULL;
+    return 0;
   }
 
-  buf = snmp_ber_decode_integer(buf, &buf_len, &header->version);
-  if(buf == NULL) {
+  if(!snmp_ber_decode_integer(snmp_packet, &header->version)) {
     LOG_DBG("Could not decode version\n");
-    return NULL;
+    return 0;
   }
 
-  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;
+  switch(header->version) {
+  case SNMP_VERSION_1:
+  case SNMP_VERSION_2C:
+    break;
+  default:
+    LOG_DBG("Invalid version\n");
+    return 0;
   }
 
-  if(header->version != SNMP_VERSION_1 &&
-     header->version != SNMP_VERSION_2C) {
-    LOG_DBG("Invalid version\n");
-    return NULL;
+  if(!snmp_ber_decode_string_len_buffer(snmp_packet, &header->community.community, &header->community.length)) {
+    LOG_DBG("Could not decode community\n");
+    return 0;
   }
 
-  buf = snmp_ber_decode_type(buf, &buf_len, &type);
-  if(buf == NULL) {
-    LOG_DBG("Could not decode type\n");
-    return NULL;
+  if(!snmp_ber_decode_type(snmp_packet, &header->pdu_type)) {
+    LOG_DBG("Could not decode pdu type\n");
+    return 0;
   }
 
-  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;
+  switch(header->pdu_type) {
+  case BER_DATA_TYPE_PDU_GET_REQUEST:
+  case BER_DATA_TYPE_PDU_GET_NEXT_REQUEST:
+  case BER_DATA_TYPE_PDU_GET_RESPONSE:
+  case BER_DATA_TYPE_PDU_SET_REQUEST:
+  case BER_DATA_TYPE_PDU_GET_BULK:
+    break;
+  default:
+    LOG_DBG("Invalid version\n");
+    return 0;
   }
 
-  buf = snmp_ber_decode_length(buf, &buf_len, &len);
-  if(buf == NULL) {
+  if(!snmp_ber_decode_length(snmp_packet, &len)) {
     LOG_DBG("Could not decode length\n");
-    return NULL;
+    return 0;
   }
 
-  buf = snmp_ber_decode_integer(buf, &buf_len, &header->request_id);
-  if(buf == NULL) {
+  if(!snmp_ber_decode_integer(snmp_packet, &header->request_id)) {
     LOG_DBG("Could not decode request id\n");
-    return NULL;
+    return 0;
   }
 
-  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;
+  switch(header->pdu_type) {
+  case BER_DATA_TYPE_PDU_GET_BULK:
+    if(!snmp_ber_decode_integer(snmp_packet, &header->non_repeaters)) {
+      LOG_DBG("Could not decode non repeaters\n");
+      return 0;
     }
 
-    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;
+    if(!snmp_ber_decode_integer(snmp_packet, &header->max_repetitions)) {
+      LOG_DBG("Could not decode max repetition\n");
+      return 0;
     }
-  } else {
-    buf = snmp_ber_decode_integer(buf, &buf_len, &header->error_status_non_repeaters.error_status);
-    if(buf == NULL) {
+    break;
+  default:
+    if(!snmp_ber_decode_integer(snmp_packet, &header->error_status)) {
       LOG_DBG("Could not decode error status\n");
-      return NULL;
+      return 0;
     }
 
-    buf = snmp_ber_decode_integer(buf, &buf_len, &header->error_index_max_repetitions.error_index);
-    if(buf == NULL) {
+    if(!snmp_ber_decode_integer(snmp_packet, &header->error_index)) {
       LOG_DBG("Could not decode error index\n");
-      return NULL;
+      return 0;
     }
+    break;
   }
 
-  buf = snmp_ber_decode_type(buf, &buf_len, &type);
-  if(buf == NULL) {
+  if(!snmp_ber_decode_type(snmp_packet, &type)) {
     LOG_DBG("Could not decode type\n");
-    return NULL;
+    return 0;
   }
 
   if(type != BER_DATA_TYPE_SEQUENCE) {
     LOG_DBG("Invalid type\n");
-    return NULL;
+    return 0;
   }
 
-  buf = snmp_ber_decode_length(buf, &buf_len, &len);
-  if(buf == NULL) {
+  if(!snmp_ber_decode_length(snmp_packet, &len)) {
     LOG_DBG("Could not decode length\n");
-    return NULL;
+    return 0;
   }
 
-  for(i = 0; buf_len > 0; ++i) {
-    if(i >= *varbind_num) {
-      return NULL;
+  for(i = 0; snmp_packet->used > 0; ++i) {
+    if(i >= SNMP_MAX_NR_VALUES) {
+      LOG_DBG("OID's overflow\n");
+      return 0;
     }
 
-    buf = snmp_ber_decode_type(buf, &buf_len, &type);
-    if(buf == NULL) {
+    if(!snmp_ber_decode_type(snmp_packet, &type)) {
       LOG_DBG("Could not decode type\n");
-      return NULL;
+      return 0;
     }
 
     if(type != BER_DATA_TYPE_SEQUENCE) {
       LOG_DBG("Invalid (%X) type\n", type);
-      return NULL;
+      return 0;
     }
 
-    buf = snmp_ber_decode_length(buf, &buf_len, &len);
-    if(buf == NULL) {
+    if(!snmp_ber_decode_length(snmp_packet, &len)) {
       LOG_DBG("Could not decode length\n");
-      return NULL;
+      return 0;
     }
 
-    buf = snmp_oid_decode_oid(buf, &buf_len, varbinds[i].oid, &oid_len);
-    if(buf == NULL) {
+    if(!snmp_ber_decode_oid(snmp_packet, &varbinds[i].oid)) {
       LOG_DBG("Could not decode oid\n");
-      return NULL;
+      return 0;
     }
 
-    varbinds[i].value_type = *buf;
+    varbinds[i].value_type = *snmp_packet->in;
 
     switch(varbinds[i].value_type) {
     case BER_DATA_TYPE_INTEGER:
-      buf = snmp_ber_decode_integer(buf, &buf_len, &varbinds[i].value.integer);
+      if(!snmp_ber_decode_integer(snmp_packet, &varbinds[i].value.integer)) {
+        LOG_DBG("Could not decode integer type\n");
+        return 0;
+      }
       break;
-    case SNMP_DATA_TYPE_TIME_TICKS:
-      buf = snmp_ber_decode_unsigned_integer(buf, &buf_len, varbinds[i].value_type, &varbinds[i].value.integer);
+    case BER_DATA_TYPE_TIMETICKS:
+      if(!snmp_ber_decode_timeticks(snmp_packet, &varbinds[i].value.integer)) {
+        LOG_DBG("Could not decode timeticks type\n");
+        return 0;
+      }
       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);
+      if(!snmp_ber_decode_string_len_buffer(snmp_packet, &varbinds[i].value.string.string, &varbinds[i].value.string.length)) {
+        LOG_DBG("Could not decode octed string type\n");
+        return 0;
+      }
       break;
     case BER_DATA_TYPE_NULL:
-      buf = snmp_ber_decode_null(buf, &buf_len);
+      if(!snmp_ber_decode_null(snmp_packet)) {
+        LOG_DBG("Could not decode null type\n");
+        return 0;
+      }
       break;
     default:
       LOG_DBG("Invalid varbind type\n");
-      return NULL;
-    }
-
-    if(buf == NULL) {
-      LOG_DBG("Could varbind type\n");
-      return NULL;
+      return 0;
     }
   }
 
-  *varbind_num = i;
-
-  return buf;
+  return 1;
 }
diff --git a/os/net/app-layer/snmp/snmp-message.h b/os/net/app-layer/snmp/snmp-message.h
index 26436b9b7..3bd1706de 100644
--- a/os/net/app-layer/snmp/snmp-message.h
+++ b/os/net/app-layer/snmp/snmp-message.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,11 +30,11 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the messages
  * \author
  *      Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
  */
 
 /**
@@ -43,50 +43,51 @@
  */
 
 #ifndef SNMP_MESSAGE_H_
 #define SNMP_MESSAGE_H_
 
-#include "snmp.h"
+/**
+ * \addtogroup SNMPInternal SNMP Internal API
+ * @{
+ *
+ * This group contains all the functions that can be used inside the OS level.
+ */
 
-#define SNMP_DATA_TYPE_TIME_TICKS               0x43
-#define SNMP_DATA_TYPE_NO_SUCH_INSTANCE         0x81
-#define SNMP_DATA_TYPE_END_OF_MIB_VIEW          0x82
+#include "snmp.h"
 
-#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
+/**
+ * \addtogroup SNMPMessage SNMP Message
+ * @{
+ *
+ * This group contains the Message implementation
+ */
 
 /**
  * @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 snmp_packet A pointer to the snmp packet
  * @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);
+int
+snmp_message_encode(snmp_packet_t *snmp_packet, snmp_header_t *header, snmp_varbind_t *varbinds);
 /**
  * @brief
  *
- * @param buf A pointer to the beginning of the buffer
- * @param buf_len A pointer to the buffer length
+ * @param snmp_packet A pointer to the snmp packet
  * @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);
+int
+snmp_message_decode(snmp_packet_t *snmp_packet, snmp_header_t *header, snmp_varbind_t *varbinds);
+
+/** @} */
+
+/** @} */
 
 #endif /* SNMP_MESSAGE_H_ */
 
 /** @} */
diff --git a/os/net/app-layer/snmp/snmp-mib.c b/os/net/app-layer/snmp/snmp-mib.c
index fae834af1..2e35dfbc3 100644
--- a/os/net/app-layer/snmp/snmp-mib.c
+++ b/os/net/app-layer/snmp/snmp-mib.c
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,88 +30,138 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the MIB
  * \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);
 
+/*---------------------------------------------------------------------------*/
+/**
+ * @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
+ */
+static inline int
+snmp_mib_cmp_oid(snmp_oid_t *oid1, snmp_oid_t *oid2)
+{
+  uint8_t i;
+
+  i = 0;
+  while(i < oid1->length && i < oid2->length) {
+    if(oid1->data[i] != oid2->data[i]) {
+      if(oid1->data[i] < oid2->data[i]) {
+        return -1;
+      }
+      return 1;
+    }
+    i++;
+  }
+
+  if(i == oid1->length &&
+     i < oid2->length) {
+    return -1;
+  }
+
+  if(i < oid1->length &&
+     i == oid2->length) {
+    return 1;
+  }
+
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
 snmp_mib_resource_t *
-snmp_mib_find(uint32_t *oid)
+snmp_mib_find(snmp_oid_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)) {
+    if(!snmp_mib_cmp_oid(oid, &resource->oid)) {
       return resource;
     }
   }
 
   return NULL;
 }
+/*---------------------------------------------------------------------------*/
 snmp_mib_resource_t *
-snmp_mib_find_next(uint32_t *oid)
+snmp_mib_find_next(snmp_oid_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) {
+    if(snmp_mib_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;
+  uint8_t i;
 
   for(resource = list_head(snmp_mib);
       resource; resource = resource->next) {
 
-    if(snmp_oid_cmp_oid(resource->oid, new_resource->oid) > 0) {
+    if(snmp_mib_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);
+  if(LOG_DBG_ENABLED) {
+    /*
+     * We print the entire resource table
+     */
+    LOG_DBG("Table after insert.\n");
+    for(resource = list_head(snmp_mib);
+        resource; resource = resource->next) {
+
+      i = 0;
+      LOG_DBG("{");
+      while(i < resource->oid.length) {
+        LOG_DBG_("%lu", (unsigned long)resource->oid.data[i]);
+        i++;
+        if(i < resource->oid.length) {
+          LOG_DBG_(".");
+        }
+      }
+      LOG_DBG_("}\n");
+    }
   }
-#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
index 84115156a..34b63b82a 100644
--- a/os/net/app-layer/snmp/snmp-mib.h
+++ b/os/net/app-layer/snmp/snmp-mib.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,11 +30,11 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the MIB
  * \author
  *      Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
  */
 
 /**
@@ -43,19 +43,33 @@
  */
 
 #ifndef SNMP_MIB_H_
 #define SNMP_MIB_H_
 
+/**
+ * \addtogroup SNMPInternal SNMP Internal API
+ * @{
+ *
+ * This group contains all the functions that can be used inside the OS level.
+ */
+
 #include "snmp.h"
 
+/**
+ * \addtogroup SNMPMIB SNMP MIB
+ * @{
+ *
+ * This group contains the MIB implementation
+ */
+
 /**
  * @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);
+typedef void (*snmp_mib_resource_handler_t)(snmp_varbind_t *varbind, snmp_oid_t *oid);
 
 /**
  * @brief The MIB Resource struct
  */
 typedef struct snmp_mib_resource_s {
@@ -64,15 +78,13 @@ typedef struct snmp_mib_resource_s {
    *
    * @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.
+   * @brief A OID struct
    */
-  uint32_t *oid;
+  snmp_oid_t oid;
   /**
    * @brief The function handler that is called for this resource
    */
   snmp_mib_resource_handler_t handler;
 } snmp_mib_resource_t;
@@ -83,21 +95,21 @@ typedef struct snmp_mib_resource_s {
  * @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);
+snmp_mib_find(snmp_oid_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);
+snmp_mib_find_next(snmp_oid_t *oid);
 
 /**
  * @brief Adds a resource into the linked list
  *
  * @param resource The resource
@@ -109,7 +121,12 @@ 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
deleted file mode 100644
index 29e4a2637..000000000
--- a/os/net/app-layer/snmp/snmp-oid.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 1da2d16d2..000000000
--- a/os/net/app-layer/snmp/snmp-oid.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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
index a721129fc..873ede9ba 100644
--- a/os/net/app-layer/snmp/snmp.c
+++ b/os/net/app-layer/snmp/snmp.c
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,16 +30,17 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the process
  * \author
  *      Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
  */
 
 #include "contiki.h"
+#include "contiki-net.h"
 
 #include "snmp.h"
 #include "snmp-mib.h"
 #include "snmp-engine.h"
 
@@ -48,41 +49,11 @@
 
 /*---------------------------------------------------------------------------*/
 #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);
-  }
-}
+static struct uip_udp_conn *snmp_udp_conn;
 /*---------------------------------------------------------------------------*/
 void
 snmp_init()
 {
   snmp_mib_init();
@@ -93,23 +64,49 @@ snmp_init()
 /*---------------------------------------------------------------------------*/
 PROCESS_THREAD(snmp_process, ev, data)
 {
   PROCESS_BEGIN();
 
+  snmp_packet_t snmp_packet;
+
   /* 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();
-      }
+    if(ev != tcpip_event) {
+      continue;
+    }
+
+    if(!uip_newdata()) {
+      continue;
     }
+
+    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());
+
+    /* Setup SNMP packet */
+    snmp_packet.in = (uint8_t *)uip_appdata;
+    snmp_packet.used = uip_datalen();
+
+    snmp_packet.out = (uint8_t *)(uip_appdata + UIP_BUFSIZE - UIP_IPUDPH_LEN);
+    snmp_packet.max = UIP_BUFSIZE - UIP_IPUDPH_LEN;
+
+    /* Handle the request */
+    if(!snmp_engine(&snmp_packet)) {
+      LOG_DBG("Error while handling the request\n");
+      continue;
+    }
+
+    LOG_DBG("Sending response\n");
+    /* Send the response */
+    uip_udp_packet_sendto(snmp_udp_conn, snmp_packet.out, snmp_packet.used, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport);
   } /* while (1) */
 
   PROCESS_END();
 }
 /*---------------------------------------------------------------------------*/
diff --git a/os/net/app-layer/snmp/snmp.h b/os/net/app-layer/snmp/snmp.h
index f6c4be066..7e193f959 100644
--- a/os/net/app-layer/snmp/snmp.h
+++ b/os/net/app-layer/snmp/snmp.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 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:
@@ -30,41 +30,49 @@
  */
 /*---------------------------------------------------------------------------*/
 
 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the process
  * \author
  *      Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
  */
 
 /**
  * \addtogroup apps
  * @{
  *
- * \defgroup snmp SNMP (Simple Network Management Protocol)
+ * \addtogroup snmp An implementation of SNMP
  * @{
  *
  * This is an implementation of the Simple Network Management Protocol
  */
 
 #ifndef SNMP_H_
 #define SNMP_H_
 
+/**
+ * \addtogroup SNMPInternal SNMP Internal API
+ * @{
+ *
+ * This group contains all the functions that can be used inside the OS level.
+ */
+
 #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
+ * \addtogroup SNMPCore SNMP Core
  * @{
+ *
+ * This group contains the SNMP MIB implementation
  */
 
 /**
  * @brief SNMP Version 1 code
  */
@@ -77,17 +85,10 @@
 /**
  * @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 {
   /**
@@ -118,69 +119,68 @@ typedef struct snmp_header_s {
   /**
    * @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
+   * @brief The error status
    */
-  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;
+  uint32_t error_status;
   /**
-   * @brief Union to hold the error index or the max repetitions
-   *
-   * @remarks A union was used since these values cannot co-exist
+   * @brief The non repeaters
    */
-  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;
+  uint32_t non_repeaters;
+  /**
+   * @brief The error index
+   */
+  uint32_t error_index;
+  /**
+   * @brief The max repetitions
+   */
+  uint32_t max_repetitions;
 } snmp_header_t;
 
+/**
+ * @brief The OID struct
+ */
+typedef struct snmp_oid_s {
+  /**
+   * @brief The OID
+   */
+  uint32_t data[SNMP_MSG_OID_MAX_LEN];
+  /**
+   * @brief The OID length
+   *
+   */
+  uint8_t length;
+} snmp_oid_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];
+  snmp_oid_t oid;
   /**
    * @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 {
+  union {
     /**
      * @brief The integer value
      */
     uint32_t integer;
     /**
      * @brief A struct that contains the string
      */
-    struct snmp_varbind_string_s {
+    struct {
       /**
        * @brief A pointer to the string value from this varbind
        *
        * @remarks This pointer points to a string that cannot be changed
        */
@@ -191,29 +191,53 @@ typedef struct snmp_varbind_s {
        * @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
+     * @brief The OID value
      */
-    uint32_t *oid;
+    snmp_oid_t oid;
   } value;
 } snmp_varbind_t;
 
-/** @}*/
-
 /**
- * \defgroup SNMPFunctions SNMP Functions
- * @{
+ * @brief The packet struct
+ *
  */
+typedef struct {
+  /**
+   * @brief The number os bytes used
+   *
+   */
+  uint16_t used;
+  /**
+   * @brief The maximum number of bytes
+   *
+   */
+  uint16_t max;
+  /**
+   * @brief The pointer used for the incoming packet
+   *
+   */
+  uint8_t *in;
+  /**
+   * @brief The pointer used for the outgoing packet
+   *
+   */
+  uint8_t *out;
+} snmp_packet_t;
 
 /**
  * @brief Initializes the SNMP engine
  */
 void
 snmp_init();
 
 /** @}*/
 
+/** @}*/
+
 #endif /* SNMP_H_ */
+
 /** @} */
+
 /** @} */
diff --git a/tests/08-native-runs/10-snmp-server.sh b/tests/08-native-runs/10-snmp-server.sh
index 6a6e12f38..240fa5d80 100644
--- a/tests/08-native-runs/10-snmp-server.sh
+++ b/tests/08-native-runs/10-snmp-server.sh
@@ -6,43 +6,77 @@ 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
+test_handler () {
+  # Starting Contiki-NG 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
+
+  $1 2>&1 | grep -z -E "$2" >> $BASENAME.log 2>&1 
+  STATUS=$?
+  
+  sleep 2
+  kill_bg $CPID > /dev/null 2>&1
+  wait $CPID > /dev/null 2>&1
+
+  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
+}
+
+# v1
+## snmpget - pass
+test_handler "snmpget -t2 -v1 -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.0" "iso\.3\.6\.1\.2\.1\.1\.1\.0"
+## snmpwalk - pass
+test_handler "snmpwalk -t2 -v1 -c public udp6:[$IPADDR]:161 1" "iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.2\.0.*iso\.3\.6\.1\.2\.1\.1\.3\.0.*iso\.3\.6\.1\.2\.1\.1\.4\.0.*iso\.3\.6\.1\.2\.1\.1\.5\.0.*iso\.3\.6\.1\.2\.1\.1\.6\.0.*iso\.3\.6\.1\.2\.1\.1\.7\.0.*End of MIB"
+
+## snmpget - fail - noSuchName
+test_handler "snmpget -t2 -v1 -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1" ".*noSuchName.*"
+## snmpget - fail - timeout - 16 Ids in OID
+test_handler "snmpget -t2 -v1 -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.1.3.6.1.2.1.1.1.1" "Timeout.*"
+## snmpget - fail - timeout - 4 OIDs
+test_handler "snmpget -t2 -v1 -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0" "Timeout.*"
+
+# v2
+## snmpget - pass
+test_handler "snmpget -t2 -v2c -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.0" "iso\.3\.6\.1\.2\.1\.1\.1\.0"
+## snmpwalk - pass
+test_handler "snmpwalk -t2 -v2c -c public udp6:[$IPADDR]:161 1" "iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.2\.0.*iso\.3\.6\.1\.2\.1\.1\.3\.0.*iso\.3\.6\.1\.2\.1\.1\.4\.0.*iso\.3\.6\.1\.2\.1\.1\.5\.0.*iso\.3\.6\.1\.2\.1\.1\.6\.0.*iso\.3\.6\.1\.2\.1\.1\.7\.0.*iso\.3\.6\.1\.2\.1\.1\.7\.0"
+## snmpbulkget two non-repeater - pass
+test_handler "snmpbulkget -v2c -Cn2 -c public udp6:[$IPADDR]:161 1 1" "iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.1\.0"
+## snmpbulkget two max-repetitions - pass
+test_handler "snmpbulkget -t2 -v2c -Cr2 -c public udp6:[$IPADDR]:161 1" "iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.2\.0"
+## snmpbulkget one non-repeater and two max-repetitions - pass
+test_handler "snmpbulkget -t2 -v2c -Cn1 -Cr2 -c public udp6:[$IPADDR]:161 1 1" "iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.2\.0"
+
+## snmpget - fail - noSuchName
+test_handler "snmpget -t2 -v2c -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1" ".*No Such Instance currently.*"
+## snmpget - fail - timeout - 16 Ids in OID
+test_handler "snmpget -t2 -v2c -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.1.3.6.1.2.1.1.1.1" "Timeout.*"
+## snmpget - fail - timeout - 4 OIDs
+test_handler "snmpget -t2 -v2c -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0" "Timeout.*"
+
+#v3
+## snmpget - fail - timeout - v3 not implemented
+test_handler "snmpget -t2 -v3 -l authPriv -u snmp-poller -a SHA -A \"PASSWORD1\" -x AES -X \"PASSWORD1\" udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.0" ".*Timeout.*"
 
 # We do not want Make to stop -> Return 0
 # The Makefile will check if a log contains FAIL at the end
 exit 0

Vulnerable code:  * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
sysDescr_handler(snmp_varbind_t *varbind, uint32_t *oid);
sysDescr_handler(snmp_varbind_t *varbind, uint32_t *oid)
sysObjectID_handler(snmp_varbind_t *varbind, uint32_t *oid);
sysObjectID_handler(snmp_varbind_t *varbind, uint32_t *oid)
  snmp_api_set_oid(varbind, oid, sysObjectID_oid);
sysUpTime_handler(snmp_varbind_t *varbind, uint32_t *oid);
sysUpTime_handler(snmp_varbind_t *varbind, uint32_t *oid)
sysContact_handler(snmp_varbind_t *varbind, uint32_t *oid);
sysContact_handler(snmp_varbind_t *varbind, uint32_t *oid)
sysName_handler(snmp_varbind_t *varbind, uint32_t *oid);
sysName_handler(snmp_varbind_t *varbind, uint32_t *oid)
sysLocation_handler(snmp_varbind_t *varbind, uint32_t *oid);
sysLocation_handler(snmp_varbind_t *varbind, uint32_t *oid)
sysServices_handler(snmp_varbind_t *varbind, uint32_t *oid);
sysServices_handler(snmp_varbind_t *varbind, uint32_t *oid)
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
#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);
}
snmp_api_set_string(snmp_varbind_t *varbind, uint32_t *oid, char *string)

  snmp_api_replace_oid(varbind, oid);
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;
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;
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      The public API for the Contiki-NG SNMP implementation
 * \defgroup SNMPAPI This is the SNMP Public API
 * The function outside this header can be changed without notice
typedef void (*snmp_mib_resource_handler_t)(snmp_varbind_t *varbind, uint32_t *oid);
  static uint32_t name[] = { __VA_ARGS__, -1 };
  uint32_t name##_oid[] = { __VA_ARGS__, -1 }; \
  snmp_mib_resource_t name = { NULL, name##_oid, handler };
snmp_api_set_string(snmp_varbind_t *varbind, uint32_t *oid, char *string);
snmp_api_set_time_ticks(snmp_varbind_t *varbind, uint32_t *oid, uint32_t integer);
snmp_api_set_oid(snmp_varbind_t *varbind, uint32_t *oid, uint32_t *ret_oid);
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
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;
    (*out_len)++;
    *out-- = (uint8_t)(number & 0xFF);
  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)
    (*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)
  if(*buff_len == 0) {
    return NULL;
  *type = *buff++;
  (*buff_len)--;
  return buff;
unsigned char *
snmp_ber_decode_length(unsigned char *buff, uint32_t *buff_len, uint8_t *length)
  if(*buff_len == 0) {
    return NULL;
  *length = *buff++;
  (*buff_len)--;
  return buff;
unsigned char *
snmp_ber_decode_integer(unsigned char *buf, uint32_t *buff_len, uint32_t *num)
  buf = snmp_ber_decode_type(buf, buff_len, &type);
  if(buf == NULL || type != BER_DATA_TYPE_INTEGER) {
    return NULL;
  buf = snmp_ber_decode_length(buf, buff_len, &len);
  if(buf == NULL || len > 4) {
    return NULL;
  if(*buff_len < len) {
    return NULL;
  *num = (uint32_t)(*buf++ & 0xFF);
  (*buff_len)--;
    *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(buf == NULL || type != expected_type) {
    /*
     * Sanity check
     * Invalid type in buffer
     */
    return NULL;
  buf = snmp_ber_decode_length(buf, buff_len, &len);

  if(buf == NULL || len > 4) {
    /*
     * Sanity check
     * It will not fit in the uint32_t
     */
    return NULL;
  }
  if(*buff_len < len) {
    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)
  buf = snmp_ber_decode_type(buf, buff_len, &type);
  if(buf == NULL || type != BER_DATA_TYPE_OCTET_STRING) {
    return NULL;
  if((*buf & 0x80) == 0) {
    *length = (uint32_t)*buf++;
    (*buff_len)--;
    length_bytes = (uint8_t)(*buf++ & 0x7F);
    (*buff_len)--;
      return NULL;
    *length = (uint32_t)*buf++;
    (*buff_len)--;
      *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;
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
#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
 * @param out A pointer to the end of the buffer
 * @param out_len A pointer to the buffer length
 * @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);
 * @param out A pointer to the end of the buffer
 * @param out_len A pointer to the buffer 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);
 * @param out A pointer to the end of the buffer
 * @param out_len A pointer to the buffer length
 * @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);
 * @param out A pointer to the end of the buffer
 * @param out_len A pointer to the buffer 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);
 * @param out A pointer to the end of the buffer
 * @param out_len A pointer to the buffer length
 * @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);
 * @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_type(unsigned char *buff, uint32_t *buff_len, uint8_t *type);
 * @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_length(unsigned char *buff, uint32_t *buff_len, uint8_t *length);
 * @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_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);
 * @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_string_len_buffer(unsigned char *buff, uint32_t *buff_len, const char **str, uint32_t *length);
 * @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);
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Configurable Macros
 * \defgroup SNMPConfs SNMP Configurable Defines
/**
 * \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
/*@}*/
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
#include "snmp-oid.h"
int
snmp_engine_get(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t varbinds_length)
  uint32_t i;
  for(i = 0; i < varbinds_length; i++) {
    resource = snmp_mib_find(varbinds[i].oid);
        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index_max_repetitions.error_index = i + 1;
        (&varbinds[i])->value_type = SNMP_DATA_TYPE_NO_SUCH_INSTANCE;
        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index_max_repetitions.error_index = 0;
      resource->handler(&varbinds[i], resource->oid);
int
snmp_engine_get_next(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t varbinds_length)
  uint32_t i;
  for(i = 0; i < varbinds_length; i++) {
    resource = snmp_mib_find_next(varbinds[i].oid);
        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index_max_repetitions.error_index = i + 1;
        (&varbinds[i])->value_type = SNMP_DATA_TYPE_END_OF_MIB_VIEW;
        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index_max_repetitions.error_index = 0;
      resource->handler(&varbinds[i], resource->oid);
int
snmp_engine_get_bulk(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t *varbinds_length)
  uint32_t i, j, original_varbinds_length;
  uint32_t oid[SNMP_MAX_NR_VALUES][SNMP_MSG_OID_MAX_LEN];
  original_varbinds_length = *varbinds_length;
  for(i = 0; i < original_varbinds_length; i++) {
    snmp_oid_copy(oid[i], varbinds[i].oid);
  *varbinds_length = 0;
    if(i >= header->error_status_non_repeaters.non_repeaters) {
    resource = snmp_mib_find_next(oid[i]);
        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index_max_repetitions.error_index = i + 1;
        (&varbinds[i])->value_type = SNMP_DATA_TYPE_END_OF_MIB_VIEW;
        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index_max_repetitions.error_index = 0;
      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++) {
    for(j = header->error_status_non_repeaters.non_repeaters; j < original_varbinds_length; j++) {
      resource = snmp_mib_find_next(oid[j]);
          header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
          header->error_index_max_repetitions.error_index = *varbinds_length + 1;
          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)++;
          header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
          header->error_index_max_repetitions.error_index = 0;
        if(*varbinds_length < SNMP_MAX_NR_VALUES) {
          resource->handler(&varbinds[*varbinds_length], resource->oid);
          (*varbinds_length)++;
          snmp_oid_copy(oid[j], resource->oid);
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 = SNMP_MAX_NR_VALUES;
  buff = snmp_message_decode(buff, buff_len, &header, varbinds, &varbind_length);
  if(buff == NULL) {
    return NULL;
      return NULL;
  case SNMP_DATA_TYPE_PDU_GET_REQUEST:
    if(snmp_engine_get(&header, varbinds, varbind_length) == -1) {
      return NULL;
  case SNMP_DATA_TYPE_PDU_GET_NEXT_REQUEST:
    if(snmp_engine_get_next(&header, varbinds, varbind_length) == -1) {
      return NULL;
  case SNMP_DATA_TYPE_PDU_GET_BULK:
    if(snmp_engine_get_bulk(&header, varbinds, &varbind_length) == -1) {
      return NULL;
    return NULL;
  header.pdu_type = SNMP_DATA_TYPE_PDU_GET_RESPONSE;
  out = snmp_message_encode(out, out_len, &header, varbinds, varbind_length);
  return ++out;
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
 * @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);
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
#include "snmp-oid.h"
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;
  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) {
      out = snmp_ber_encode_integer(out, out_len, varbind->value.integer);
    case SNMP_DATA_TYPE_TIME_TICKS:
      out = snmp_ber_encode_unsigned_integer(out, out_len, varbind->value_type, varbind->value.integer);
      out = snmp_ber_encode_string_len(out, out_len, varbind->value.string.string, varbind->value.string.length);
    case BER_DATA_TYPE_OID:
      out = snmp_oid_encode_oid(out, out_len, varbind->value.oid);
    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);
      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 = SNMP_MSG_OID_MAX_LEN;
  buf = snmp_ber_decode_type(buf, &buf_len, &type);
  if(buf == NULL) {
    return NULL;
    return NULL;
  buf = snmp_ber_decode_length(buf, &buf_len, &len);
  if(buf == NULL) {
    return NULL;
  buf = snmp_ber_decode_integer(buf, &buf_len, &header->version);
  if(buf == NULL) {
    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) {
    return NULL;
  buf = snmp_ber_decode_integer(buf, &buf_len, &header->request_id);
  if(buf == NULL) {
    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) {
      return NULL;
    buf = snmp_ber_decode_integer(buf, &buf_len, &header->error_index_max_repetitions.error_index);
    if(buf == NULL) {
      return NULL;
  buf = snmp_ber_decode_type(buf, &buf_len, &type);
  if(buf == NULL) {
    return NULL;
    return NULL;
  buf = snmp_ber_decode_length(buf, &buf_len, &len);
  if(buf == NULL) {
    return NULL;
  for(i = 0; buf_len > 0; ++i) {
    if(i >= *varbind_num) {
      return NULL;
    buf = snmp_ber_decode_type(buf, &buf_len, &type);
    if(buf == NULL) {
      return NULL;
      return NULL;
    buf = snmp_ber_decode_length(buf, &buf_len, &len);
    if(buf == NULL) {
      return NULL;
    buf = snmp_oid_decode_oid(buf, &buf_len, varbinds[i].oid, &oid_len);
    if(buf == NULL) {
      return NULL;
    varbinds[i].value_type = *buf;
      buf = snmp_ber_decode_integer(buf, &buf_len, &varbinds[i].value.integer);
    case SNMP_DATA_TYPE_TIME_TICKS:
      buf = snmp_ber_decode_unsigned_integer(buf, &buf_len, varbinds[i].value_type, &varbinds[i].value.integer);
      buf = snmp_ber_decode_string_len_buffer(buf, &buf_len, &varbinds[i].value.string.string, &varbinds[i].value.string.length);
      buf = snmp_ber_decode_null(buf, &buf_len);
      return NULL;
    }

    if(buf == NULL) {
      LOG_DBG("Could varbind type\n");
      return NULL;
  *varbind_num = i;

  return buf;
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
#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
 * @param out A pointer to the end of the buffer
 * @param out_len A pointer to the buffer length
 * @param varbinds_length The number of varbinds
unsigned char *
snmp_message_encode(unsigned char *out, uint32_t *out_len, snmp_header_t *header,
                    snmp_varbind_t *varbinds, uint32_t varbinds_length);
 * @param buf A pointer to the beginning of the buffer
 * @param buf_len A pointer to the buffer length
 * @param varbinds_length A pointer to the number of varbinds
uint8_t *
snmp_message_decode(uint8_t *buf, uint32_t buf_len, snmp_header_t *header,
                    snmp_varbind_t *varbinds, uint32_t *varbinds_length);
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
#include "snmp-oid.h"
snmp_mib_find(uint32_t *oid)
    if(!snmp_oid_cmp_oid(oid, resource->oid)) {
snmp_mib_find_next(uint32_t *oid)
    if(snmp_oid_cmp_oid(resource->oid, oid) > 0) {
    if(snmp_oid_cmp_oid(resource->oid, new_resource->oid) > 0) {
#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  */
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
typedef void (*snmp_mib_resource_handler_t)(snmp_varbind_t *varbind, uint32_t *oid);
   * @brief A array that represents the OID
   *
   * @remarks This array is "null" terminated. In this case the -1 is used.
  uint32_t *oid;
snmp_mib_find(uint32_t *oid);
snmp_mib_find_next(uint32_t *oid);
/*
 * 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  */
/*
 * 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_ */
/** @} */
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
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);
  }
}
    if(ev == tcpip_event) {
      if(uip_newdata()) {
        snmp_process_data();
      }
 * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
 * \defgroup snmp SNMP (Simple Network Management Protocol)
#include "contiki-net.h"
 * \defgroup SNMPDefine SNMP Defines
/** @} */

/**
 * \defgroup SNMPStructs SNMP Structs
 * @{
 */

   * @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;
   *
   * @remarks The length is configurable
  uint32_t oid[SNMP_MSG_OID_MAX_LEN];
  union snmp_varbind_val_u {
    struct snmp_varbind_string_s {
     * @brief A pointer to the beggining of a oid array
    uint32_t *oid;
/** @}*/

 * \defgroup SNMPFunctions SNMP Functions
 * @{
# 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
Fixed code:  * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
/*
 * In order to test SNMP compliance,
 * at least three OID's in the same package are necessary
 */
#define SNMP_CONF_MAX_NR_VALUES 3
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
sysDescr_handler(snmp_varbind_t *varbind, snmp_oid_t *oid);
sysDescr_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
sysObjectID_handler(snmp_varbind_t *varbind, snmp_oid_t *oid);
sysObjectID_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
  snmp_api_set_oid(varbind, oid, &sysObjectID_oid);
sysUpTime_handler(snmp_varbind_t *varbind, snmp_oid_t *oid);
sysUpTime_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
sysContact_handler(snmp_varbind_t *varbind, snmp_oid_t *oid);
sysContact_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
sysName_handler(snmp_varbind_t *varbind, snmp_oid_t *oid);
sysName_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
sysLocation_handler(snmp_varbind_t *varbind, snmp_oid_t *oid);
sysLocation_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
sysServices_handler(snmp_varbind_t *varbind, snmp_oid_t *oid);
sysServices_handler(snmp_varbind_t *varbind, snmp_oid_t *oid)
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the public API
snmp_api_set_string(snmp_varbind_t *varbind, snmp_oid_t *oid, char *string)
  memcpy(&varbind->oid, oid, sizeof(snmp_oid_t));
snmp_api_set_time_ticks(snmp_varbind_t *varbind, snmp_oid_t *oid, uint32_t integer)
  memcpy(&varbind->oid, oid, sizeof(snmp_oid_t));
  varbind->value_type = BER_DATA_TYPE_TIMETICKS;
snmp_api_set_oid(snmp_varbind_t *varbind, snmp_oid_t *oid, snmp_oid_t *ret_oid)
  memcpy(&varbind->oid, oid, sizeof(snmp_oid_t));
  varbind->value_type = BER_DATA_TYPE_OBJECT_IDENTIFIER;
  memcpy(&varbind->value.oid, ret_oid, sizeof(snmp_oid_t));
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the public API
 * \addtogroup SNMPAPI SNMP Public API
typedef void (*snmp_mib_resource_handler_t)(snmp_varbind_t *varbind, snmp_oid_t *oid);
  static snmp_oid_t name = { \
    .data = __VA_ARGS__, \
    .length = (sizeof((uint32_t[]){ __VA_ARGS__ }) / sizeof(uint32_t)) \
  };
  snmp_mib_resource_t name = { \
    NULL, \
    { \
      .data = __VA_ARGS__, \
      .length = (sizeof((uint32_t[]){ __VA_ARGS__ }) / sizeof(uint32_t)) \
    }, \
    handler \
  };
snmp_api_set_string(snmp_varbind_t *varbind, snmp_oid_t *oid, char *string);
snmp_api_set_time_ticks(snmp_varbind_t *varbind, snmp_oid_t *oid, uint32_t integer);
snmp_api_set_oid(snmp_varbind_t *varbind, snmp_oid_t *oid, snmp_oid_t *ret_oid);
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the BER encoding
static inline int
snmp_ber_encode_unsigned_integer(snmp_packet_t *snmp_packet, uint8_t type, uint32_t number)
  uint16_t original_out_len;
  original_out_len = snmp_packet->used;
    if(snmp_packet->used == snmp_packet->max) {
      return 0;
    }

    *snmp_packet->out-- = (uint8_t)number & 0xFF;
    snmp_packet->used++;
    /* I'm not sure why but on MSPGCC the >> 8 operation goes haywire here */
#ifdef __MSPGCC__
    number >>= 4;
    number >>= 4;
#else /* __MSPGCC__ */
#endif /* __MSPGCC__ */
  if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used - original_out_len)) {
    return 0;
  }

  if(!snmp_ber_encode_type(snmp_packet, type)) {
    return 0;
  }
  return 1;
int
snmp_ber_encode_type(snmp_packet_t *snmp_packet, uint8_t type)
  if(snmp_packet->used == snmp_packet->max) {
    return 0;
  }
  *snmp_packet->out-- = type;
  snmp_packet->used++;

  return 1;
}
/*---------------------------------------------------------------------------*/
int
snmp_ber_encode_length(snmp_packet_t *snmp_packet, uint16_t length)
{
  if(length > 0xFF) {
    if(snmp_packet->used == snmp_packet->max) {
      return 0;
    }

    *snmp_packet->out-- = (uint8_t)length & 0xFF;
    snmp_packet->used++;

    if(snmp_packet->used == snmp_packet->max) {
      return 0;
    }

    *snmp_packet->out-- = (uint8_t)(length >> 8) & 0xFF;
    snmp_packet->used++;

    if(snmp_packet->used == snmp_packet->max) {
      return 0;
    }

    *snmp_packet->out-- = 0x82;
    snmp_packet->used++;
  } else if(length > 0x7F) {
    if(snmp_packet->used == snmp_packet->max) {
      return 0;
    }

    *snmp_packet->out-- = (uint8_t)length & 0xFF;
    snmp_packet->used++;
    if(snmp_packet->used == snmp_packet->max) {
      return 0;
    }
    *snmp_packet->out-- = 0x81;
    snmp_packet->used++;
  } else {
    if(snmp_packet->used == snmp_packet->max) {
      return 0;
    }

    *snmp_packet->out-- = (uint8_t)length & 0x7F;
    snmp_packet->used++;
  }

  return 1;
}
/*---------------------------------------------------------------------------*/
int
snmp_ber_encode_timeticks(snmp_packet_t *snmp_packet, uint32_t timeticks)
{
  return snmp_ber_encode_unsigned_integer(snmp_packet, BER_DATA_TYPE_TIMETICKS, timeticks);
}
/*---------------------------------------------------------------------------*/
int
snmp_ber_encode_integer(snmp_packet_t *snmp_packet, uint32_t number)
{
  return snmp_ber_encode_unsigned_integer(snmp_packet, BER_DATA_TYPE_INTEGER, number);
int
snmp_ber_encode_string_len(snmp_packet_t *snmp_packet, const char *str, uint32_t length)
    if(snmp_packet->used == snmp_packet->max) {
      return 0;
    }

    *snmp_packet->out-- = (uint8_t)*str--;
    snmp_packet->used++;
  if(!snmp_ber_encode_length(snmp_packet, length)) {
    return 0;
  }
  if(!snmp_ber_encode_type(snmp_packet, BER_DATA_TYPE_OCTET_STRING)) {
    return 0;
  }
  return 1;
int
snmp_ber_encode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid)
  uint32_t val;
  uint16_t original_out_len;
  uint8_t pos;

  original_out_len = snmp_packet->used;

  pos = oid->length - 1;
  while(pos) {
    val = oid->data[pos];

    if(snmp_packet->used == snmp_packet->max) {
      return 0;
    }

    *snmp_packet->out-- = (uint8_t)(val & 0x7F);
    snmp_packet->used++;
    val >>= 7;

    while(val) {
      if(snmp_packet->used == snmp_packet->max) {
        return 0;
      }

      *snmp_packet->out-- = (uint8_t)((val & 0x7F) | 0x80);
      snmp_packet->used++;

      val >>= 7;
    }
    pos--;
  }

  if(snmp_packet->used == snmp_packet->max) {
    return 0;
  }

  val = *(snmp_packet->out + 1) + 40 * oid->data[pos];
  snmp_packet->used--;
  snmp_packet->out++;

  if(snmp_packet->used == snmp_packet->max) {
    return 0;
  }

  *snmp_packet->out-- = (uint8_t)(val & 0x7F);
  snmp_packet->used++;

  val >>= 7;

  while(val) {
    if(snmp_packet->used == snmp_packet->max) {
      return 0;
    }

    *snmp_packet->out-- = (uint8_t)((val & 0x7F) | 0x80);
    snmp_packet->used++;

    val >>= 7;
  }

  if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used - original_out_len)) {
    return 0;
  if(!snmp_ber_encode_type(snmp_packet, BER_DATA_TYPE_OBJECT_IDENTIFIER)) {
    return 0;
  }
  return 1;
int
snmp_ber_encode_null(snmp_packet_t *snmp_packet, uint8_t type)

  if(snmp_packet->used == snmp_packet->max) {
    return 0;
  *snmp_packet->out-- = 0x00;
  snmp_packet->used++;
  return snmp_ber_encode_type(snmp_packet, type);
static inline int
snmp_ber_decode_unsigned_integer(snmp_packet_t *snmp_packet, uint8_t expected_type, uint32_t *num)
  if(!snmp_ber_decode_type(snmp_packet, &type)) {
    return 0;
  }
  if(type != expected_type) {
    return 0;
  if(!snmp_ber_decode_length(snmp_packet, &len)) {
    return 0;
  }
  if(len > 4) {
    return 0;
  if(snmp_packet->used == 0) {
    return 0;
  *num = (uint32_t)(*snmp_packet->in++ & 0xFF);
  snmp_packet->used--;

    if(snmp_packet->used == 0) {
      return 0;
    }
    *num |= (uint8_t)(*snmp_packet->in++ & 0xFF);
    snmp_packet->used--;
  return 1;
int
snmp_ber_decode_type(snmp_packet_t *snmp_packet, uint8_t *type)
  if(snmp_packet->used == 0) {
    return 0;
  *type = *snmp_packet->in++;
  snmp_packet->used--;
  return 1;
}
/*---------------------------------------------------------------------------*/
int
snmp_ber_decode_length(snmp_packet_t *snmp_packet, uint8_t *length)
{
  if(snmp_packet->used == 0) {
    return 0;
  *length = *snmp_packet->in++;
  snmp_packet->used--;
  return 1;
}
/*---------------------------------------------------------------------------*/
int
snmp_ber_decode_timeticks(snmp_packet_t *snmp_packet, uint32_t *timeticks)
{
  return snmp_ber_decode_unsigned_integer(snmp_packet, BER_DATA_TYPE_TIMETICKS, timeticks);
int
snmp_ber_decode_integer(snmp_packet_t *snmp_packet, uint32_t *num)
{
  return snmp_ber_decode_unsigned_integer(snmp_packet, BER_DATA_TYPE_INTEGER, num);
}
/*---------------------------------------------------------------------------*/
int
snmp_ber_decode_string_len_buffer(snmp_packet_t *snmp_packet, const char **str, uint32_t *length)
  if(!snmp_ber_decode_type(snmp_packet, &type)) {
    return 0;
  }
  if(type != BER_DATA_TYPE_OCTET_STRING) {
    return 0;
  if((*snmp_packet->in & 0x80) == 0) {

    if(snmp_packet->used == 0) {
      return 0;
    }

    *length = (uint32_t)*snmp_packet->in++;
    snmp_packet->used--;
    if(snmp_packet->used == 0) {
      return 0;
    }

    length_bytes = (uint8_t)(*snmp_packet->in++ & 0x7F);
    snmp_packet->used--;

      return 0;
    }

    if(snmp_packet->used == 0) {
      return 0;
    *length = (uint32_t)*snmp_packet->in++;
    snmp_packet->used--;


      if(snmp_packet->used == 0) {
        return 0;
      }

      *length |= *snmp_packet->in++;
      snmp_packet->used--;
  *str = (const char *)snmp_packet->in;

  if(snmp_packet->used == 0 || snmp_packet->used - *length <= 0) {
    return 0;
  }

  snmp_packet->used -= *length;
  snmp_packet->in += *length;

  return 1;
}
/*---------------------------------------------------------------------------*/
int
snmp_ber_decode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid)
{
  uint8_t *buf_end, type;
  uint8_t len, j;
  div_t first;

  if(!snmp_ber_decode_type(snmp_packet, &type)) {
    return 0;
  }

  if(type != BER_DATA_TYPE_OBJECT_IDENTIFIER) {
    return 0;
  }

  if(!snmp_ber_decode_length(snmp_packet, &len)) {
    return 0;
  }

  buf_end = snmp_packet->in + len;

  if(snmp_packet->used == 0) {
    return 0;
  }

  snmp_packet->used--;
  first = div(*snmp_packet->in++, 40);

  oid->length = 0;

  oid->data[oid->length++] = (uint32_t)first.quot;
  oid->data[oid->length++] = (uint32_t)first.rem;

  while(snmp_packet->in != buf_end) {
    if(oid->length >= SNMP_MSG_OID_MAX_LEN) {
      return 0;
    }
    if(snmp_packet->used == 0) {
      return 0;
    }
    oid->data[oid->length] = (uint32_t)(*snmp_packet->in & 0x7F);
    for(j = 0; j < 4; j++) {
      snmp_packet->used--;
      if((*snmp_packet->in++ & 0x80) == 0) {
        break;
      }

      if(snmp_packet->used == 0) {
        return 0;
      }

      oid->data[oid->length] <<= 7;
      oid->data[oid->length] |= (*snmp_packet->in & 0x7F);
    }

    oid->length++;
  }

  return 1;
int
snmp_ber_decode_null(snmp_packet_t *snmp_packet)
  if(snmp_packet->used == 0) {
    return 0;
  }

  snmp_packet->in++;
  snmp_packet->used--;

  if(snmp_packet->used == 0) {
    return 0;
  }
  snmp_packet->in++;
  snmp_packet->used--;
  return 1;
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the BER encoding
/**
 * \addtogroup SNMPInternal SNMP Internal API
 * @{
 *
 * This group contains all the functions that can be used inside the OS level.
 */

/**
 * \addtogroup SNMPBER SNMP BER
 * @{
 *
 * This group contains the BER implementation
 */

/**
 * @brief End-of-Content
 *
 */
#define BER_DATA_TYPE_EOC                   0x00

/**
 * @brief Integer
 *
 */
#define BER_DATA_TYPE_INTEGER               0x02

/**
 * @brief Octet String
 *
 */
#define BER_DATA_TYPE_OCTET_STRING          0x04

/**
 * @brief Null
 *
 */
#define BER_DATA_TYPE_NULL                  0x05

/**
 * @brief Object Identifier
 *
 */
#define BER_DATA_TYPE_OBJECT_IDENTIFIER     0x06

/**
 * @brief Sequence
 *
 */
#define BER_DATA_TYPE_SEQUENCE              0x30

/**
 * @brief TimeTicks
 *
 */
#define BER_DATA_TYPE_TIMETICKS             0x43

/**
 * @brief No Such Instance
 *
 */
#define BER_DATA_TYPE_NO_SUCH_INSTANCE      0x81

/**
 * @brief End of MIB View
 *
 */
#define BER_DATA_TYPE_END_OF_MIB_VIEW       0x82

/**
 * @brief PDU Get Request
 *
 */
#define BER_DATA_TYPE_PDU_GET_REQUEST       0xA0

/**
 * @brief PDU Get Next Request
 *
 */
#define BER_DATA_TYPE_PDU_GET_NEXT_REQUEST  0xA1

/**
 * @brief PDU Get Reponse
 *
 */
#define BER_DATA_TYPE_PDU_GET_RESPONSE      0xA2

/**
 * @brief PDU Set Request
 *
 */
#define BER_DATA_TYPE_PDU_SET_REQUEST       0xA3

/**
 * @brief PDU Trap
 *
 */
#define BER_DATA_TYPE_PDU_TRAP              0xA4

/**
 * @brief PDU Get Bulk
 *
 */
#define BER_DATA_TYPE_PDU_GET_BULK          0xA5
 * @param snmp_packet A pointer to the snmp packet
 * @return 0 if error or 1 if success
int
snmp_ber_encode_type(snmp_packet_t *snmp_packet, uint8_t type);
 * @param snmp_packet A pointer to the snmp packet
 * @return 0 if error or 1 if success
int
snmp_ber_encode_length(snmp_packet_t *snmp_packet, uint16_t length);
 * @param snmp_packet A pointer to the snmp packet
 * @return 0 if error or 1 if success
int
snmp_ber_encode_integer(snmp_packet_t *snmp_packet, uint32_t integer);
 * @brief Encodes a timeticks
 * @param snmp_packet A pointer to the snmp packet
 * @param timeticks A TimeTicks
 * @return 0 if error or 1 if success
int
snmp_ber_encode_timeticks(snmp_packet_t *snmp_packet, uint32_t timeticks);
 * @param snmp_packet A pointer to the snmp packet
 * @return 0 if error or 1 if success
 */
int
snmp_ber_encode_string_len(snmp_packet_t *snmp_packet, const char *str, uint32_t length);

/**
 * @brief Encodes a Oid
 *
 * @param snmp_packet A pointer to the snmp packet
 * @param oid A OID
 *
 * @return 0 if error or 1 if success
int
snmp_ber_encode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid);
 * @param snmp_packet A pointer to the snmp packet
 * @return 0 if error or 1 if success
int
snmp_ber_encode_null(snmp_packet_t *snmp_packet, uint8_t type);
 * @param snmp_packet A pointer to the snmp packet
 * @return 0 if error or 1 if success
int
snmp_ber_decode_type(snmp_packet_t *snmp_packet, uint8_t *type);
 * @param snmp_packet A pointer to the snmp packet
 * @return 0 if error or 1 if success
int
snmp_ber_decode_length(snmp_packet_t *snmp_packet, uint8_t *length);
 * @param snmp_packet A pointer to the snmp packet
 * @return 0 if error or 1 if success
int
snmp_ber_decode_integer(snmp_packet_t *snmp_packet, uint32_t *integer);
 * @brief Decodes a timeticks
 * @param snmp_packet A pointer to the snmp packet
 * @param timeticks A pointer to the timeticks
 * @return 0 if error or 1 if success
int
snmp_ber_decode_timeticks(snmp_packet_t *snmp_packet, uint32_t *timeticks);
 * @param snmp_packet A pointer to the snmp packet
 * @return 0 if error or 1 if success
int
snmp_ber_decode_string_len_buffer(snmp_packet_t *snmp_packet, const char **str, uint32_t *length);
 * @param snmp_packet A pointer to the snmp packet
 * @return 0 if error or 1 if success
int
snmp_ber_decode_null(snmp_packet_t *snmp_packet);

/**
 * @brief Decodes an OID
 *
 * @param snmp_packet  pointer to the snmp packet
 * @param oid A pointer to the OID
 *
 * @return 0 if error or 1 if success
 */
int
snmp_ber_decode_oid(snmp_packet_t *snmp_packet, snmp_oid_t *oid);

/** @} */

/** @} */

 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the configurable macros
 * \addtogroup SNMPInternal SNMP Internal API
 *
 * This group contains all the functions that can be used inside the OS level.
 */

/**
 * \addtogroup SNMPConfs SNMP Configurable
 * @{
 *
 * This group contains all the defines that can be configurable following the Contiki standard
#if SNMP_CONF_MSG_OID_MAX_LEN > 128
#error "OID is limited to 128 in the standard"
#endif
#if SNMP_CONF_MAX_NR_VALUES > 255
#error "Number of OID's per packet is limited to 255 in this implementation"
#endif
#error "SNMP_CONF_MAX_PACKET_SIZE is obsolete. Use UIP_CONF_BUFFER_SIZE"
#endif /* SNMP_CONF_MAX_PACKET_SIZE */
/** @} */

/** @} */

 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the protocol engine
#include "snmp-ber.h"
static inline int
snmp_engine_get(snmp_header_t *header, snmp_varbind_t *varbinds)
  uint8_t i;
  i = 0;
  while(varbinds[i].value_type != BER_DATA_TYPE_EOC && i < SNMP_MAX_NR_VALUES) {
    resource = snmp_mib_find(&varbinds[i].oid);
        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index = i + 1;
        (&varbinds[i])->value_type = BER_DATA_TYPE_NO_SUCH_INSTANCE;
        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index = 0;
      resource->handler(&varbinds[i], &resource->oid);

    i++;
static inline int
snmp_engine_get_next(snmp_header_t *header, snmp_varbind_t *varbinds)
  uint8_t i;
  i = 0;
  while(varbinds[i].value_type != BER_DATA_TYPE_EOC && i < SNMP_MAX_NR_VALUES) {
    resource = snmp_mib_find_next(&varbinds[i].oid);
        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index = i + 1;
        (&varbinds[i])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index = 0;
      resource->handler(&varbinds[i], &resource->oid);

    i++;
static inline int
snmp_engine_get_bulk(snmp_header_t *header, snmp_varbind_t *varbinds)
  snmp_oid_t oids[SNMP_MAX_NR_VALUES];
  uint32_t j, original_varbinds_length;
  uint8_t i, varbinds_length;
  original_varbinds_length = 0;
  while(varbinds[original_varbinds_length].value_type != BER_DATA_TYPE_EOC && original_varbinds_length < SNMP_MAX_NR_VALUES) {
    memcpy(&oids[original_varbinds_length], &varbinds[original_varbinds_length].oid, sizeof(snmp_oid_t));
    original_varbinds_length++;
  varbinds_length = 0;
    if(i >= header->non_repeaters) {
    resource = snmp_mib_find_next(&oids[i]);
        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index = i + 1;
        (&varbinds[i])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
        header->error_index = 0;
      if(varbinds_length < SNMP_MAX_NR_VALUES) {
        resource->handler(&varbinds[varbinds_length], &resource->oid);
        (varbinds_length)++;
      } else {
        return -1;
  for(i = 0; i < header->max_repetitions; i++) {
    for(j = header->non_repeaters; j < original_varbinds_length; j++) {
      resource = snmp_mib_find_next(&oids[j]);
          header->error_status = SNMP_STATUS_NO_SUCH_NAME;
          header->error_index = varbinds_length + 1;
          if(varbinds_length < SNMP_MAX_NR_VALUES) {
            (&varbinds[varbinds_length])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
            memcpy(&varbinds[varbinds_length].oid, &oids[j], sizeof(snmp_oid_t));
            (varbinds_length)++;
          } else {
            return -1;
          header->error_status = SNMP_STATUS_NO_SUCH_NAME;
          header->error_index = 0;
        if(varbinds_length < SNMP_MAX_NR_VALUES) {
          resource->handler(&varbinds[varbinds_length], &resource->oid);
          (varbinds_length)++;
          memcpy(&oids[j], &resource->oid, sizeof(snmp_oid_t));
        } else {
          return -1;
int
snmp_engine(snmp_packet_t *snmp_packet)
  snmp_header_t header;
  snmp_varbind_t varbinds[SNMP_MAX_NR_VALUES];

  memset(&header, 0, sizeof(header));
  memset(varbinds, 0, sizeof(varbinds));
  if(!snmp_message_decode(snmp_packet, &header, varbinds)) {
    return 0;
      return 0;
  case BER_DATA_TYPE_PDU_GET_REQUEST:
    if(snmp_engine_get(&header, varbinds) == -1) {
      return 0;
  case BER_DATA_TYPE_PDU_GET_NEXT_REQUEST:
    if(snmp_engine_get_next(&header, varbinds) == -1) {
      return 0;
  case BER_DATA_TYPE_PDU_GET_BULK:
    if(snmp_engine_get_bulk(&header, varbinds) == -1) {
      return 0;
    return 0;
  header.pdu_type = BER_DATA_TYPE_PDU_GET_RESPONSE;
  return snmp_message_encode(snmp_packet, &header, varbinds);
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the protocol engine
/**
 * \addtogroup SNMPInternal SNMP Internal API
 * @{
 *
 * This group contains all the functions that can be used inside the OS level.
 */
 * \addtogroup SNMPEngine SNMP Engine
 * @{
 * This group contains the Engine implementation
 */

/**
 * @brief Process the SNMP packet and prepares the response
 * @param snmp_packet A pointer to the snmp packet
int
snmp_engine(snmp_packet_t *snmp_packet);

/** @} */

/** @} */
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the messages
int
snmp_message_encode(snmp_packet_t *snmp_packet, snmp_header_t *header, snmp_varbind_t *varbinds)
  uint32_t last_out_len;
  for(i = SNMP_MAX_NR_VALUES - 1; i >= 0; i--) {
    if(varbinds[i].value_type == BER_DATA_TYPE_EOC) {
      continue;
    }
    last_out_len = snmp_packet->used;
    switch(varbinds[i].value_type) {
      if(!snmp_ber_encode_integer(snmp_packet, varbinds[i].value.integer)) {
        LOG_DBG("Could not encode integer type\n");
        return 0;
      }
    case BER_DATA_TYPE_TIMETICKS:
      if(!snmp_ber_encode_timeticks(snmp_packet, varbinds[i].value.integer)) {
        LOG_DBG("Could not encode timeticks type\n");
        return 0;
      }
      if(!snmp_ber_encode_string_len(snmp_packet, varbinds[i].value.string.string, varbinds[i].value.string.length)) {
        LOG_DBG("Could not encode octet string type\n");
        return 0;
      }
    case BER_DATA_TYPE_OBJECT_IDENTIFIER:
      if(!snmp_ber_encode_oid(snmp_packet, &varbinds[i].value.oid)) {
        LOG_DBG("Could not encode oid type\n");
        return 0;
      }
    case BER_DATA_TYPE_NO_SUCH_INSTANCE:
    case BER_DATA_TYPE_END_OF_MIB_VIEW:
      if(!snmp_ber_encode_null(snmp_packet, varbinds[i].value_type)) {
        LOG_DBG("Could not encode null type\n");
        return 0;
      }
      LOG_DBG("Could not encode invlid type\n");
      return 0;
    }

    if(!snmp_ber_encode_oid(snmp_packet, &varbinds[i].oid)) {
      LOG_DBG("Could not encode oid\n");
      return 0;
    }

    if(!snmp_ber_encode_length(snmp_packet, (snmp_packet->used - last_out_len))) {
      LOG_DBG("Could not encode length\n");
      return 0;
    if(!snmp_ber_encode_type(snmp_packet, BER_DATA_TYPE_SEQUENCE)) {
      LOG_DBG("Could not encode type\n");
      return 0;
    }
  if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used)) {
    LOG_DBG("Could not encode length\n");
    return 0;
  }
  if(!snmp_ber_encode_type(snmp_packet, BER_DATA_TYPE_SEQUENCE)) {
    LOG_DBG("Could not encode type\n");
    return 0;
  }
  switch(header->pdu_type) {
  case BER_DATA_TYPE_PDU_GET_BULK:
    if(!snmp_ber_encode_integer(snmp_packet, header->max_repetitions)) {
      LOG_DBG("Could not encode max repetition\n");
      return 0;
    }

    if(!snmp_ber_encode_integer(snmp_packet, header->non_repeaters)) {
      LOG_DBG("Could not encode non repeaters\n");
      return 0;
    }
    break;
  default:
    if(!snmp_ber_encode_integer(snmp_packet, header->error_index)) {
      LOG_DBG("Could not encode error index\n");
      return 0;
    }

    if(!snmp_ber_encode_integer(snmp_packet, header->error_status)) {
      LOG_DBG("Could not encode error status\n");
      return 0;
    }
    break;
  if(!snmp_ber_encode_integer(snmp_packet, header->request_id)) {
    LOG_DBG("Could not encode request id\n");
    return 0;
  }
  if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used)) {
    LOG_DBG("Could not encode length\n");
    return 0;
  }
  if(!snmp_ber_encode_type(snmp_packet, header->pdu_type)) {
    LOG_DBG("Could not encode pdu type\n");
    return 0;
  }
  if(!snmp_ber_encode_string_len(snmp_packet, header->community.community, header->community.length)) {
    LOG_DBG("Could not encode community\n");
    return 0;
  }

  if(!snmp_ber_encode_integer(snmp_packet, header->version)) {
    LOG_DBG("Could not encode version\n");
    return 0;
  }

  if(!snmp_ber_encode_length(snmp_packet, snmp_packet->used)) {
    LOG_DBG("Could not encode length\n");
    return 0;
  }

  if(!snmp_ber_encode_type(snmp_packet, BER_DATA_TYPE_SEQUENCE)) {
    LOG_DBG("Could not encode type\n");
    return 0;
  }

  /* Move the pointer to the last position */
  snmp_packet->out++;
  return 1;
int
snmp_message_decode(snmp_packet_t *snmp_packet, snmp_header_t *header, snmp_varbind_t *varbinds)
  uint8_t type, len, i;
  if(!snmp_ber_decode_type(snmp_packet, &type)) {
    return 0;
    return 0;
  if(!snmp_ber_decode_length(snmp_packet, &len)) {
    return 0;
  if(!snmp_ber_decode_integer(snmp_packet, &header->version)) {
    return 0;
  switch(header->version) {
  case SNMP_VERSION_1:
  case SNMP_VERSION_2C:
    break;
  default:
    LOG_DBG("Invalid version\n");
    return 0;
  if(!snmp_ber_decode_string_len_buffer(snmp_packet, &header->community.community, &header->community.length)) {
    LOG_DBG("Could not decode community\n");
    return 0;
  if(!snmp_ber_decode_type(snmp_packet, &header->pdu_type)) {
    LOG_DBG("Could not decode pdu type\n");
    return 0;
  switch(header->pdu_type) {
  case BER_DATA_TYPE_PDU_GET_REQUEST:
  case BER_DATA_TYPE_PDU_GET_NEXT_REQUEST:
  case BER_DATA_TYPE_PDU_GET_RESPONSE:
  case BER_DATA_TYPE_PDU_SET_REQUEST:
  case BER_DATA_TYPE_PDU_GET_BULK:
    break;
  default:
    LOG_DBG("Invalid version\n");
    return 0;
  if(!snmp_ber_decode_length(snmp_packet, &len)) {
    return 0;
  if(!snmp_ber_decode_integer(snmp_packet, &header->request_id)) {
    return 0;
  switch(header->pdu_type) {
  case BER_DATA_TYPE_PDU_GET_BULK:
    if(!snmp_ber_decode_integer(snmp_packet, &header->non_repeaters)) {
      LOG_DBG("Could not decode non repeaters\n");
      return 0;
    if(!snmp_ber_decode_integer(snmp_packet, &header->max_repetitions)) {
      LOG_DBG("Could not decode max repetition\n");
      return 0;
    break;
  default:
    if(!snmp_ber_decode_integer(snmp_packet, &header->error_status)) {
      return 0;
    if(!snmp_ber_decode_integer(snmp_packet, &header->error_index)) {
      return 0;
    break;
  if(!snmp_ber_decode_type(snmp_packet, &type)) {
    return 0;
    return 0;
  if(!snmp_ber_decode_length(snmp_packet, &len)) {
    return 0;
  for(i = 0; snmp_packet->used > 0; ++i) {
    if(i >= SNMP_MAX_NR_VALUES) {
      LOG_DBG("OID's overflow\n");
      return 0;
    if(!snmp_ber_decode_type(snmp_packet, &type)) {
      return 0;
      return 0;
    if(!snmp_ber_decode_length(snmp_packet, &len)) {
      return 0;
    if(!snmp_ber_decode_oid(snmp_packet, &varbinds[i].oid)) {
      return 0;
    varbinds[i].value_type = *snmp_packet->in;
      if(!snmp_ber_decode_integer(snmp_packet, &varbinds[i].value.integer)) {
        LOG_DBG("Could not decode integer type\n");
        return 0;
      }
    case BER_DATA_TYPE_TIMETICKS:
      if(!snmp_ber_decode_timeticks(snmp_packet, &varbinds[i].value.integer)) {
        LOG_DBG("Could not decode timeticks type\n");
        return 0;
      }
      if(!snmp_ber_decode_string_len_buffer(snmp_packet, &varbinds[i].value.string.string, &varbinds[i].value.string.length)) {
        LOG_DBG("Could not decode octed string type\n");
        return 0;
      }
      if(!snmp_ber_decode_null(snmp_packet)) {
        LOG_DBG("Could not decode null type\n");
        return 0;
      }
      return 0;
  return 1;
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the messages
/**
 * \addtogroup SNMPInternal SNMP Internal API
 * @{
 *
 * This group contains all the functions that can be used inside the OS level.
 */
#include "snmp.h"
/**
 * \addtogroup SNMPMessage SNMP Message
 * @{
 *
 * This group contains the Message implementation
 */
 * @param snmp_packet A pointer to the snmp packet
int
snmp_message_encode(snmp_packet_t *snmp_packet, snmp_header_t *header, snmp_varbind_t *varbinds);
 * @param snmp_packet A pointer to the snmp packet
int
snmp_message_decode(snmp_packet_t *snmp_packet, snmp_header_t *header, snmp_varbind_t *varbinds);

/** @} */

/** @} */
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the MIB
/*---------------------------------------------------------------------------*/
/**
 * @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
 */
static inline int
snmp_mib_cmp_oid(snmp_oid_t *oid1, snmp_oid_t *oid2)
{
  uint8_t i;

  i = 0;
  while(i < oid1->length && i < oid2->length) {
    if(oid1->data[i] != oid2->data[i]) {
      if(oid1->data[i] < oid2->data[i]) {
        return -1;
      }
      return 1;
    }
    i++;
  }

  if(i == oid1->length &&
     i < oid2->length) {
    return -1;
  }

  if(i < oid1->length &&
     i == oid2->length) {
    return 1;
  }

  return 0;
}
/*---------------------------------------------------------------------------*/
snmp_mib_find(snmp_oid_t *oid)
    if(!snmp_mib_cmp_oid(oid, &resource->oid)) {
/*---------------------------------------------------------------------------*/
snmp_mib_find_next(snmp_oid_t *oid)
    if(snmp_mib_cmp_oid(&resource->oid, oid) > 0) {
/*---------------------------------------------------------------------------*/
  uint8_t i;
    if(snmp_mib_cmp_oid(&resource->oid, &new_resource->oid) > 0) {
  if(LOG_DBG_ENABLED) {
    /*
     * We print the entire resource table
     */
    LOG_DBG("Table after insert.\n");
    for(resource = list_head(snmp_mib);
        resource; resource = resource->next) {

      i = 0;
      LOG_DBG("{");
      while(i < resource->oid.length) {
        LOG_DBG_("%lu", (unsigned long)resource->oid.data[i]);
        i++;
        if(i < resource->oid.length) {
          LOG_DBG_(".");
        }
      }
      LOG_DBG_("}\n");
    }
/*---------------------------------------------------------------------------*/
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the MIB
/**
 * \addtogroup SNMPInternal SNMP Internal API
 * @{
 *
 * This group contains all the functions that can be used inside the OS level.
 */

/**
 * \addtogroup SNMPMIB SNMP MIB
 * @{
 *
 * This group contains the MIB implementation
 */

typedef void (*snmp_mib_resource_handler_t)(snmp_varbind_t *varbind, snmp_oid_t *oid);
   * @brief A OID struct
  snmp_oid_t oid;
snmp_mib_find(snmp_oid_t *oid);
snmp_mib_find_next(snmp_oid_t *oid);
/** @} */

/** @} */


 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the process
#include "contiki-net.h"
static struct uip_udp_conn *snmp_udp_conn;
  snmp_packet_t snmp_packet;

    if(ev != tcpip_event) {
      continue;
    }

    if(!uip_newdata()) {
      continue;

    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());

    /* Setup SNMP packet */
    snmp_packet.in = (uint8_t *)uip_appdata;
    snmp_packet.used = uip_datalen();

    snmp_packet.out = (uint8_t *)(uip_appdata + UIP_BUFSIZE - UIP_IPUDPH_LEN);
    snmp_packet.max = UIP_BUFSIZE - UIP_IPUDPH_LEN;

    /* Handle the request */
    if(!snmp_engine(&snmp_packet)) {
      LOG_DBG("Error while handling the request\n");
      continue;
    }

    LOG_DBG("Sending response\n");
    /* Send the response */
    uip_udp_packet_sendto(snmp_udp_conn, snmp_packet.out, snmp_packet.used, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport);
 * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
 *      SNMP Implementation of the process
 * \addtogroup snmp An implementation of SNMP
/**
 * \addtogroup SNMPInternal SNMP Internal API
 * @{
 *
 * This group contains all the functions that can be used inside the OS level.
 */

 * \addtogroup SNMPCore SNMP Core
 *
 * This group contains the SNMP MIB implementation
   * @brief The error status
  uint32_t error_status;
   * @brief The non repeaters
  uint32_t non_repeaters;
  /**
   * @brief The error index
   */
  uint32_t error_index;
  /**
   * @brief The max repetitions
   */
  uint32_t max_repetitions;
/**
 * @brief The OID struct
 */
typedef struct snmp_oid_s {
  /**
   * @brief The OID
   */
  uint32_t data[SNMP_MSG_OID_MAX_LEN];
  /**
   * @brief The OID length
   *
   */
  uint8_t length;
} snmp_oid_t;

  snmp_oid_t oid;
  union {
    struct {
     * @brief The OID value
    snmp_oid_t oid;
 * @brief The packet struct
 *
typedef struct {
  /**
   * @brief The number os bytes used
   *
   */
  uint16_t used;
  /**
   * @brief The maximum number of bytes
   *
   */
  uint16_t max;
  /**
   * @brief The pointer used for the incoming packet
   *
   */
  uint8_t *in;
  /**
   * @brief The pointer used for the outgoing packet
   *
   */
  uint8_t *out;
} snmp_packet_t;
/** @}*/



test_handler () {
  # Starting Contiki-NG 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

  $1 2>&1 | grep -z -E "$2" >> $BASENAME.log 2>&1 
  STATUS=$?
  
  sleep 2
  kill_bg $CPID > /dev/null 2>&1
  wait $CPID > /dev/null 2>&1

  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
}

# v1
## snmpget - pass
test_handler "snmpget -t2 -v1 -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.0" "iso\.3\.6\.1\.2\.1\.1\.1\.0"
## snmpwalk - pass
test_handler "snmpwalk -t2 -v1 -c public udp6:[$IPADDR]:161 1" "iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.2\.0.*iso\.3\.6\.1\.2\.1\.1\.3\.0.*iso\.3\.6\.1\.2\.1\.1\.4\.0.*iso\.3\.6\.1\.2\.1\.1\.5\.0.*iso\.3\.6\.1\.2\.1\.1\.6\.0.*iso\.3\.6\.1\.2\.1\.1\.7\.0.*End of MIB"

## snmpget - fail - noSuchName
test_handler "snmpget -t2 -v1 -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1" ".*noSuchName.*"
## snmpget - fail - timeout - 16 Ids in OID
test_handler "snmpget -t2 -v1 -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.1.3.6.1.2.1.1.1.1" "Timeout.*"
## snmpget - fail - timeout - 4 OIDs
test_handler "snmpget -t2 -v1 -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0" "Timeout.*"

# v2
## snmpget - pass
test_handler "snmpget -t2 -v2c -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.0" "iso\.3\.6\.1\.2\.1\.1\.1\.0"
## snmpwalk - pass
test_handler "snmpwalk -t2 -v2c -c public udp6:[$IPADDR]:161 1" "iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.2\.0.*iso\.3\.6\.1\.2\.1\.1\.3\.0.*iso\.3\.6\.1\.2\.1\.1\.4\.0.*iso\.3\.6\.1\.2\.1\.1\.5\.0.*iso\.3\.6\.1\.2\.1\.1\.6\.0.*iso\.3\.6\.1\.2\.1\.1\.7\.0.*iso\.3\.6\.1\.2\.1\.1\.7\.0"
## snmpbulkget two non-repeater - pass
test_handler "snmpbulkget -v2c -Cn2 -c public udp6:[$IPADDR]:161 1 1" "iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.1\.0"
## snmpbulkget two max-repetitions - pass
test_handler "snmpbulkget -t2 -v2c -Cr2 -c public udp6:[$IPADDR]:161 1" "iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.2\.0"
## snmpbulkget one non-repeater and two max-repetitions - pass
test_handler "snmpbulkget -t2 -v2c -Cn1 -Cr2 -c public udp6:[$IPADDR]:161 1 1" "iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.1\.0.*iso\.3\.6\.1\.2\.1\.1\.2\.0"

## snmpget - fail - noSuchName
test_handler "snmpget -t2 -v2c -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1" ".*No Such Instance currently.*"
## snmpget - fail - timeout - 16 Ids in OID
test_handler "snmpget -t2 -v2c -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.1.3.6.1.2.1.1.1.1" "Timeout.*"
## snmpget - fail - timeout - 4 OIDs
test_handler "snmpget -t2 -v2c -c public udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.1.0" "Timeout.*"

#v3
## snmpget - fail - timeout - v3 not implemented
test_handler "snmpget -t2 -v3 -l authPriv -u snmp-poller -a SHA -A \"PASSWORD1\" -x AES -X \"PASSWORD1\" udp6:[$IPADDR]:161 1.3.6.1.2.1.1.1.0" ".*Timeout.*"