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

Dependents:   WeatherPlatform_20110408 WeatherPlatform WeatherStation

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Agentbed.cpp Source File

Agentbed.cpp

00001 /*
00002   Agentbed library
00003   Modified for mbed, 2010 Suga.
00004  
00005  
00006   Agentuino.cpp - An Arduino library for a lightweight SNMP Agent.
00007   Copyright (C) 2010 Eric C. Gionet <lavco_eg@hotmail.com>
00008   All rights reserved.
00009 
00010   This library is free software; you can redistribute it and/or
00011   modify it under the terms of the GNU Lesser General Public
00012   License as published by the Free Software Foundation; either
00013   version 2.1 of the License, or (at your option) any later version.
00014 
00015   This library is distributed in the hope that it will be useful,
00016   but WITHOUT ANY WARRANTY; without even the implied warranty of
00017   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018   Lesser General Public License for more details.
00019 
00020   You should have received a copy of the GNU Lesser General Public
00021   License along with this library; if not, write to the Free Software
00022   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00023 */
00024 
00025 //
00026 // sketch_aug23a
00027 //
00028 
00029 #include "Agentbed.h"
00030 
00031 SNMP_API_STAT_CODES AgentbedClass::begin(EthernetNetIf *eth)
00032 {
00033     // set community names
00034     _getCommName = "public";
00035     _setCommName = "private";
00036     //
00037     // set community name set/get sizes
00038     _setSize = strlen(_setCommName);
00039     _getSize = strlen(_getCommName);
00040     //
00041     // init UDP socket
00042     udpsock = new UDPSocket;
00043     udpsock->setOnEvent(this, &AgentbedClass::listen);
00044     udpsock->bind(Host(eth->getIp(), SNMP_DEFAULT_PORT));
00045     //
00046     return SNMP_API_STAT_SUCCESS;
00047 }
00048 
00049 SNMP_API_STAT_CODES AgentbedClass::begin(char *getCommName, char *setCommName, uint16_t port, EthernetNetIf *eth)
00050 {
00051     // set community name set/get sizes
00052     _setSize = strlen(setCommName);
00053     _getSize = strlen(getCommName);
00054     //
00055     // validate get/set community name sizes
00056     if ( _setSize > SNMP_MAX_NAME_LEN + 1 || _getSize > SNMP_MAX_NAME_LEN + 1 ) {
00057         return SNMP_API_STAT_NAME_TOO_BIG;
00058     }
00059     //
00060     // set community names
00061     _getCommName = getCommName;
00062     _setCommName = setCommName;
00063     //
00064     // validate session port number
00065     if ( port == NULL || port == 0 ) port = SNMP_DEFAULT_PORT;
00066     //
00067     // init UDP socket
00068     udpsock = new UDPSocket;
00069     udpsock->setOnEvent(this, &AgentbedClass::listen);
00070     udpsock->bind(Host(eth->getIp(), port));
00071     //
00072     return SNMP_API_STAT_SUCCESS;
00073 }
00074 
00075 void AgentbedClass::listen (UDPSocketEvent e)
00076 {
00077     // if bytes available in receive buffer
00078     // and pointer to a function (delegate function)
00079     // isn't null, trigger the function
00080     if (e == UDPSOCKET_READABLE && _callback != NULL ) {
00081         (*_callback)();
00082     }
00083 }
00084 
00085 
00086 SNMP_API_STAT_CODES AgentbedClass::requestPdu(SNMP_PDU *pdu)
00087 {
00088     char *community;
00089     // sequence length
00090     byte __attribute__((__unused__)) seqLen;
00091     // version
00092     byte verLen, verEnd;
00093     // community string
00094     byte comLen, comEnd;
00095     // pdu
00096     byte __attribute__((__unused__)) pduTyp, pduLen;
00097     byte ridLen, ridEnd;
00098     byte errLen, errEnd;
00099     byte eriLen, eriEnd;
00100     byte __attribute__((__unused__)) vblTyp, vblLen;
00101     byte __attribute__((__unused__)) vbiTyp, vbiLen;
00102     byte obiLen, obiEnd;
00103     byte __attribute__((__unused__)) valTyp, valLen, valEnd;
00104     byte i;
00105     Host dest;
00106     //
00107     // set packet packet size (skip UDP header)
00108 //    _packetSize = Udp.available()-8;
00109     //
00110     memset(_packet, 0, SNMP_MAX_PACKET_LEN);
00111     //
00112     // get UDP packet
00113     _packetSize = udpsock->recvfrom((char*)_packet, SNMP_MAX_PACKET_LEN, &_dst);
00114     //
00115     // validate packet
00116     if ( _packetSize != 0 && _packetSize > SNMP_MAX_PACKET_LEN ) {
00117         //
00118         //SNMP_FREE(_packet);
00119 
00120         return SNMP_API_STAT_PACKET_TOO_BIG;
00121     }
00122     //
00123     // allocate byte array based on packet size
00124     //if ( (_packet = (byte *)malloc(sizeof(byte)*_packetSize)) == NULL ) {
00125         //
00126         //SNMP_FREE(_packet);
00127 
00128     //    return SNMP_API_STAT_MALLOC_ERR;
00129     //}
00130     //
00131     // packet check 1
00132     if ( _packet[0] != 0x30 ) {
00133         //
00134         //SNMP_FREE(_packet);
00135 
00136         return SNMP_API_STAT_PACKET_INVALID;
00137     }
00138     //
00139     // sequence length
00140     seqLen = _packet[1];
00141     // version
00142     verLen = _packet[3];
00143     verEnd = 3 + verLen;
00144     // community string
00145     comLen = _packet[verEnd + 2];
00146     comEnd = verEnd + 2 + comLen;
00147     // pdu
00148     pduTyp = _packet[comEnd + 1];
00149     pduLen = _packet[comEnd + 2];
00150     ridLen = _packet[comEnd + 4];
00151     ridEnd = comEnd + 4 + ridLen;
00152     errLen = _packet[ridEnd + 2];
00153     errEnd = ridEnd + 2 + errLen;
00154     eriLen = _packet[errEnd + 2];
00155     eriEnd = errEnd + 2 + eriLen;
00156     vblTyp = _packet[eriEnd + 1];
00157     vblLen = _packet[eriEnd + 2];
00158     vbiTyp = _packet[eriEnd + 3];
00159     vbiLen = _packet[eriEnd + 4];
00160     obiLen = _packet[eriEnd + 6];
00161     obiEnd = eriEnd + obiLen + 6;
00162     valTyp = _packet[obiEnd + 1];
00163     valLen = _packet[obiEnd + 2];
00164     valEnd = obiEnd + 2 + valLen;
00165     //
00166     // extract version
00167     pdu->version = 0;
00168     for ( i = 0; i < verLen; i++ ) {
00169         pdu->version = (pdu->version << 8) | _packet[5 + i];
00170     }
00171     //
00172     // pdu-type
00173     pdu->type = (SNMP_PDU_TYPES)pduTyp;
00174     _dstType = pdu->type;
00175     //
00176     // validate community size
00177     if ( comLen > SNMP_MAX_NAME_LEN ) {
00178         // set pdu error
00179         pdu->error = SNMP_ERR_TOO_BIG;
00180         //
00181         //SNMP_FREE(_packet);
00182 
00183         return SNMP_API_STAT_NAME_TOO_BIG;
00184     }
00185     //
00186     // extract and compare community name
00187     // allocate char array based on community size
00188     if ( (community = (char *)malloc(sizeof(char)*comLen)) == NULL ) {
00189         //
00190         //SNMP_FREE(_packet);
00191 
00192         return SNMP_API_STAT_MALLOC_ERR;
00193     }
00194     //
00195     for ( i = 0; i < comLen; i++ ) {
00196         community[i] = _packet[verEnd + 3 + i];
00197     }
00198     // terminate as a string
00199     community[comLen] = '\0';
00200     //
00201     // validate community name
00202     if ( pdu->type == SNMP_PDU_SET ) {
00203         if ( strcmp(_setCommName, community) != 0 )
00204             // set pdu error
00205             pdu->error = SNMP_ERR_NO_SUCH_NAME;
00206     } else {
00207         if ( strcmp(_getCommName, community) != 0 )
00208             // set pdu error
00209             pdu->error = SNMP_ERR_NO_SUCH_NAME;
00210     }
00211     //
00212     // free community buffer
00213     SNMP_FREE(community);
00214     //
00215     // extract reqiest-id 0x00 0x00 0x00 0x01 (4-byte int aka int32)
00216     pdu->requestId = 0;
00217     for ( i = 0; i < ridLen; i++ ) {
00218         pdu->requestId = (pdu->requestId << 8) | _packet[comEnd + 5 + i];
00219     }
00220     //
00221     // extract error 
00222     pdu->error = SNMP_ERR_NO_ERROR;
00223     int32_t err = 0;
00224     for ( i = 0; i < errLen; i++ ) {
00225         err = (err << 8) | _packet[ridEnd + 3 + i];
00226     }
00227     pdu->error = (SNMP_ERR_CODES)err;
00228     //
00229     // extract error-index 
00230     pdu->errorIndex = 0;
00231     for ( i = 0; i < eriLen; i++ ) {
00232         pdu->errorIndex = (pdu->errorIndex << 8) | _packet[errEnd + 3 + i];
00233     }
00234     //
00235     //
00236     // validate object-identifier size
00237     if ( obiLen > SNMP_MAX_OID_LEN ) {
00238         // set pdu error
00239         pdu->error = SNMP_ERR_TOO_BIG;
00240         //
00241         //SNMP_FREE(_packet);
00242 
00243         return SNMP_API_STAT_OID_TOO_BIG;
00244     }
00245     //
00246     // extract and contruct object-identifier
00247     /*
00248     if ( (pdu->OID.oid = (byte *)malloc(sizeof(byte)*obiLen)) == NULL ) {
00249         // free DPU receive buffer
00250         _socket.readSkip(_socket.available());
00251         //
00252         SNMP_FREE(_packet);
00253 
00254         return SNMP_API_STAT_MALLOC_ERR;
00255     }
00256     */
00257     memset(pdu->OID.data, 0, SNMP_MAX_OID_LEN);
00258     pdu->OID.size = obiLen;
00259     for ( i = 0; i < obiLen; i++ ) {
00260         pdu->OID.data[i] = _packet[eriEnd + 7 + i];
00261     }
00262     //
00263     // value-type
00264     pdu->VALUE.syntax = (SNMP_SYNTAXES)valTyp;
00265     //
00266     // validate value size
00267     if ( obiLen > SNMP_MAX_VALUE_LEN ) {
00268         // set pdu error
00269         pdu->error = SNMP_ERR_TOO_BIG;
00270         //
00271         //SNMP_FREE(_packet);
00272 
00273         return SNMP_API_STAT_VALUE_TOO_BIG;
00274     }
00275     //
00276     // value-size
00277     pdu->VALUE.size = valLen;
00278     //
00279     // extract value
00280     // allocate char array based on oid size
00281     /*
00282     if( (pdu->VALUE.value = (byte *)malloc(sizeof(byte)*valLen)) == NULL ) {
00283         // free DPU receive buffer
00284         _socket.readSkip(_socket.available());
00285         //
00286         SNMP_FREE(_packet);
00287 
00288         return SNMP_API_STAT_MALLOC_ERR;
00289     }
00290     */
00291     memset(pdu->VALUE.data, 0, SNMP_MAX_VALUE_LEN);
00292     for ( i = 0; i < valLen; i++ ) {
00293         pdu->VALUE.data[i] = _packet[obiEnd + 3 + i];
00294     }
00295     //
00296     //SNMP_FREE(_packet);
00297     //
00298     return SNMP_API_STAT_SUCCESS;
00299 }
00300 
00301 SNMP_API_STAT_CODES AgentbedClass::responsePdu(SNMP_PDU *pdu)
00302 {
00303     int32_u u;
00304     byte i;
00305     //
00306     // Length of entire SNMP packet
00307     _packetPos = 0;  // 23
00308     _packetSize = 25 - 1 + sizeof(pdu->requestId) + sizeof(pdu->error) + sizeof(pdu->errorIndex) + pdu->OID.size + pdu->VALUE.size;
00309     //
00310     memset(_packet, 0, SNMP_MAX_PACKET_LEN);
00311     //
00312     if ( _dstType == SNMP_PDU_SET ) {
00313         _packetSize += _setSize;
00314     } else {
00315         _packetSize += _getSize;
00316     }
00317     //
00318     // allocate byte array based on packet size
00319     //if ( (_packet = (byte *)malloc(sizeof(byte)*_packetSize)) == NULL ) {
00320         //
00321         //SNMP_FREE(_packet);
00322 
00323     //    return SNMP_API_STAT_MALLOC_ERR;
00324     //}
00325     //
00326     _packet[_packetPos++] = (byte)SNMP_SYNTAX_SEQUENCE;    // type
00327     _packet[_packetPos++] = (byte)_packetSize;        // length
00328     //
00329 
00330     // SNMP version
00331     _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT;    // type
00332     _packet[_packetPos++] = 0x01;            // length
00333     _packet[_packetPos++] = 0x00;            // value
00334     //
00335     // SNMP community string
00336     _packet[_packetPos++] = (byte)SNMP_SYNTAX_OCTETS;    // type
00337     if ( _dstType == SNMP_PDU_SET ) {
00338         _packet[_packetPos++] = (byte)_setSize;    // length
00339         for ( i = 0; i < _setSize; i++ ) {
00340             _packet[_packetPos++] = (byte)_setCommName[i];
00341         }
00342     } else {
00343         _packet[_packetPos++] = (byte)_getSize;    // length
00344         for ( i = 0; i < _getSize; i++ ) {
00345             _packet[_packetPos++] = (byte)_getCommName[i];
00346         }
00347     }
00348     //
00349     // SNMP PDU
00350     _packet[_packetPos++] = (byte)pdu->type;
00351     _packet[_packetPos++] = (byte)( sizeof(pdu->requestId) + sizeof((int32_t)pdu->error) + sizeof(pdu->errorIndex) + pdu->OID.size + pdu->VALUE.size + 14 );
00352     //
00353     // Request ID (size always 4 e.g. 4-byte int)
00354     _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT;    // type
00355     _packet[_packetPos++] = (byte)sizeof(pdu->requestId);
00356     u.int32 = pdu->requestId;
00357     _packet[_packetPos++] = u.data[3];
00358     _packet[_packetPos++] = u.data[2];
00359     _packet[_packetPos++] = u.data[1];
00360     _packet[_packetPos++] = u.data[0];
00361     //
00362     // Error (size always 4 e.g. 4-byte int)
00363     _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT;    // type
00364     _packet[_packetPos++] = (byte)sizeof((int32_t)pdu->error);
00365     u.int32 = pdu->error;
00366     _packet[_packetPos++] = u.data[3];
00367     _packet[_packetPos++] = u.data[2];
00368     _packet[_packetPos++] = u.data[1];
00369     _packet[_packetPos++] = u.data[0];
00370     //
00371     // Error Index (size always 4 e.g. 4-byte int)
00372     _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT;    // type
00373     _packet[_packetPos++] = (byte)sizeof(pdu->errorIndex);
00374     u.int32 = pdu->errorIndex;
00375     _packet[_packetPos++] = u.data[3];
00376     _packet[_packetPos++] = u.data[2];
00377     _packet[_packetPos++] = u.data[1];
00378     _packet[_packetPos++] = u.data[0];
00379     //
00380     // Varbind List
00381     _packet[_packetPos++] = (byte)SNMP_SYNTAX_SEQUENCE;    // type
00382     _packet[_packetPos++] = (byte)( pdu->OID.size + pdu->VALUE.size + 6 ); //4
00383     //
00384     // Varbind
00385     _packet[_packetPos++] = (byte)SNMP_SYNTAX_SEQUENCE;    // type
00386     _packet[_packetPos++] = (byte)( pdu->OID.size + pdu->VALUE.size + 4 ); //2
00387     //
00388     // ObjectIdentifier
00389     _packet[_packetPos++] = (byte)SNMP_SYNTAX_OID;    // type
00390     _packet[_packetPos++] = (byte)(pdu->OID.size);
00391     for ( i = 0; i < pdu->OID.size; i++ ) {
00392         _packet[_packetPos++] = pdu->OID.data[i];
00393     }
00394     //
00395     // Value
00396     _packet[_packetPos++] = (byte)pdu->VALUE.syntax;    // type
00397     _packet[_packetPos++] = (byte)(pdu->VALUE.size);
00398     for ( i = 0; i < pdu->VALUE.size; i++ ) {
00399         _packet[_packetPos++] = pdu->VALUE.data[i];
00400     }
00401     //
00402     udpsock->sendto((char*)_packet, _packetPos, &_dst);
00403     //
00404     //SNMP_FREE(_packet);
00405     //
00406     return SNMP_API_STAT_SUCCESS;
00407 }
00408 
00409 
00410 
00411 void AgentbedClass::onPduReceive(onPduReceiveCallback pduReceived)
00412 {
00413     _callback = pduReceived;
00414 }
00415 
00416 void AgentbedClass::freePdu(SNMP_PDU *pdu)
00417 {
00418     //SNMP_FREE(pdu->OID.oid);
00419     //SNMP_FREE(pdu->VALUE.value);
00420     memset(pdu->OID.data, 0, SNMP_MAX_OID_LEN);
00421     memset(pdu->VALUE.data, 0, SNMP_MAX_VALUE_LEN);
00422     //free((char *) pdu);
00423 }
00424 
00425 // Create one global object
00426 //AgentbedClass Agentbed;