SNMP Agent http://mbed.org/users/okini3939/notebook/agentbed-library/
Dependents: WeatherPlatform_20110408 WeatherPlatform WeatherStation
Diff: Agentbed.cpp
- Revision:
- 0:bb21da73024a
- Child:
- 2:9e4369522e03
--- /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;