SNMP Agent http://mbed.org/users/okini3939/notebook/agentbed-library/

Dependents:   WeatherPlatform_20110408 WeatherPlatform WeatherStation

Files at this revision

API Documentation at this revision

Comitter:
okini3939
Date:
Tue Dec 28 13:40:49 2010 +0000
Child:
1:b2db0ea96703
Commit message:

Changed in this revision

Agentbed.cpp Show annotated file Show diff for this revision Revisions of this file
Agentbed.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agentbed.cpp	Tue Dec 28 13:40:49 2010 +0000
@@ -0,0 +1,426 @@
+/*
+  Agentbed library
+  Modified for mbed, 2010 Suga.
+ 
+ 
+  Agentuino.cpp - An Arduino library for a lightweight SNMP Agent.
+  Copyright (C) 2010 Eric C. Gionet <lavco_eg@hotmail.com>
+  All rights reserved.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+//
+// sketch_aug23a
+//
+
+#include "Agentbed.h"
+
+SNMP_API_STAT_CODES AgentbedClass::begin(EthernetNetIf *eth)
+{
+    // set community names
+    _getCommName = "public";
+    _setCommName = "private";
+    //
+    // set community name set/get sizes
+    _setSize = strlen(_setCommName);
+    _getSize = strlen(_getCommName);
+    //
+    // init UDP socket
+    udpsock = new UDPSocket;
+    udpsock->setOnEvent(this, &AgentbedClass::listen);
+    udpsock->bind(Host(eth->getIp(), SNMP_DEFAULT_PORT));
+    //
+    return SNMP_API_STAT_SUCCESS;
+}
+
+SNMP_API_STAT_CODES AgentbedClass::begin(char *getCommName, char *setCommName, uint16_t port, EthernetNetIf *eth)
+{
+    // set community name set/get sizes
+    _setSize = strlen(setCommName);
+    _getSize = strlen(getCommName);
+    //
+    // validate get/set community name sizes
+    if ( _setSize > SNMP_MAX_NAME_LEN + 1 || _getSize > SNMP_MAX_NAME_LEN + 1 ) {
+        return SNMP_API_STAT_NAME_TOO_BIG;
+    }
+    //
+    // set community names
+    _getCommName = getCommName;
+    _setCommName = setCommName;
+    //
+    // validate session port number
+    if ( port == NULL || port == 0 ) port = SNMP_DEFAULT_PORT;
+    //
+    // init UDP socket
+    udpsock = new UDPSocket;
+    udpsock->setOnEvent(this, &AgentbedClass::listen);
+    udpsock->bind(Host(eth->getIp(), port));
+    //
+    return SNMP_API_STAT_SUCCESS;
+}
+
+void AgentbedClass::listen (UDPSocketEvent e)
+{
+    // if bytes available in receive buffer
+    // and pointer to a function (delegate function)
+    // isn't null, trigger the function
+    if (e == UDPSOCKET_READABLE && _callback != NULL ) {
+        (*_callback)();
+    }
+}
+
+
+SNMP_API_STAT_CODES AgentbedClass::requestPdu(SNMP_PDU *pdu)
+{
+    char *community;
+    // sequence length
+    byte seqLen;
+    // version
+    byte verLen, verEnd;
+    // community string
+    byte comLen, comEnd;
+    // pdu
+    byte pduTyp, pduLen;
+    byte ridLen, ridEnd;
+    byte errLen, errEnd;
+    byte eriLen, eriEnd;
+    byte vblTyp, vblLen;
+    byte vbiTyp, vbiLen;
+    byte obiLen, obiEnd;
+    byte valTyp, valLen, valEnd;
+    byte i;
+    Host dest;
+    //
+    // set packet packet size (skip UDP header)
+//    _packetSize = Udp.available()-8;
+    //
+    memset(_packet, 0, SNMP_MAX_PACKET_LEN);
+    //
+    // get UDP packet
+    _packetSize = udpsock->recvfrom((char*)_packet, SNMP_MAX_PACKET_LEN, &_dst);
+    //
+    // validate packet
+    if ( _packetSize != 0 && _packetSize > SNMP_MAX_PACKET_LEN ) {
+        //
+        //SNMP_FREE(_packet);
+
+        return SNMP_API_STAT_PACKET_TOO_BIG;
+    }
+    //
+    // allocate byte array based on packet size
+    //if ( (_packet = (byte *)malloc(sizeof(byte)*_packetSize)) == NULL ) {
+        //
+        //SNMP_FREE(_packet);
+
+    //    return SNMP_API_STAT_MALLOC_ERR;
+    //}
+    //
+    // packet check 1
+    if ( _packet[0] != 0x30 ) {
+        //
+        //SNMP_FREE(_packet);
+
+        return SNMP_API_STAT_PACKET_INVALID;
+    }
+    //
+    // sequence length
+    seqLen = _packet[1];
+    // version
+    verLen = _packet[3];
+    verEnd = 3 + verLen;
+    // community string
+    comLen = _packet[verEnd + 2];
+    comEnd = verEnd + 2 + comLen;
+    // pdu
+    pduTyp = _packet[comEnd + 1];
+    pduLen = _packet[comEnd + 2];
+    ridLen = _packet[comEnd + 4];
+    ridEnd = comEnd + 4 + ridLen;
+    errLen = _packet[ridEnd + 2];
+    errEnd = ridEnd + 2 + errLen;
+    eriLen = _packet[errEnd + 2];
+    eriEnd = errEnd + 2 + eriLen;
+    vblTyp = _packet[eriEnd + 1];
+    vblLen = _packet[eriEnd + 2];
+    vbiTyp = _packet[eriEnd + 3];
+    vbiLen = _packet[eriEnd + 4];
+    obiLen = _packet[eriEnd + 6];
+    obiEnd = eriEnd + obiLen + 6;
+    valTyp = _packet[obiEnd + 1];
+    valLen = _packet[obiEnd + 2];
+    valEnd = obiEnd + 2 + valLen;
+    //
+    // extract version
+    pdu->version = 0;
+    for ( i = 0; i < verLen; i++ ) {
+        pdu->version = (pdu->version << 8) | _packet[5 + i];
+    }
+    //
+    // pdu-type
+    pdu->type = (SNMP_PDU_TYPES)pduTyp;
+    _dstType = pdu->type;
+    //
+    // validate community size
+    if ( comLen > SNMP_MAX_NAME_LEN ) {
+        // set pdu error
+        pdu->error = SNMP_ERR_TOO_BIG;
+        //
+        //SNMP_FREE(_packet);
+
+        return SNMP_API_STAT_NAME_TOO_BIG;
+    }
+    //
+    // extract and compare community name
+    // allocate char array based on community size
+    if ( (community = (char *)malloc(sizeof(char)*comLen)) == NULL ) {
+        //
+        //SNMP_FREE(_packet);
+
+        return SNMP_API_STAT_MALLOC_ERR;
+    }
+    //
+    for ( i = 0; i < comLen; i++ ) {
+        community[i] = _packet[verEnd + 3 + i];
+    }
+    // terminate as a string
+    community[comLen] = '\0';
+    //
+    // validate community name
+    if ( pdu->type == SNMP_PDU_SET ) {
+        if ( strcmp(_setCommName, community) != 0 )
+            // set pdu error
+            pdu->error = SNMP_ERR_NO_SUCH_NAME;
+    } else {
+        if ( strcmp(_getCommName, community) != 0 )
+            // set pdu error
+            pdu->error = SNMP_ERR_NO_SUCH_NAME;
+    }
+    //
+    // free community buffer
+    SNMP_FREE(community);
+    //
+    // extract reqiest-id 0x00 0x00 0x00 0x01 (4-byte int aka int32)
+    pdu->requestId = 0;
+    for ( i = 0; i < ridLen; i++ ) {
+        pdu->requestId = (pdu->requestId << 8) | _packet[comEnd + 5 + i];
+    }
+    //
+    // extract error 
+    pdu->error = SNMP_ERR_NO_ERROR;
+    int32_t err = 0;
+    for ( i = 0; i < errLen; i++ ) {
+        err = (err << 8) | _packet[ridEnd + 3 + i];
+    }
+    pdu->error = (SNMP_ERR_CODES)err;
+    //
+    // extract error-index 
+    pdu->errorIndex = 0;
+    for ( i = 0; i < eriLen; i++ ) {
+        pdu->errorIndex = (pdu->errorIndex << 8) | _packet[errEnd + 3 + i];
+    }
+    //
+    //
+    // validate object-identifier size
+    if ( obiLen > SNMP_MAX_OID_LEN ) {
+        // set pdu error
+        pdu->error = SNMP_ERR_TOO_BIG;
+        //
+        //SNMP_FREE(_packet);
+
+        return SNMP_API_STAT_OID_TOO_BIG;
+    }
+    //
+    // extract and contruct object-identifier
+    /*
+    if ( (pdu->OID.oid = (byte *)malloc(sizeof(byte)*obiLen)) == NULL ) {
+        // free DPU receive buffer
+        _socket.readSkip(_socket.available());
+        //
+        SNMP_FREE(_packet);
+
+        return SNMP_API_STAT_MALLOC_ERR;
+    }
+    */
+    memset(pdu->OID.data, 0, SNMP_MAX_OID_LEN);
+    pdu->OID.size = obiLen;
+    for ( i = 0; i < obiLen; i++ ) {
+        pdu->OID.data[i] = _packet[eriEnd + 7 + i];
+    }
+    //
+    // value-type
+    pdu->VALUE.syntax = (SNMP_SYNTAXES)valTyp;
+    //
+    // validate value size
+    if ( obiLen > SNMP_MAX_VALUE_LEN ) {
+        // set pdu error
+        pdu->error = SNMP_ERR_TOO_BIG;
+        //
+        //SNMP_FREE(_packet);
+
+        return SNMP_API_STAT_VALUE_TOO_BIG;
+    }
+    //
+    // value-size
+    pdu->VALUE.size = valLen;
+    //
+    // extract value
+    // allocate char array based on oid size
+    /*
+    if( (pdu->VALUE.value = (byte *)malloc(sizeof(byte)*valLen)) == NULL ) {
+        // free DPU receive buffer
+        _socket.readSkip(_socket.available());
+        //
+        SNMP_FREE(_packet);
+
+        return SNMP_API_STAT_MALLOC_ERR;
+    }
+    */
+    memset(pdu->VALUE.data, 0, SNMP_MAX_VALUE_LEN);
+    for ( i = 0; i < valLen; i++ ) {
+        pdu->VALUE.data[i] = _packet[obiEnd + 3 + i];
+    }
+    //
+    //SNMP_FREE(_packet);
+    //
+    return SNMP_API_STAT_SUCCESS;
+}
+
+SNMP_API_STAT_CODES AgentbedClass::responsePdu(SNMP_PDU *pdu)
+{
+    int32_u u;
+    byte i;
+    //
+    // Length of entire SNMP packet
+    _packetPos = 0;  // 23
+    _packetSize = 25 - 1 + sizeof(pdu->requestId) + sizeof(pdu->error) + sizeof(pdu->errorIndex) + pdu->OID.size + pdu->VALUE.size;
+    //
+    memset(_packet, 0, SNMP_MAX_PACKET_LEN);
+    //
+    if ( _dstType == SNMP_PDU_SET ) {
+        _packetSize += _setSize;
+    } else {
+        _packetSize += _getSize;
+    }
+    //
+    // allocate byte array based on packet size
+    //if ( (_packet = (byte *)malloc(sizeof(byte)*_packetSize)) == NULL ) {
+        //
+        //SNMP_FREE(_packet);
+
+    //    return SNMP_API_STAT_MALLOC_ERR;
+    //}
+    //
+    _packet[_packetPos++] = (byte)SNMP_SYNTAX_SEQUENCE;    // type
+    _packet[_packetPos++] = (byte)_packetSize;        // length
+    //
+
+    // SNMP version
+    _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT;    // type
+    _packet[_packetPos++] = 0x01;            // length
+    _packet[_packetPos++] = 0x00;            // value
+    //
+    // SNMP community string
+    _packet[_packetPos++] = (byte)SNMP_SYNTAX_OCTETS;    // type
+    if ( _dstType == SNMP_PDU_SET ) {
+        _packet[_packetPos++] = (byte)_setSize;    // length
+        for ( i = 0; i < _setSize; i++ ) {
+            _packet[_packetPos++] = (byte)_setCommName[i];
+        }
+    } else {
+        _packet[_packetPos++] = (byte)_getSize;    // length
+        for ( i = 0; i < _getSize; i++ ) {
+            _packet[_packetPos++] = (byte)_getCommName[i];
+        }
+    }
+    //
+    // SNMP PDU
+    _packet[_packetPos++] = (byte)pdu->type;
+    _packet[_packetPos++] = (byte)( sizeof(pdu->requestId) + sizeof((int32_t)pdu->error) + sizeof(pdu->errorIndex) + pdu->OID.size + pdu->VALUE.size + 14 );
+    //
+    // Request ID (size always 4 e.g. 4-byte int)
+    _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT;    // type
+    _packet[_packetPos++] = (byte)sizeof(pdu->requestId);
+    u.int32 = pdu->requestId;
+    _packet[_packetPos++] = u.data[3];
+    _packet[_packetPos++] = u.data[2];
+    _packet[_packetPos++] = u.data[1];
+    _packet[_packetPos++] = u.data[0];
+    //
+    // Error (size always 4 e.g. 4-byte int)
+    _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT;    // type
+    _packet[_packetPos++] = (byte)sizeof((int32_t)pdu->error);
+    u.int32 = pdu->error;
+    _packet[_packetPos++] = u.data[3];
+    _packet[_packetPos++] = u.data[2];
+    _packet[_packetPos++] = u.data[1];
+    _packet[_packetPos++] = u.data[0];
+    //
+    // Error Index (size always 4 e.g. 4-byte int)
+    _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT;    // type
+    _packet[_packetPos++] = (byte)sizeof(pdu->errorIndex);
+    u.int32 = pdu->errorIndex;
+    _packet[_packetPos++] = u.data[3];
+    _packet[_packetPos++] = u.data[2];
+    _packet[_packetPos++] = u.data[1];
+    _packet[_packetPos++] = u.data[0];
+    //
+    // Varbind List
+    _packet[_packetPos++] = (byte)SNMP_SYNTAX_SEQUENCE;    // type
+    _packet[_packetPos++] = (byte)( pdu->OID.size + pdu->VALUE.size + 6 ); //4
+    //
+    // Varbind
+    _packet[_packetPos++] = (byte)SNMP_SYNTAX_SEQUENCE;    // type
+    _packet[_packetPos++] = (byte)( pdu->OID.size + pdu->VALUE.size + 4 ); //2
+    //
+    // ObjectIdentifier
+    _packet[_packetPos++] = (byte)SNMP_SYNTAX_OID;    // type
+    _packet[_packetPos++] = (byte)(pdu->OID.size);
+    for ( i = 0; i < pdu->OID.size; i++ ) {
+        _packet[_packetPos++] = pdu->OID.data[i];
+    }
+    //
+    // Value
+    _packet[_packetPos++] = (byte)pdu->VALUE.syntax;    // type
+    _packet[_packetPos++] = (byte)(pdu->VALUE.size);
+    for ( i = 0; i < pdu->VALUE.size; i++ ) {
+        _packet[_packetPos++] = pdu->VALUE.data[i];
+    }
+    //
+    udpsock->sendto((char*)_packet, _packetPos, &_dst);
+    //
+    //SNMP_FREE(_packet);
+    //
+    return SNMP_API_STAT_SUCCESS;
+}
+
+
+
+void AgentbedClass::onPduReceive(onPduReceiveCallback pduReceived)
+{
+    _callback = pduReceived;
+}
+
+void AgentbedClass::freePdu(SNMP_PDU *pdu)
+{
+    //SNMP_FREE(pdu->OID.oid);
+    //SNMP_FREE(pdu->VALUE.value);
+    memset(pdu->OID.data, 0, SNMP_MAX_OID_LEN);
+    memset(pdu->VALUE.data, 0, SNMP_MAX_VALUE_LEN);
+    //free((char *) pdu);
+}
+
+// Create one global object
+//AgentbedClass Agentbed;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agentbed.h	Tue Dec 28 13:40:49 2010 +0000
@@ -0,0 +1,551 @@
+/*
+  Agentbed library
+  Modified for mbed, 2010 Suga.
+ 
+ 
+  Agentuino.cpp - An Arduino library for a lightweight SNMP Agent.
+  Copyright (C) 2010 Eric C. Gionet <lavco_eg@hotmail.com>
+  All rights reserved.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef Agentbed_h
+#define Agentbed_h
+
+#define SNMP_DEFAULT_PORT    161
+#define SNMP_MIN_OID_LEN    2
+#define SNMP_MAX_OID_LEN    64 // 128
+#define SNMP_MAX_NAME_LEN    20
+#define SNMP_MAX_VALUE_LEN      64  // 128 ??? should limit this
+#define SNMP_MAX_PACKET_LEN     SNMP_MAX_VALUE_LEN + SNMP_MAX_OID_LEN + 25  //???
+#define SNMP_FREE(s)   do { if (s) { free((void *)s); s=NULL; } } while(0)
+//Frees a pointer only if it is !NULL and sets its value to NULL. 
+
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "UDPSocket.h"
+#include <stdlib.h>
+
+extern "C" {
+    // callback function
+    typedef void (*onPduReceiveCallback)(void);
+}
+
+//typedef long long int64_t;
+typedef unsigned long long uint64_t;
+//typedef long int32_t;
+//typedef unsigned long uint32_t;
+//typedef unsigned char uint8_t;
+//typedef short int16_t;
+//typedef unsigned short uint16_t;
+typedef unsigned char byte;
+
+typedef union uint64_u {
+    uint64_t uint64;
+    byte data[8];
+} uint64_u;
+
+typedef union int32_u {
+    int32_t int32;
+    byte data[4];
+} int32_u;
+
+typedef union uint32_u{
+    uint32_t uint32;
+    byte data[4];
+} uint32_u;
+
+typedef union int16_u {
+    int16_t int16;
+    byte data[2];
+} int16_u;
+
+//typedef union uint16_u {
+//    uint16_t uint16;
+//    byte data[2];
+//};
+
+enum ASN_BER_BASE_TYPES {
+    //   ASN/BER base types
+    ASN_BER_BASE_UNIVERSAL      = 0x0,
+    ASN_BER_BASE_APPLICATION = 0x40,
+    ASN_BER_BASE_CONTEXT      = 0x80,
+    ASN_BER_BASE_PUBLIC      = 0xC0,
+    ASN_BER_BASE_PRIMITIVE      = 0x0,
+    ASN_BER_BASE_CONSTRUCTOR = 0x20
+};
+
+enum SNMP_PDU_TYPES {
+    // PDU choices
+    SNMP_PDU_GET      = ASN_BER_BASE_CONTEXT | ASN_BER_BASE_CONSTRUCTOR | 0,
+    SNMP_PDU_GET_NEXT = ASN_BER_BASE_CONTEXT | ASN_BER_BASE_CONSTRUCTOR | 1,
+    SNMP_PDU_RESPONSE = ASN_BER_BASE_CONTEXT | ASN_BER_BASE_CONSTRUCTOR | 2,
+    SNMP_PDU_SET      = ASN_BER_BASE_CONTEXT | ASN_BER_BASE_CONSTRUCTOR | 3,
+    SNMP_PDU_TRAP      = ASN_BER_BASE_CONTEXT | ASN_BER_BASE_CONSTRUCTOR | 4
+};
+
+enum SNMP_TRAP_TYPES {
+    //   Trap generic types:
+    SNMP_TRAP_COLD_START           = 0,
+    SNMP_TRAP_WARM_START           = 1,
+    SNMP_TRAP_LINK_DOWN           = 2,
+    SNMP_TRAP_LINK_UP           = 3,
+    SNMP_TRAP_AUTHENTICATION_FAIL = 4,
+    SNMP_TRAP_EGP_NEIGHBORLOSS    = 5,
+    SNMP_TRAP_ENTERPRISE_SPECIFIC = 6
+};
+
+enum SNMP_ERR_CODES {
+    SNMP_ERR_NO_ERROR               = 0,
+    SNMP_ERR_TOO_BIG               = 1,
+    SNMP_ERR_NO_SUCH_NAME             = 2,
+    SNMP_ERR_BAD_VALUE               = 3,
+    SNMP_ERR_READ_ONLY               = 4,
+    SNMP_ERR_GEN_ERROR               = 5,
+
+    SNMP_ERR_NO_ACCESS              = 6,
+    SNMP_ERR_WRONG_TYPE               = 7,
+    SNMP_ERR_WRONG_LENGTH             = 8,
+    SNMP_ERR_WRONG_ENCODING            = 9,
+    SNMP_ERR_WRONG_VALUE            = 10,
+    SNMP_ERR_NO_CREATION            = 11,
+    SNMP_ERR_INCONSISTANT_VALUE         = 12,
+    SNMP_ERR_RESOURCE_UNAVAILABLE        = 13,
+    SNMP_ERR_COMMIT_FAILED            = 14,
+    SNMP_ERR_UNDO_FAILED            = 15,
+    SNMP_ERR_AUTHORIZATION_ERROR        = 16,
+    SNMP_ERR_NOT_WRITABLE            = 17,
+    SNMP_ERR_INCONSISTEN_NAME        = 18
+};
+
+enum SNMP_API_STAT_CODES {
+    SNMP_API_STAT_SUCCESS = 0,
+    SNMP_API_STAT_MALLOC_ERR = 1,
+    SNMP_API_STAT_NAME_TOO_BIG = 2,
+    SNMP_API_STAT_OID_TOO_BIG = 3,
+    SNMP_API_STAT_VALUE_TOO_BIG = 4,
+    SNMP_API_STAT_PACKET_INVALID = 5,
+    SNMP_API_STAT_PACKET_TOO_BIG = 6
+};
+
+//
+// http://oreilly.com/catalog/esnmp/chapter/ch02.html Table 2-1: SMIv1 Datatypes
+
+enum SNMP_SYNTAXES {
+    //   SNMP ObjectSyntax values
+    SNMP_SYNTAX_SEQUENCE            = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_CONSTRUCTOR | 0x10,
+    //   These values are used in the "syntax" member of VALUEs
+    SNMP_SYNTAX_BOOL            = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 1,
+    SNMP_SYNTAX_INT            = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 2,
+    SNMP_SYNTAX_BITS            = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 3,
+    SNMP_SYNTAX_OCTETS            = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 4,
+    SNMP_SYNTAX_NULL            = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 5,
+    SNMP_SYNTAX_OID               = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 6,
+    SNMP_SYNTAX_INT32            = SNMP_SYNTAX_INT,
+    SNMP_SYNTAX_IP_ADDRESS         = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 0,
+    SNMP_SYNTAX_COUNTER            = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 1,
+    SNMP_SYNTAX_GAUGE            = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 2,
+    SNMP_SYNTAX_TIME_TICKS         = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 3,
+    SNMP_SYNTAX_OPAQUE            = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 4,
+    SNMP_SYNTAX_NSAPADDR            = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 5,
+    SNMP_SYNTAX_COUNTER64            = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 6,
+    SNMP_SYNTAX_UINT32            = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 7,
+};
+
+typedef struct SNMP_OID {
+    byte data[SNMP_MAX_OID_LEN];  // ushort array insted??
+    size_t size;
+    //
+    void fromString(const char *buffer) {
+    }
+    //
+    void toString(char *buffer) {
+        buffer[0] = '1';
+        buffer[1] = '.';
+        buffer[2] = '3';
+        buffer[3] = '\0';
+        //
+        // tmp buffer - short (Int16)
+        //char *buff = (char *)malloc(sizeof(char)*16);  // I ya ya keeps hanging the MCU
+        char buff[16];
+        byte hsize = size - 1;
+        byte hpos = 1;
+        uint16_t subid;
+        //
+        while ( hsize > 0 ) {
+            subid = 0;
+            uint16_t b = 0;
+            do {
+                uint16_t next = data[hpos++];
+                b = next & 0xFF;
+                subid = (subid << 7) + (b & ~0x80);
+                hsize--;
+            } while ( (hsize > 0) && ((b & 0x80) != 0) );
+            //utoa(subid, buff, 10);
+            sprintf(buff, "%d", subid);
+            strcat(buffer, ".");
+            strcat(buffer, buff);
+        }
+        //
+        // free buff
+        //SNMP_FREE(buff);
+    };
+} SNMP_OID;
+
+// union for values?
+//
+typedef struct SNMP_VALUE {
+    byte data[SNMP_MAX_VALUE_LEN];
+    size_t size;
+    SNMP_SYNTAXES syntax;
+    //
+    byte i; // for encoding/decoding functions
+    //
+    // clear's buffer and sets size to 0
+    void clear(void) {
+        memset(data, 0, SNMP_MAX_VALUE_LEN);
+        size = 0;
+    }
+    //
+    //
+    // ASN.1 decoding functions
+    //
+    // decode's an octet string, object-identifier, opaque syntax to string
+    SNMP_ERR_CODES decode(char *value, size_t max_size) {
+        if ( syntax == SNMP_SYNTAX_OCTETS || syntax == SNMP_SYNTAX_OID
+            || syntax == SNMP_SYNTAX_OPAQUE ) {
+            if ( strlen(value) - 1 < max_size ) {
+                if ( syntax == SNMP_SYNTAX_OID ) {
+                    value[0] = '1';
+                    value[1] = '.';
+                    value[2] = '3';
+                    value[3] = '\0';
+                    //
+                    // tmp buffer - ushort (UInt16)
+                    //char *buff = (char *)malloc(sizeof(char)*16); // I ya ya..keep hanging the MCU
+                    char buff[16];
+                    byte hsize = size - 1;
+                    byte hpos = 1;
+                    uint16_t subid;
+                    //
+                    while ( hsize > 0 ) {
+                        subid = 0;
+                        uint16_t b = 0;
+                        do {
+                            uint16_t next = data[hpos++];
+                            b = next & 0xFF;
+                            subid = (subid << 7) + (b & ~0x80);
+                            hsize--;
+                        } while ( (hsize > 0) && ((b & 0x80) != 0) );
+                        //utoa(subid, buff, 10);
+                        sprintf(buff, "%d", subid);
+                        strcat(value, ".");
+                        strcat(value, buff);
+                    }
+                    //
+                    // free buff
+                    //SNMP_FREE(buff);
+                } else {
+                    for ( i = 0; i < size; i++ ) {
+                        value[i] = (char)data[i];
+                    }
+                    value[size] = '\0';
+                }
+                return SNMP_ERR_NO_ERROR;
+            } else {
+                clear();    
+                return SNMP_ERR_TOO_BIG;
+            }
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // decode's an int syntax to int16 ?? is this applicable
+    SNMP_ERR_CODES decode(int16_t *value) {
+        if ( syntax == SNMP_SYNTAX_INT ) {
+            int16_u tmp;
+            tmp.data[1] = data[0];
+            tmp.data[0] = data[1];
+            *value = tmp.int16;
+            return SNMP_ERR_NO_ERROR;
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // decode's an int32 syntax to int32
+    SNMP_ERR_CODES decode(int32_t *value) {
+        if ( syntax == SNMP_SYNTAX_INT32 ) {
+            int32_u tmp;
+            tmp.data[3] = data[0];
+            tmp.data[2] = data[1];
+            tmp.data[1] = data[2];
+            tmp.data[0] = data[3];
+            *value = tmp.int32;
+            return SNMP_ERR_NO_ERROR;
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // decode's an uint32, counter, time-ticks, gauge syntax to uint32
+    SNMP_ERR_CODES decode(uint32_t *value) {
+        if ( syntax == SNMP_SYNTAX_COUNTER || syntax == SNMP_SYNTAX_TIME_TICKS
+            || syntax == SNMP_SYNTAX_GAUGE || syntax == SNMP_SYNTAX_UINT32 ) {
+            uint32_u tmp;
+            tmp.data[3] = data[0];
+            tmp.data[2] = data[1];
+            tmp.data[1] = data[2];
+            tmp.data[0] = data[3];
+            *value = tmp.uint32;
+            return SNMP_ERR_NO_ERROR;
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // decode's an ip-address, NSAP-address syntax to an ip-address byte array 
+    SNMP_ERR_CODES decode(byte *value) {
+        memset(data, 0, SNMP_MAX_VALUE_LEN);
+        if ( syntax == SNMP_SYNTAX_IP_ADDRESS || syntax == SNMP_SYNTAX_NSAPADDR ) {
+            if ( sizeof(value) > 4 ) {
+                clear();
+                return SNMP_ERR_TOO_BIG;
+            } else {
+                size = 4;
+                data[0] = value[3];
+                data[1] = value[2];
+                data[2] = value[1];
+                data[3] = value[0];
+                return SNMP_ERR_NO_ERROR;
+            }
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // decode's a boolean syntax to boolean
+    SNMP_ERR_CODES decode(bool *value) {
+        if ( syntax == SNMP_SYNTAX_BOOL ) {
+            *value = (data[0] != 0);
+            return SNMP_ERR_NO_ERROR;
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    //
+    // ASN.1 encoding functions
+    //
+    // encode's a octet string to a string, opaque syntax
+    // encode object-identifier here??
+    SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const char *value) {
+        memset(data, 0, SNMP_MAX_VALUE_LEN);
+        if ( syn == SNMP_SYNTAX_OCTETS || syn == SNMP_SYNTAX_OPAQUE ) {
+            if ( strlen(value) - 1 < SNMP_MAX_VALUE_LEN ) {
+                syntax = syn;
+                size = strlen(value);
+                for ( i = 0; i < size; i++ ) {
+                    data[i] = (byte)value[i];
+                }
+                return SNMP_ERR_NO_ERROR;
+            } else {
+                clear();    
+                return SNMP_ERR_TOO_BIG;
+            }
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // encode's an int16 to int, opaque  syntax
+    SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const int16_t value) {
+        memset(data, 0, SNMP_MAX_VALUE_LEN);
+        if ( syn == SNMP_SYNTAX_INT || syn == SNMP_SYNTAX_OPAQUE ) {
+            int16_u tmp;
+            size = 2;
+            syntax = syn;
+            tmp.int16 = value;
+            data[0] = tmp.data[1];
+            data[1] = tmp.data[0];
+            return SNMP_ERR_NO_ERROR;
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // encode's an int32 to int32, opaque  syntax
+    SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const int32_t value) {
+        memset(data, 0, SNMP_MAX_VALUE_LEN);
+        if ( syn == SNMP_SYNTAX_INT32 || syn == SNMP_SYNTAX_OPAQUE ) {
+            int32_u tmp;
+            size = 4;
+            syntax = syn;
+            tmp.int32 = value;
+            data[0] = tmp.data[3];
+            data[1] = tmp.data[2];
+            data[2] = tmp.data[1];
+            data[3] = tmp.data[0];
+            return SNMP_ERR_NO_ERROR;
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // encode's an uint32 to uint32, counter, time-ticks, gauge, opaque  syntax
+    SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const uint32_t value) {
+        memset(data, 0, SNMP_MAX_VALUE_LEN);
+        if ( syn == SNMP_SYNTAX_COUNTER || syn == SNMP_SYNTAX_TIME_TICKS
+            || syn == SNMP_SYNTAX_GAUGE || syn == SNMP_SYNTAX_UINT32 
+            || syn == SNMP_SYNTAX_OPAQUE ) {
+            uint32_u tmp;
+            size = 4;
+            syntax = syn;
+            tmp.uint32 = value;
+            data[0] = tmp.data[3];
+            data[1] = tmp.data[2];
+            data[2] = tmp.data[1];
+            data[3] = tmp.data[0];
+            return SNMP_ERR_NO_ERROR;
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // encode's an ip-address byte array to ip-address, NSAP-address, opaque  syntax
+    SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const byte *value) {
+        memset(data, 0, SNMP_MAX_VALUE_LEN);
+        if ( syn == SNMP_SYNTAX_IP_ADDRESS || syn == SNMP_SYNTAX_NSAPADDR 
+            || syn == SNMP_SYNTAX_OPAQUE ) {
+            if ( sizeof(value) > 4 ) {
+                clear();
+                return SNMP_ERR_TOO_BIG;
+            } else {
+                size = 4;
+                syntax = syn;
+                data[0] = value[3];
+                data[1] = value[2];
+                data[2] = value[1];
+                data[3] = value[0];
+                return SNMP_ERR_NO_ERROR;
+            }
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // encode's a boolean to boolean, opaque  syntax
+    SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const bool value) {
+        memset(data, 0, SNMP_MAX_VALUE_LEN);
+        if ( syn == SNMP_SYNTAX_BOOL || syn == SNMP_SYNTAX_OPAQUE ) {
+            size = 1;
+            syntax = syn;
+            data[0] = value ? 0xff : 0;
+            return SNMP_ERR_NO_ERROR;
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // encode's an uint64 to counter64, opaque  syntax
+    SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const uint64_t value) {
+        memset(data, 0, SNMP_MAX_VALUE_LEN);
+        if ( syn == SNMP_SYNTAX_COUNTER64 || syn == SNMP_SYNTAX_OPAQUE ) {
+            uint64_u tmp;
+            size = 8;
+            syntax = syn;
+            tmp.uint64 = value;
+            data[0] = tmp.data[7];
+            data[1] = tmp.data[6];
+            data[2] = tmp.data[5];
+            data[3] = tmp.data[4];
+            data[4] = tmp.data[3];
+            data[5] = tmp.data[2];
+            data[6] = tmp.data[1];
+            data[7] = tmp.data[0];
+            return SNMP_ERR_NO_ERROR;
+        } else {
+            clear();
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+    //
+    // encode's a null to null, opaque  syntax
+    SNMP_ERR_CODES encode(SNMP_SYNTAXES syn) {
+        clear();
+        if ( syn == SNMP_SYNTAX_NULL || syn == SNMP_SYNTAX_OPAQUE ) {
+            size = 0;
+            syntax = syn;
+            return SNMP_ERR_NO_ERROR;
+        } else {
+            return SNMP_ERR_WRONG_TYPE;
+        }
+    }
+} SNMP_VALUE;
+
+typedef struct SNMP_PDU {
+    SNMP_PDU_TYPES type;
+    int32_t version;
+    int32_t requestId;
+    SNMP_ERR_CODES error;
+    int32_t errorIndex;
+    SNMP_OID OID;
+    SNMP_VALUE VALUE;
+} SNMP_PDU;
+
+class AgentbedClass {
+public:
+    // Agent functions
+    SNMP_API_STAT_CODES begin(EthernetNetIf *eth);
+    SNMP_API_STAT_CODES begin(char *getCommName, char *setCommName, uint16_t port, EthernetNetIf *eth);
+    void listen(UDPSocketEvent);
+    SNMP_API_STAT_CODES requestPdu(SNMP_PDU *pdu);
+    SNMP_API_STAT_CODES responsePdu(SNMP_PDU *pdu);
+    void onPduReceive(onPduReceiveCallback pduReceived);
+    void freePdu(SNMP_PDU *pdu);
+
+    // Helper functions
+
+private:
+    byte _packet[SNMP_MAX_PACKET_LEN];
+    uint16_t _packetSize;
+    uint16_t _packetPos;
+    SNMP_PDU_TYPES _dstType;
+    char *_getCommName;
+    size_t _getSize;
+    char *_setCommName;
+    size_t _setSize;
+    onPduReceiveCallback _callback;
+    UDPSocket *udpsock;
+    Host _dst;
+};
+
+//extern AgentbedClass Agentbed;
+
+#endif