CVE-2020-12141 (published 2021-10-19T16:15Z)

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.

Severity: MEDIUM
CVSS v2 base score: 6.4 (AV:N/AC:L/Au:N/C:P/I:N/A:P)
CVSS v3 base score: 9.1, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H)

Weakness information:
cwe_id: CWE-125
cwe_name: Out-of-bounds Read
description: The product reads data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/contiki-ng/contiki-ng
commit_details: repo_url: https://github.com/contiki-ng/contiki-ng
author: Yagoor
author_date: 2020-09-08 21:09:31+02:00
msg: Refactored SNMP engine after vulnerabilities
repository: repo_url: https://github.com/contiki-ng/contiki-ng
repo_name: contiki-ng/contiki-ng
description: Contiki-NG: The OS for Next Generation IoT Devices
repo_language: C
owner: contiki-ng
file_changes: filename: project-conf.h
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -30,4 +30,9 @@
  */
 /*---------------------------------------------------------------------------*/
 
+/*
+ * 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

programming_language: C
filename: snmp-SNMP-MIB-2-System.c
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -33,12 +33,12 @@
 
 /*---------------------------------------------------------------------------*/
 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);
 }
@@ -46,26 +46,26 @@ sysDescr_handler(snmp_varbind_t *varbind, uint32_t *oid)
 
 /*---------------------------------------------------------------------------*/
 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);
 }
@@ -73,12 +73,12 @@ sysUpTime_handler(snmp_varbind_t *varbind, uint32_t *oid)
 
 /*---------------------------------------------------------------------------*/
 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");
 }
@@ -86,12 +86,12 @@ sysContact_handler(snmp_varbind_t *varbind, uint32_t *oid)
 
 /*---------------------------------------------------------------------------*/
 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);
 }
@@ -99,12 +99,12 @@ sysName_handler(snmp_varbind_t *varbind, uint32_t *oid)
 
 /*---------------------------------------------------------------------------*/
 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, "");
 }
@@ -112,12 +112,12 @@ sysLocation_handler(snmp_varbind_t *varbind, uint32_t *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);
 }

programming_language: C
filename: snmp-server.c
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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

programming_language: C
filename: snmp-api.c
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \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
  */
@@ -43,47 +43,31 @@
 
 #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

programming_language: C
filename: snmp-api.h
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \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
  */
@@ -49,11 +49,10 @@
 #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
  */
 
 /**
@@ -62,7 +61,7 @@
  * @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
@@ -78,7 +77,10 @@ typedef struct snmp_mib_resource_s snmp_mib_resource_t;
  * @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
@@ -88,8 +90,14 @@ typedef struct snmp_mib_resource_s snmp_mib_resource_t;
  * @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
@@ -101,7 +109,7 @@ typedef struct snmp_mib_resource_s snmp_mib_resource_t;
  * @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
@@ -113,7 +121,7 @@ snmp_api_set_string(snmp_varbind_t *varbind, uint32_t *oid, char *string);
  * @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
@@ -125,7 +133,7 @@ snmp_api_set_time_ticks(snmp_varbind_t *varbind, uint32_t *oid, uint32_t integer
  * @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

programming_language: C
filename: snmp-ber.c
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \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
  */
@@ -46,245 +46,465 @@
 #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;
 }
 /*---------------------------------------------------------------------------*/

programming_language: C
filename: snmp-ber.h
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \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
  */
@@ -45,158 +45,269 @@
 #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_ */
+
 /** @} */

programming_language: C
filename: snmp-conf.h
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \file
- *      SNMP Configurable Macros
+ *      SNMP Implementation of the configurable macros
  * \author
  *      Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
  */
@@ -46,8 +46,17 @@
 #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
@@ -63,6 +72,9 @@
 #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
  */
@@ -75,6 +87,9 @@
 #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
  */
@@ -87,16 +102,8 @@
 #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
 /**
@@ -110,7 +117,10 @@
 #define SNMP_PORT 161
 #endif
 
-/*@}*/
+/** @} */
+
+/** @} */
 
 #endif /* SNMP_CONF_H_ */
+
 /** @} */

programming_language: C
filename: snmp-engine.c
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \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
  */
@@ -42,154 +42,168 @@
 #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;
         }
       }
     }
@@ -201,22 +215,23 @@ 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;
     }
   }
 
@@ -224,31 +239,30 @@ snmp_engine(unsigned char *buff, uint32_t buff_len, unsigned char *out, uint32_t
    * 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);
 }

programming_language: C
filename: snmp-engine.h
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \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
  */
@@ -45,20 +45,32 @@
 #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_ */
 

programming_language: C
filename: snmp-message.c
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \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
  */
@@ -41,243 +41,314 @@
 
 #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;
 }

programming_language: C++
filename: snmp-message.h
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \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
  */
@@ -45,47 +45,48 @@
 #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_ */
 

programming_language: C
filename: snmp-mib.c
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \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
  */
@@ -40,7 +40,6 @@
 #include "contiki.h"
 
 #include "snmp-mib.h"
-#include "snmp-oid.h"
 #include "lib/list.h"
 
 #define LOG_MODULE "SNMP [mib]"
@@ -48,8 +47,46 @@
 
 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;
 
@@ -57,15 +94,16 @@ snmp_mib_find(uint32_t *oid)
   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;
 
@@ -73,22 +111,24 @@ snmp_mib_find_next(uint32_t *oid)
   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;
     }
   }
@@ -98,18 +138,28 @@ snmp_mib_add(snmp_mib_resource_t *new_resource)
     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)
 {

programming_language: C
filename: snmp-mib.h
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \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
  */
@@ -45,15 +45,29 @@
 #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
@@ -66,11 +80,9 @@ typedef struct snmp_mib_resource_s {
    */
   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
    */
@@ -85,7 +97,7 @@ typedef struct snmp_mib_resource_s {
  * @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
@@ -95,7 +107,7 @@ snmp_mib_find(uint32_t *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
@@ -111,5 +123,10 @@ snmp_mib_add(snmp_mib_resource_t *resource);
 void
 snmp_mib_init(void);
 
+/** @} */
+
+/** @} */
+
 #endif /* SNMP_MIB_H_ */
+
 /** @} */

programming_language: C
filename: snmp-oid.c
change_type: ModificationType.DELETE
diff: @@ -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  */

programming_language: unknown
filename: snmp-oid.h
change_type: ModificationType.DELETE
diff: @@ -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_ */
-/** @} */

programming_language: unknown
filename: snmp.c
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,12 +32,13 @@
 
 /**
  * \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"
@@ -50,37 +51,7 @@
 #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()
@@ -95,6 +66,8 @@ 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);
@@ -103,11 +76,35 @@ PROCESS_THREAD(snmp_process, ev, data)
   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();

programming_language: C++
filename: snmp.h
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,7 +32,7 @@
 
 /**
  * \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
  */
@@ -41,7 +41,7 @@
  * \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
@@ -50,8 +50,14 @@
 #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"
 
@@ -61,8 +67,10 @@
 #include <stdint.h>
 
 /**
- * \defgroup SNMPDefine SNMP Defines
+ * \addtogroup SNMPCore SNMP Core
  * @{
+ *
+ * This group contains the SNMP MIB implementation
  */
 
 /**
@@ -79,13 +87,6 @@
  */
 #define SNMP_STATUS_NO_SUCH_NAME 2
 
-/** @} */
-
-/**
- * \defgroup SNMPStructs SNMP Structs
- * @{
- */
-
 /**
  * @brief The SNMP header struct
  */
@@ -120,47 +121,46 @@ typedef struct snmp_header_s {
    */
   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
    */
@@ -170,7 +170,7 @@ typedef struct snmp_varbind_s {
    *
    * @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
      */
@@ -178,7 +178,7 @@ typedef struct snmp_varbind_s {
     /**
      * @brief A struct that contains the string
      */
-    struct snmp_varbind_string_s {
+    struct {
       /**
        * @brief A pointer to the string value from this varbind
        *
@@ -193,18 +193,38 @@ typedef struct snmp_varbind_s {
       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
@@ -214,6 +234,10 @@ snmp_init();
 
 /** @}*/
 
+/** @}*/
+
 #endif /* SNMP_H_ */
+
 /** @} */
+
 /** @} */

programming_language: C
filename: 10-snmp-server.sh
change_type: ModificationType.MODIFY
diff: @@ -8,40 +8,74 @@ 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

programming_language: Batchfile