SNMP Agent http://mbed.org/users/okini3939/notebook/agentbed-library/
Dependents: WeatherPlatform_20110408 WeatherPlatform WeatherStation
Revision 0:bb21da73024a, committed 2010-12-28
- 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