├── Agentuino.cpp ├── Agentuino.h ├── README.txt └── examples └── AgentPlus └── AgentPlus.ino /Agentuino.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Agentuino.cpp - An Arduino library for a lightweight SNMP Agent. 3 | Copyright (C) 2010 Eric C. Gionet 4 | All rights reserved. 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | This library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | // 22 | // sketch_aug23a 23 | // 24 | 25 | #include "Agentuino.h" 26 | #include "EthernetUdp.h" 27 | 28 | EthernetUDP Udp; 29 | SNMP_API_STAT_CODES AgentuinoClass::begin() 30 | { 31 | // set community names 32 | _getCommName = "public"; 33 | _setCommName = "private"; 34 | // 35 | // set community name set/get sizes 36 | _setSize = strlen(_setCommName); 37 | _getSize = strlen(_getCommName); 38 | // 39 | // init UDP socket 40 | Udp.begin(SNMP_DEFAULT_PORT); 41 | // 42 | return SNMP_API_STAT_SUCCESS; 43 | } 44 | 45 | SNMP_API_STAT_CODES AgentuinoClass::begin(char *getCommName, char *setCommName, uint16_t port) 46 | { 47 | // set community name set/get sizes 48 | _setSize = strlen(setCommName); 49 | _getSize = strlen(getCommName); 50 | // 51 | // validate get/set community name sizes 52 | if ( _setSize > SNMP_MAX_NAME_LEN + 1 || _getSize > SNMP_MAX_NAME_LEN + 1 ) { 53 | return SNMP_API_STAT_NAME_TOO_BIG; 54 | } 55 | // 56 | // set community names 57 | _getCommName = getCommName; 58 | _setCommName = setCommName; 59 | // 60 | // validate session port number 61 | if ( port == NULL || port == 0 ) port = SNMP_DEFAULT_PORT; 62 | // 63 | // init UDP socket 64 | Udp.begin(port); 65 | 66 | return SNMP_API_STAT_SUCCESS; 67 | } 68 | 69 | void AgentuinoClass::listen(void) 70 | { 71 | // if bytes are available in receive buffer 72 | // and pointer to a function (delegate function) 73 | // isn't null, trigger the function 74 | Udp.parsePacket(); 75 | if ( Udp.available() && _callback != NULL ) (*_callback)(); 76 | } 77 | 78 | 79 | SNMP_API_STAT_CODES AgentuinoClass::requestPdu(SNMP_PDU *pdu) 80 | { 81 | char *community; 82 | // sequence length 83 | byte seqLen; 84 | // version 85 | byte verLen, verEnd; 86 | // community string 87 | byte comLen, comEnd; 88 | // pdu 89 | byte pduTyp, pduLen; 90 | byte ridLen, ridEnd; 91 | byte errLen, errEnd; 92 | byte eriLen, eriEnd; 93 | byte vblTyp, vblLen; 94 | byte vbiTyp, vbiLen; 95 | byte obiLen, obiEnd; 96 | byte valTyp, valLen, valEnd; 97 | byte i; 98 | // 99 | // set packet packet size (skip UDP header) 100 | _packetSize = Udp.available(); 101 | // 102 | // reset packet array 103 | memset(_packet, 0, SNMP_MAX_PACKET_LEN); 104 | // 105 | // validate packet 106 | if ( _packetSize != 0 && _packetSize > SNMP_MAX_PACKET_LEN ) { 107 | // 108 | //SNMP_FREE(_packet); 109 | 110 | return SNMP_API_STAT_PACKET_TOO_BIG; 111 | } 112 | // 113 | // get UDP packet 114 | //Udp.parsePacket(); 115 | Udp.read(_packet, _packetSize); 116 | // Udp.readPacket(_packet, _packetSize, _dstIp, &_dstPort); 117 | // 118 | // packet check 1 119 | if ( _packet[0] != 0x30 ) { 120 | // 121 | //SNMP_FREE(_packet); 122 | 123 | return SNMP_API_STAT_PACKET_INVALID; 124 | } 125 | // 126 | // sequence length 127 | seqLen = _packet[1]; 128 | // version 129 | verLen = _packet[3]; 130 | verEnd = 3 + verLen; 131 | // community string 132 | comLen = _packet[verEnd + 2]; 133 | comEnd = verEnd + 2 + comLen; 134 | // pdu 135 | pduTyp = _packet[comEnd + 1]; 136 | pduLen = _packet[comEnd + 2]; 137 | ridLen = _packet[comEnd + 4]; 138 | ridEnd = comEnd + 4 + ridLen; 139 | errLen = _packet[ridEnd + 2]; 140 | errEnd = ridEnd + 2 + errLen; 141 | eriLen = _packet[errEnd + 2]; 142 | eriEnd = errEnd + 2 + eriLen; 143 | vblTyp = _packet[eriEnd + 1]; 144 | vblLen = _packet[eriEnd + 2]; 145 | vbiTyp = _packet[eriEnd + 3]; 146 | vbiLen = _packet[eriEnd + 4]; 147 | obiLen = _packet[eriEnd + 6]; 148 | obiEnd = eriEnd + obiLen + 6; 149 | valTyp = _packet[obiEnd + 1]; 150 | valLen = _packet[obiEnd + 2]; 151 | valEnd = obiEnd + 2 + valLen; 152 | // 153 | // extract version 154 | pdu->version = 0; 155 | for ( i = 0; i < verLen; i++ ) { 156 | pdu->version = (pdu->version << 8) | _packet[5 + i]; 157 | } 158 | // 159 | // validate version 160 | // 161 | // pdu-type 162 | pdu->type = (SNMP_PDU_TYPES)pduTyp; 163 | _dstType = pdu->type; 164 | // 165 | // validate community size 166 | if ( comLen > SNMP_MAX_NAME_LEN ) { 167 | // set pdu error 168 | pdu->error = SNMP_ERR_TOO_BIG; 169 | // 170 | return SNMP_API_STAT_NAME_TOO_BIG; 171 | } 172 | // 173 | // 174 | // validate community name 175 | if ( pdu->type == SNMP_PDU_SET && comLen == _setSize ) { 176 | // 177 | for ( i = 0; i < _setSize; i++ ) { 178 | if( _packet[verEnd + 3 + i] != (byte)_setCommName[i] ) { 179 | // set pdu error 180 | pdu->error = SNMP_ERR_NO_SUCH_NAME; 181 | // 182 | return SNMP_API_STAT_NO_SUCH_NAME; 183 | } 184 | } 185 | } else if ( pdu->type == SNMP_PDU_GET && comLen == _getSize ) { 186 | // 187 | for ( i = 0; i < _getSize; i++ ) { 188 | if( _packet[verEnd + 3 + i] != (byte)_getCommName[i] ) { 189 | // set pdu error 190 | pdu->error = SNMP_ERR_NO_SUCH_NAME; 191 | // 192 | return SNMP_API_STAT_NO_SUCH_NAME; 193 | } 194 | } 195 | } else if ( pdu->type == SNMP_PDU_GET_NEXT && comLen == _getSize ) { 196 | // 197 | for ( i = 0; i < _getSize; i++ ) { 198 | if( _packet[verEnd + 3 + i] != (byte)_getCommName[i] ) { 199 | // set pdu error 200 | pdu->error = SNMP_ERR_NO_SUCH_NAME; 201 | // 202 | return SNMP_API_STAT_NO_SUCH_NAME; 203 | } 204 | } 205 | } else { 206 | // set pdu error 207 | pdu->error = SNMP_ERR_NO_SUCH_NAME; 208 | // 209 | return SNMP_API_STAT_NO_SUCH_NAME; 210 | } 211 | // 212 | // 213 | // extract reqiest-id 0x00 0x00 0x00 0x01 (4-byte int aka int32) 214 | pdu->requestId = 0; 215 | for ( i = 0; i < ridLen; i++ ) { 216 | pdu->requestId = (pdu->requestId << 8) | _packet[comEnd + 5 + i]; 217 | } 218 | // 219 | // extract error 220 | pdu->error = SNMP_ERR_NO_ERROR; 221 | int32_t err = 0; 222 | for ( i = 0; i < errLen; i++ ) { 223 | err = (err << 8) | _packet[ridEnd + 3 + i]; 224 | } 225 | pdu->error = (SNMP_ERR_CODES)err; 226 | // 227 | // extract error-index 228 | pdu->errorIndex = 0; 229 | for ( i = 0; i < eriLen; i++ ) { 230 | pdu->errorIndex = (pdu->errorIndex << 8) | _packet[errEnd + 3 + i]; 231 | } 232 | // 233 | // 234 | // validate object-identifier size 235 | if ( obiLen > SNMP_MAX_OID_LEN ) { 236 | // set pdu error 237 | pdu->error = SNMP_ERR_TOO_BIG; 238 | 239 | return SNMP_API_STAT_OID_TOO_BIG; 240 | } 241 | // 242 | // extract and contruct object-identifier 243 | memset(pdu->OID.data, 0, SNMP_MAX_OID_LEN); 244 | pdu->OID.size = obiLen; 245 | for ( i = 0; i < obiLen; i++ ) { 246 | pdu->OID.data[i] = _packet[eriEnd + 7 + i]; 247 | } 248 | // 249 | // value-type 250 | pdu->VALUE.syntax = (SNMP_SYNTAXES)valTyp; 251 | // 252 | // validate value size 253 | if ( obiLen > SNMP_MAX_VALUE_LEN ) { 254 | // set pdu error 255 | pdu->error = SNMP_ERR_TOO_BIG; 256 | 257 | return SNMP_API_STAT_VALUE_TOO_BIG; 258 | } 259 | // 260 | // value-size 261 | pdu->VALUE.size = valLen; 262 | // 263 | // extract value 264 | memset(pdu->VALUE.data, 0, SNMP_MAX_VALUE_LEN); 265 | for ( i = 0; i < valLen; i++ ) { 266 | pdu->VALUE.data[i] = _packet[obiEnd + 3 + i]; 267 | } 268 | // 269 | return SNMP_API_STAT_SUCCESS; 270 | } 271 | 272 | SNMP_API_STAT_CODES AgentuinoClass::responsePdu(SNMP_PDU *pdu) 273 | { 274 | int32_u u; 275 | byte i; 276 | // 277 | // Length of entire SNMP packet 278 | _packetPos = 0; // 23 279 | _packetSize = 25 + sizeof(pdu->requestId) + sizeof(pdu->error) + sizeof(pdu->errorIndex) + pdu->OID.size + pdu->VALUE.size; 280 | // 281 | memset(_packet, 0, SNMP_MAX_PACKET_LEN); 282 | // 283 | if ( _dstType == SNMP_PDU_SET ) { 284 | _packetSize += _setSize; 285 | } else { 286 | _packetSize += _getSize; 287 | } 288 | // 289 | _packet[_packetPos++] = (byte)SNMP_SYNTAX_SEQUENCE; // type 290 | _packet[_packetPos++] = (byte)_packetSize - 2; // length 291 | // 292 | // SNMP version 293 | _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT; // type 294 | _packet[_packetPos++] = 0x01; // length 295 | _packet[_packetPos++] = 0x00; // value 296 | // 297 | // SNMP community string 298 | _packet[_packetPos++] = (byte)SNMP_SYNTAX_OCTETS; // type 299 | if ( _dstType == SNMP_PDU_SET ) { 300 | _packet[_packetPos++] = (byte)_setSize; // length 301 | for ( i = 0; i < _setSize; i++ ) { 302 | _packet[_packetPos++] = (byte)_setCommName[i]; 303 | } 304 | } else { 305 | _packet[_packetPos++] = (byte)_getSize; // length 306 | for ( i = 0; i < _getSize; i++ ) { 307 | _packet[_packetPos++] = (byte)_getCommName[i]; 308 | } 309 | } 310 | // 311 | // SNMP PDU 312 | _packet[_packetPos++] = (byte)pdu->type; 313 | _packet[_packetPos++] = (byte)( sizeof(pdu->requestId) + sizeof((int32_t)pdu->error) + sizeof(pdu->errorIndex) + pdu->OID.size + pdu->VALUE.size + 14 ); 314 | // 315 | // Request ID (size always 4 e.g. 4-byte int) 316 | _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT; // type 317 | _packet[_packetPos++] = (byte)sizeof(pdu->requestId); 318 | u.int32 = pdu->requestId; 319 | _packet[_packetPos++] = u.data[3]; 320 | _packet[_packetPos++] = u.data[2]; 321 | _packet[_packetPos++] = u.data[1]; 322 | _packet[_packetPos++] = u.data[0]; 323 | // 324 | // Error (size always 4 e.g. 4-byte int) 325 | _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT; // type 326 | _packet[_packetPos++] = (byte)sizeof((int32_t)pdu->error); 327 | u.int32 = pdu->error; 328 | _packet[_packetPos++] = u.data[3]; 329 | _packet[_packetPos++] = u.data[2]; 330 | _packet[_packetPos++] = u.data[1]; 331 | _packet[_packetPos++] = u.data[0]; 332 | // 333 | // Error Index (size always 4 e.g. 4-byte int) 334 | _packet[_packetPos++] = (byte)SNMP_SYNTAX_INT; // type 335 | _packet[_packetPos++] = (byte)sizeof(pdu->errorIndex); 336 | u.int32 = pdu->errorIndex; 337 | _packet[_packetPos++] = u.data[3]; 338 | _packet[_packetPos++] = u.data[2]; 339 | _packet[_packetPos++] = u.data[1]; 340 | _packet[_packetPos++] = u.data[0]; 341 | // 342 | // Varbind List 343 | _packet[_packetPos++] = (byte)SNMP_SYNTAX_SEQUENCE; // type 344 | _packet[_packetPos++] = (byte)( pdu->OID.size + pdu->VALUE.size + 6 ); //4 345 | // 346 | // Varbind 347 | _packet[_packetPos++] = (byte)SNMP_SYNTAX_SEQUENCE; // type 348 | _packet[_packetPos++] = (byte)( pdu->OID.size + pdu->VALUE.size + 4 ); //2 349 | // 350 | // ObjectIdentifier 351 | _packet[_packetPos++] = (byte)SNMP_SYNTAX_OID; // type 352 | _packet[_packetPos++] = (byte)(pdu->OID.size); 353 | for ( i = 0; i < pdu->OID.size; i++ ) { 354 | _packet[_packetPos++] = pdu->OID.data[i]; 355 | } 356 | // 357 | // Value 358 | _packet[_packetPos++] = (byte)pdu->VALUE.syntax; // type 359 | _packet[_packetPos++] = (byte)(pdu->VALUE.size); 360 | for ( i = 0; i < pdu->VALUE.size; i++ ) { 361 | _packet[_packetPos++] = pdu->VALUE.data[i]; 362 | } 363 | // 364 | Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); 365 | Udp.write(_packet, _packetSize); 366 | Udp.endPacket(); 367 | // Udp.write(_packet, _packetSize, _dstIp, _dstPort); 368 | // 369 | return SNMP_API_STAT_SUCCESS; 370 | } 371 | 372 | 373 | 374 | void AgentuinoClass::onPduReceive(onPduReceiveCallback pduReceived) 375 | { 376 | _callback = pduReceived; 377 | } 378 | 379 | void AgentuinoClass::freePdu(SNMP_PDU *pdu) 380 | { 381 | // 382 | memset(pdu->OID.data, 0, SNMP_MAX_OID_LEN); 383 | memset(pdu->VALUE.data, 0, SNMP_MAX_VALUE_LEN); 384 | free((char *) pdu); 385 | } 386 | 387 | // Create one global object 388 | AgentuinoClass Agentuino; -------------------------------------------------------------------------------- /Agentuino.h: -------------------------------------------------------------------------------- 1 | /* 2 | Agentuino.cpp - An Arduino library for a lightweight SNMP Agent. 3 | Copyright (C) 2010 Eric C. Gionet 4 | All rights reserved. 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | This library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | // Update fromString by Petr Domorazek 22 | 23 | #ifndef Agentuino_h 24 | #define Agentuino_h 25 | 26 | #define SNMP_DEFAULT_PORT 161 27 | #define SNMP_MIN_OID_LEN 2 28 | #define SNMP_MAX_OID_LEN 64 // 128 29 | #define SNMP_MAX_NAME_LEN 20 30 | #define SNMP_MAX_VALUE_LEN 64 // 128 ??? should limit this 31 | #define SNMP_MAX_PACKET_LEN SNMP_MAX_VALUE_LEN + SNMP_MAX_OID_LEN + 25 //??? 32 | #define SNMP_FREE(s) do { if (s) { free((void *)s); s=NULL; } } while(0) 33 | //Frees a pointer only if it is !NULL and sets its value to NULL. 34 | 35 | #include "Arduino.h" 36 | #include "Udp.h" 37 | 38 | extern "C" { 39 | // callback function 40 | typedef void (*onPduReceiveCallback)(void); 41 | } 42 | 43 | //typedef long long int64_t; 44 | typedef unsigned long long uint64_t; 45 | //typedef long int32_t; 46 | //typedef unsigned long uint32_t; 47 | //typedef unsigned char uint8_t; 48 | //typedef short int16_t; 49 | //typedef unsigned short uint16_t; 50 | 51 | 52 | typedef union uint64_u { 53 | uint64_t uint64; 54 | byte data[8]; 55 | }; 56 | 57 | typedef union int32_u { 58 | int32_t int32; 59 | byte data[4]; 60 | }; 61 | 62 | typedef union uint32_u { 63 | uint32_t uint32; 64 | byte data[4]; 65 | }; 66 | 67 | typedef union int16_u { 68 | int16_t int16; 69 | byte data[2]; 70 | }; 71 | 72 | //typedef union uint16_u { 73 | // uint16_t uint16; 74 | // byte data[2]; 75 | //}; 76 | 77 | typedef enum ASN_BER_BASE_TYPES { 78 | // ASN/BER base types 79 | ASN_BER_BASE_UNIVERSAL = 0x0, 80 | ASN_BER_BASE_APPLICATION = 0x40, 81 | ASN_BER_BASE_CONTEXT = 0x80, 82 | ASN_BER_BASE_PUBLIC = 0xC0, 83 | ASN_BER_BASE_PRIMITIVE = 0x0, 84 | ASN_BER_BASE_CONSTRUCTOR = 0x20 85 | }; 86 | 87 | typedef enum SNMP_PDU_TYPES { 88 | // PDU choices 89 | SNMP_PDU_GET = ASN_BER_BASE_CONTEXT | ASN_BER_BASE_CONSTRUCTOR | 0, 90 | SNMP_PDU_GET_NEXT = ASN_BER_BASE_CONTEXT | ASN_BER_BASE_CONSTRUCTOR | 1, 91 | SNMP_PDU_RESPONSE = ASN_BER_BASE_CONTEXT | ASN_BER_BASE_CONSTRUCTOR | 2, 92 | SNMP_PDU_SET = ASN_BER_BASE_CONTEXT | ASN_BER_BASE_CONSTRUCTOR | 3, 93 | SNMP_PDU_TRAP = ASN_BER_BASE_CONTEXT | ASN_BER_BASE_CONSTRUCTOR | 4 94 | }; 95 | 96 | typedef enum SNMP_TRAP_TYPES { 97 | // Trap generic types: 98 | SNMP_TRAP_COLD_START = 0, 99 | SNMP_TRAP_WARM_START = 1, 100 | SNMP_TRAP_LINK_DOWN = 2, 101 | SNMP_TRAP_LINK_UP = 3, 102 | SNMP_TRAP_AUTHENTICATION_FAIL = 4, 103 | SNMP_TRAP_EGP_NEIGHBORLOSS = 5, 104 | SNMP_TRAP_ENTERPRISE_SPECIFIC = 6 105 | }; 106 | 107 | typedef enum SNMP_ERR_CODES { 108 | SNMP_ERR_NO_ERROR = 0, 109 | SNMP_ERR_TOO_BIG = 1, 110 | SNMP_ERR_NO_SUCH_NAME = 2, 111 | SNMP_ERR_BAD_VALUE = 3, 112 | SNMP_ERR_READ_ONLY = 4, 113 | SNMP_ERR_GEN_ERROR = 5, 114 | 115 | SNMP_ERR_NO_ACCESS = 6, 116 | SNMP_ERR_WRONG_TYPE = 7, 117 | SNMP_ERR_WRONG_LENGTH = 8, 118 | SNMP_ERR_WRONG_ENCODING = 9, 119 | SNMP_ERR_WRONG_VALUE = 10, 120 | SNMP_ERR_NO_CREATION = 11, 121 | SNMP_ERR_INCONSISTANT_VALUE = 12, 122 | SNMP_ERR_RESOURCE_UNAVAILABLE = 13, 123 | SNMP_ERR_COMMIT_FAILED = 14, 124 | SNMP_ERR_UNDO_FAILED = 15, 125 | SNMP_ERR_AUTHORIZATION_ERROR = 16, 126 | SNMP_ERR_NOT_WRITABLE = 17, 127 | SNMP_ERR_INCONSISTEN_NAME = 18 128 | }; 129 | 130 | typedef enum SNMP_API_STAT_CODES { 131 | SNMP_API_STAT_SUCCESS = 0, 132 | SNMP_API_STAT_MALLOC_ERR = 1, 133 | SNMP_API_STAT_NAME_TOO_BIG = 2, 134 | SNMP_API_STAT_OID_TOO_BIG = 3, 135 | SNMP_API_STAT_VALUE_TOO_BIG = 4, 136 | SNMP_API_STAT_PACKET_INVALID = 5, 137 | SNMP_API_STAT_PACKET_TOO_BIG = 6, 138 | SNMP_API_STAT_NO_SUCH_NAME = 7, 139 | }; 140 | 141 | // 142 | // http://oreilly.com/catalog/esnmp/chapter/ch02.html Table 2-1: SMIv1 Datatypes 143 | 144 | typedef enum SNMP_SYNTAXES { 145 | // SNMP ObjectSyntax values 146 | SNMP_SYNTAX_SEQUENCE = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_CONSTRUCTOR | 0x10, 147 | // These values are used in the "syntax" member of VALUEs 148 | SNMP_SYNTAX_BOOL = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 1, 149 | SNMP_SYNTAX_INT = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 2, 150 | SNMP_SYNTAX_BITS = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 3, 151 | SNMP_SYNTAX_OCTETS = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 4, 152 | SNMP_SYNTAX_NULL = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 5, 153 | SNMP_SYNTAX_OID = ASN_BER_BASE_UNIVERSAL | ASN_BER_BASE_PRIMITIVE | 6, 154 | SNMP_SYNTAX_INT32 = SNMP_SYNTAX_INT, 155 | SNMP_SYNTAX_IP_ADDRESS = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 0, 156 | SNMP_SYNTAX_COUNTER = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 1, 157 | SNMP_SYNTAX_GAUGE = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 2, 158 | SNMP_SYNTAX_TIME_TICKS = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 3, 159 | SNMP_SYNTAX_OPAQUE = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 4, 160 | SNMP_SYNTAX_NSAPADDR = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 5, 161 | SNMP_SYNTAX_COUNTER64 = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 6, 162 | SNMP_SYNTAX_UINT32 = ASN_BER_BASE_APPLICATION | ASN_BER_BASE_PRIMITIVE | 7, 163 | }; 164 | 165 | typedef struct SNMP_OID { 166 | byte data[SNMP_MAX_OID_LEN]; // ushort array insted?? 167 | size_t size; 168 | // 169 | void fromString(const char *buffer) { 170 | if (buffer[0] == '1' && buffer[1] == '.' && buffer[2] == '3' && buffer[3] == '.') { 171 | memset(data, 0, SNMP_MAX_OID_LEN); 172 | data[0] = 0x2B; 173 | int fs_ilen = strlen(buffer); 174 | int fs_ic = 0; 175 | int fs_id = 1; 176 | char fs_Csl[5]; 177 | memset(fs_Csl, 0, 5); 178 | for (int fs_i = 4; fs_i < fs_ilen; fs_i++){ 179 | if (buffer[fs_i] == '.') { 180 | word fs_oidw = atol(fs_Csl); 181 | if (fs_oidw < 128) { 182 | data[fs_id] = fs_oidw; 183 | } else if (fs_oidw < 16384 ) { 184 | byte fs_loidb = lowByte(fs_oidw) & 127; 185 | word fs_oidwtmp = fs_oidw << 1; 186 | byte fs_hoidb = highByte(fs_oidwtmp) | 128; 187 | data[fs_id] = fs_hoidb; 188 | fs_id++; 189 | data[fs_id] = fs_loidb; 190 | } else { 191 | byte fs_loidb = lowByte(fs_oidw) & 127; 192 | word fs_oidwtmp = fs_oidw << 1; 193 | byte fs_hoidb = highByte(fs_oidwtmp) | 128; 194 | fs_oidwtmp = fs_oidw >> 14; 195 | byte fs_hhoidb = (lowByte(fs_oidwtmp) & 3) | 128; 196 | data[fs_id] = fs_hhoidb; 197 | fs_id++; 198 | data[fs_id] = fs_hoidb; 199 | fs_id++; 200 | data[fs_id] = fs_loidb; 201 | } 202 | memset(fs_Csl, 0, 5); 203 | fs_ic = 0; 204 | fs_id++; 205 | } else { 206 | fs_Csl[fs_ic] = buffer[fs_i]; 207 | fs_ic++; 208 | } 209 | } 210 | word fs_oidw = atoi(fs_Csl); 211 | if (fs_oidw < 128) { 212 | data[fs_id] = fs_oidw; 213 | } else if (fs_oidw < 16384 ) { 214 | byte fs_loidb = lowByte(fs_oidw) & 127; 215 | word fs_oidwtmp = fs_oidw << 1; 216 | byte fs_hoidb = highByte(fs_oidwtmp) | 128; 217 | data[fs_id] = fs_hoidb; 218 | fs_id++; 219 | data[fs_id] = fs_loidb; 220 | } else { 221 | byte fs_loidb = lowByte(fs_oidw) & 127; 222 | word fs_oidwtmp = fs_oidw << 1; 223 | byte fs_hoidb = highByte(fs_oidwtmp) | 128; 224 | fs_oidwtmp = fs_oidw >> 14; 225 | byte fs_hhoidb = (lowByte(fs_oidwtmp) & 3) | 128; 226 | data[fs_id] = fs_hhoidb; 227 | fs_id++; 228 | data[fs_id] = fs_hoidb; 229 | fs_id++; 230 | data[fs_id] = fs_loidb; 231 | } 232 | 233 | fs_id++; 234 | size = fs_id; 235 | } 236 | } 237 | 238 | // 239 | void toString(char *buffer) { 240 | buffer[0] = '1'; 241 | buffer[1] = '.'; 242 | buffer[2] = '3'; 243 | buffer[3] = '\0'; 244 | // 245 | char buff[16]; 246 | byte hsize = size - 1; 247 | byte hpos = 1; 248 | uint16_t subid; 249 | // 250 | while ( hsize > 0 ) { 251 | subid = 0; 252 | uint16_t b = 0; 253 | do { 254 | uint16_t next = data[hpos++]; 255 | b = next & 0xFF; 256 | subid = (subid << 7) + (b & ~0x80); 257 | hsize--; 258 | } while ( (hsize > 0) && ((b & 0x80) != 0) ); 259 | utoa(subid, buff, 10); 260 | strcat(buffer, "."); 261 | strcat(buffer, buff); 262 | } 263 | }; 264 | }; 265 | 266 | // union for values? 267 | // 268 | typedef struct SNMP_VALUE { 269 | byte data[SNMP_MAX_VALUE_LEN]; 270 | size_t size; 271 | SNMP_SYNTAXES syntax; 272 | // 273 | byte i; // for encoding/decoding functions 274 | // 275 | // clear's buffer and sets size to 0 276 | void clear(void) { 277 | memset(data, 0, SNMP_MAX_VALUE_LEN); 278 | size = 0; 279 | } 280 | // 281 | // 282 | // ASN.1 decoding functions 283 | // 284 | // decode's an octet string, object-identifier, opaque syntax to string 285 | SNMP_ERR_CODES decode(char *value, size_t max_size) { 286 | if ( syntax == SNMP_SYNTAX_OCTETS || syntax == SNMP_SYNTAX_OID 287 | || syntax == SNMP_SYNTAX_OPAQUE ) { 288 | if ( strlen(value) - 1 < max_size ) { 289 | if ( syntax == SNMP_SYNTAX_OID ) { 290 | value[0] = '1'; 291 | value[1] = '.'; 292 | value[2] = '3'; 293 | value[3] = '\0'; 294 | // 295 | char buff[16]; 296 | byte hsize = size - 1; 297 | byte hpos = 1; 298 | uint16_t subid; 299 | // 300 | while ( hsize > 0 ) { 301 | subid = 0; 302 | uint16_t b = 0; 303 | do { 304 | uint16_t next = data[hpos++]; 305 | b = next & 0xFF; 306 | subid = (subid << 7) + (b & ~0x80); 307 | hsize--; 308 | } while ( (hsize > 0) && ((b & 0x80) != 0) ); 309 | utoa(subid, buff, 10); 310 | strcat(value, "."); 311 | strcat(value, buff); 312 | } 313 | } else { 314 | for ( i = 0; i < size; i++ ) { 315 | value[i] = (char)data[i]; 316 | } 317 | value[size] = '\0'; 318 | } 319 | return SNMP_ERR_NO_ERROR; 320 | } else { 321 | clear(); 322 | return SNMP_ERR_TOO_BIG; 323 | } 324 | } else { 325 | clear(); 326 | return SNMP_ERR_WRONG_TYPE; 327 | } 328 | } 329 | // 330 | // decode's an int syntax to int16 331 | SNMP_ERR_CODES decode(int16_t *value) { 332 | if ( syntax == SNMP_SYNTAX_INT ) { 333 | uint8_t *p = (uint8_t*)value, i; 334 | memset(value, 0, sizeof(*value)); 335 | for(i = 0;i < size;i++) 336 | { 337 | *p++ = data[size - 1 - i]; 338 | } 339 | return SNMP_ERR_NO_ERROR; 340 | } else { 341 | clear(); 342 | return SNMP_ERR_WRONG_TYPE; 343 | } 344 | } 345 | // 346 | // decode's an int32 syntax to int32 347 | SNMP_ERR_CODES decode(int32_t *value) { 348 | if ( syntax == SNMP_SYNTAX_INT32 ) { 349 | uint8_t *p = (uint8_t*)value, i; 350 | memset(value, 0, sizeof(*value)); 351 | for(i = 0;i < size;i++) 352 | { 353 | *p++ = data[size - 1 - i]; 354 | } 355 | return SNMP_ERR_NO_ERROR; 356 | } else { 357 | clear(); 358 | return SNMP_ERR_WRONG_TYPE; 359 | } 360 | } 361 | // 362 | // decode's an uint32, counter, time-ticks, gauge syntax to uint32 363 | SNMP_ERR_CODES decode(uint32_t *value) { 364 | if ( syntax == SNMP_SYNTAX_COUNTER || syntax == SNMP_SYNTAX_TIME_TICKS 365 | || syntax == SNMP_SYNTAX_GAUGE || syntax == SNMP_SYNTAX_UINT32 ) { 366 | uint8_t *p = (uint8_t*)value, i; 367 | memset(value, 0, sizeof(*value)); 368 | for(i = 0;i < size;i++) 369 | { 370 | *p++ = data[size - 1 - i]; 371 | } 372 | return SNMP_ERR_NO_ERROR; 373 | } else { 374 | clear(); 375 | return SNMP_ERR_WRONG_TYPE; 376 | } 377 | } 378 | // 379 | // decode's an ip-address, NSAP-address syntax to an ip-address byte array 380 | SNMP_ERR_CODES decode(byte *value) { 381 | memset(data, 0, SNMP_MAX_VALUE_LEN); 382 | if ( syntax == SNMP_SYNTAX_IP_ADDRESS || syntax == SNMP_SYNTAX_NSAPADDR ) { 383 | uint8_t *p = (uint8_t*)value, i; 384 | memset(value, 0, 4); 385 | for(i = 0;i < size;i++) 386 | { 387 | *p++ = data[size - 4 - i]; 388 | } 389 | return SNMP_ERR_NO_ERROR; 390 | } else { 391 | clear(); 392 | return SNMP_ERR_WRONG_TYPE; 393 | } 394 | } 395 | // 396 | // decode's a boolean syntax to boolean 397 | SNMP_ERR_CODES decode(bool *value) { 398 | if ( syntax == SNMP_SYNTAX_BOOL ) { 399 | *value = (data[0] != 0); 400 | return SNMP_ERR_NO_ERROR; 401 | } else { 402 | clear(); 403 | return SNMP_ERR_WRONG_TYPE; 404 | } 405 | } 406 | // 407 | // 408 | // ASN.1 encoding functions 409 | // 410 | // encode's a octet string to a string, opaque syntax 411 | // encode object-identifier here?? 412 | SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const char *value) { 413 | memset(data, 0, SNMP_MAX_VALUE_LEN); 414 | if ( syn == SNMP_SYNTAX_OCTETS || syn == SNMP_SYNTAX_OPAQUE ) { 415 | if ( strlen(value) - 1 < SNMP_MAX_VALUE_LEN ) { 416 | syntax = syn; 417 | size = strlen(value); 418 | for ( i = 0; i < size; i++ ) { 419 | data[i] = (byte)value[i]; 420 | } 421 | return SNMP_ERR_NO_ERROR; 422 | } else { 423 | clear(); 424 | return SNMP_ERR_TOO_BIG; 425 | } 426 | } else { 427 | clear(); 428 | return SNMP_ERR_WRONG_TYPE; 429 | } 430 | } 431 | // 432 | // encode's an int16 to int, opaque syntax 433 | SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const int16_t value) { 434 | memset(data, 0, SNMP_MAX_VALUE_LEN); 435 | if ( syn == SNMP_SYNTAX_INT || syn == SNMP_SYNTAX_OPAQUE ) { 436 | int16_u tmp; 437 | size = 2; 438 | syntax = syn; 439 | tmp.int16 = value; 440 | data[0] = tmp.data[1]; 441 | data[1] = tmp.data[0]; 442 | return SNMP_ERR_NO_ERROR; 443 | } else { 444 | clear(); 445 | return SNMP_ERR_WRONG_TYPE; 446 | } 447 | } 448 | // 449 | // encode's an int32 to int32, opaque syntax 450 | SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const int32_t value) { 451 | memset(data, 0, SNMP_MAX_VALUE_LEN); 452 | if ( syn == SNMP_SYNTAX_INT32 || syn == SNMP_SYNTAX_OPAQUE ) { 453 | int32_u tmp; 454 | size = 4; 455 | syntax = syn; 456 | tmp.int32 = value; 457 | data[0] = tmp.data[3]; 458 | data[1] = tmp.data[2]; 459 | data[2] = tmp.data[1]; 460 | data[3] = tmp.data[0]; 461 | return SNMP_ERR_NO_ERROR; 462 | } else { 463 | clear(); 464 | return SNMP_ERR_WRONG_TYPE; 465 | } 466 | } 467 | // 468 | // encode's an uint32 to uint32, counter, time-ticks, gauge, opaque syntax 469 | SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const uint32_t value) { 470 | memset(data, 0, SNMP_MAX_VALUE_LEN); 471 | if ( syn == SNMP_SYNTAX_COUNTER || syn == SNMP_SYNTAX_TIME_TICKS 472 | || syn == SNMP_SYNTAX_GAUGE || syn == SNMP_SYNTAX_UINT32 473 | || syn == SNMP_SYNTAX_OPAQUE ) { 474 | uint32_u tmp; 475 | size = 4; 476 | syntax = syn; 477 | tmp.uint32 = value; 478 | data[0] = tmp.data[3]; 479 | data[1] = tmp.data[2]; 480 | data[2] = tmp.data[1]; 481 | data[3] = tmp.data[0]; 482 | return SNMP_ERR_NO_ERROR; 483 | } else { 484 | clear(); 485 | return SNMP_ERR_WRONG_TYPE; 486 | } 487 | } 488 | // 489 | // encode's an ip-address byte array to ip-address, NSAP-address, opaque syntax 490 | SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const byte *value) { 491 | memset(data, 0, SNMP_MAX_VALUE_LEN); 492 | if ( syn == SNMP_SYNTAX_IP_ADDRESS || syn == SNMP_SYNTAX_NSAPADDR 493 | || syn == SNMP_SYNTAX_OPAQUE ) { 494 | if ( sizeof(value) > 4 ) { 495 | clear(); 496 | return SNMP_ERR_TOO_BIG; 497 | } else { 498 | size = 4; 499 | syntax = syn; 500 | data[0] = value[3]; 501 | data[1] = value[2]; 502 | data[2] = value[1]; 503 | data[3] = value[0]; 504 | return SNMP_ERR_NO_ERROR; 505 | } 506 | } else { 507 | clear(); 508 | return SNMP_ERR_WRONG_TYPE; 509 | } 510 | } 511 | // 512 | // encode's a boolean to boolean, opaque syntax 513 | SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const bool value) { 514 | memset(data, 0, SNMP_MAX_VALUE_LEN); 515 | if ( syn == SNMP_SYNTAX_BOOL || syn == SNMP_SYNTAX_OPAQUE ) { 516 | size = 1; 517 | syntax = syn; 518 | data[0] = value ? 0xff : 0; 519 | return SNMP_ERR_NO_ERROR; 520 | } else { 521 | clear(); 522 | return SNMP_ERR_WRONG_TYPE; 523 | } 524 | } 525 | // 526 | // encode's an uint64 to counter64, opaque syntax 527 | SNMP_ERR_CODES encode(SNMP_SYNTAXES syn, const uint64_t value) { 528 | memset(data, 0, SNMP_MAX_VALUE_LEN); 529 | if ( syn == SNMP_SYNTAX_COUNTER64 || syn == SNMP_SYNTAX_OPAQUE ) { 530 | uint64_u tmp; 531 | size = 8; 532 | syntax = syn; 533 | tmp.uint64 = value; 534 | data[0] = tmp.data[7]; 535 | data[1] = tmp.data[6]; 536 | data[2] = tmp.data[5]; 537 | data[3] = tmp.data[4]; 538 | data[4] = tmp.data[3]; 539 | data[5] = tmp.data[2]; 540 | data[6] = tmp.data[1]; 541 | data[7] = tmp.data[0]; 542 | return SNMP_ERR_NO_ERROR; 543 | } else { 544 | clear(); 545 | return SNMP_ERR_WRONG_TYPE; 546 | } 547 | } 548 | // 549 | // encode's a null to null, opaque syntax 550 | SNMP_ERR_CODES encode(SNMP_SYNTAXES syn) { 551 | clear(); 552 | if ( syn == SNMP_SYNTAX_NULL || syn == SNMP_SYNTAX_OPAQUE ) { 553 | size = 0; 554 | syntax = syn; 555 | return SNMP_ERR_NO_ERROR; 556 | } else { 557 | return SNMP_ERR_WRONG_TYPE; 558 | } 559 | } 560 | }; 561 | 562 | typedef struct SNMP_PDU { 563 | SNMP_PDU_TYPES type; 564 | int32_t version; 565 | int32_t requestId; 566 | SNMP_ERR_CODES error; 567 | int32_t errorIndex; 568 | SNMP_OID OID; 569 | SNMP_VALUE VALUE; 570 | }; 571 | 572 | class AgentuinoClass { 573 | public: 574 | // Agent functions 575 | SNMP_API_STAT_CODES begin(); 576 | SNMP_API_STAT_CODES begin(char *getCommName, char *setCommName, uint16_t port); 577 | void listen(void); 578 | SNMP_API_STAT_CODES requestPdu(SNMP_PDU *pdu); 579 | SNMP_API_STAT_CODES responsePdu(SNMP_PDU *pdu); 580 | void onPduReceive(onPduReceiveCallback pduReceived); 581 | void freePdu(SNMP_PDU *pdu); 582 | 583 | // Helper functions 584 | 585 | private: 586 | byte _packet[SNMP_MAX_PACKET_LEN]; 587 | uint16_t _packetSize; 588 | uint16_t _packetPos; 589 | SNMP_PDU_TYPES _dstType; 590 | uint8_t _dstIp[4]; 591 | uint16_t _dstPort; 592 | char *_getCommName; 593 | size_t _getSize; 594 | char *_setCommName; 595 | size_t _setSize; 596 | onPduReceiveCallback _callback; 597 | }; 598 | 599 | extern AgentuinoClass Agentuino; 600 | 601 | #endif -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | An updated version of the Agentuino (http://code.google.com/p/agentuino/) SNMP library. 2 | 3 | The software now support SNMP GET-NEXT-Request 4 | 5 | 6 | 7 | Net-Snmp Get-Next-Request examples 8 | ---------------------------------- 9 | 10 | snmpgetnext -v 1 -c public 192.168.20.6 sysUpTime.0 11 | 12 | Output: 13 | SNMPv2-MIB::sysContact.0 = STRING: Petr Domorazek 14 | 15 | snmpwalk -v 1 -c public 192.168.20.6 16 | 17 | Output: 18 | SNMPv2-MIB::sysDescr.0 = STRING: Agentuino, a light-weight SNMP Agent. 19 | DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (53100) 0:08:51.00 20 | SNMPv2-MIB::sysContact.0 = STRING: Petr Domorazek 21 | SNMPv2-MIB::sysName.0 = STRING: Agentuino 22 | SNMPv2-MIB::sysLocation.0 = STRING: Czech Republic 23 | SNMPv2-MIB::sysServices.0 = INTEGER: 6 24 | End of MIB -------------------------------------------------------------------------------- /examples/AgentPlus/AgentPlus.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Agentuino SNMP Agent Library Prototyping... 3 | * 4 | * Copyright 2010 Eric C. Gionet 5 | * 6 | * Update snmpGetNext by Petr Domorazek 7 | */ 8 | #include // Include the Streaming library 9 | #include // Include the Ethernet library 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | static byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 16 | static byte ip[] = { 192, 168, 20, 6 }; 17 | //static byte gateway[] = { 192, 168, 20, 1 }; 18 | //static byte subnet[] = { 255, 255, 255, 0 }; 19 | 20 | // 21 | // tkmib - linux mib browser 22 | // 23 | // RFC1213-MIB OIDs 24 | // .iso (.1) 25 | // .iso.org (.1.3) 26 | // .iso.org.dod (.1.3.6) 27 | // .iso.org.dod.internet (.1.3.6.1) 28 | // .iso.org.dod.internet.mgmt (.1.3.6.1.2) 29 | // .iso.org.dod.internet.mgmt.mib-2 (.1.3.6.1.2.1) 30 | // .iso.org.dod.internet.mgmt.mib-2.system (.1.3.6.1.2.1.1) 31 | // .iso.org.dod.internet.mgmt.mib-2.system.sysDescr (.1.3.6.1.2.1.1.1) 32 | static char sysDescr[] PROGMEM = "1.3.6.1.2.1.1.1.0"; // read-only (DisplayString) 33 | // .iso.org.dod.internet.mgmt.mib-2.system.sysObjectID (.1.3.6.1.2.1.1.2) 34 | //static char sysObjectID[] PROGMEM = "1.3.6.1.2.1.1.2.0"; // read-only (ObjectIdentifier) 35 | // .iso.org.dod.internet.mgmt.mib-2.system.sysUpTime (.1.3.6.1.2.1.1.3) 36 | static char sysUpTime[] PROGMEM = "1.3.6.1.2.1.1.3.0"; // read-only (TimeTicks) 37 | // .iso.org.dod.internet.mgmt.mib-2.system.sysContact (.1.3.6.1.2.1.1.4) 38 | static char sysContact[] PROGMEM = "1.3.6.1.2.1.1.4.0"; // read-write (DisplayString) 39 | // .iso.org.dod.internet.mgmt.mib-2.system.sysName (.1.3.6.1.2.1.1.5) 40 | static char sysName[] PROGMEM = "1.3.6.1.2.1.1.5.0"; // read-write (DisplayString) 41 | // .iso.org.dod.internet.mgmt.mib-2.system.sysLocation (.1.3.6.1.2.1.1.6) 42 | static char sysLocation[] PROGMEM = "1.3.6.1.2.1.1.6.0"; // read-write (DisplayString) 43 | // .iso.org.dod.internet.mgmt.mib-2.system.sysServices (.1.3.6.1.2.1.1.7) 44 | static char sysServices[] PROGMEM = "1.3.6.1.2.1.1.7.0"; // read-only (Integer) 45 | // 46 | // Arduino defined OIDs 47 | // .iso.org.dod.internet.private (.1.3.6.1.4) 48 | // .iso.org.dod.internet.private.enterprises (.1.3.6.1.4.1) 49 | // .iso.org.dod.internet.private.enterprises.arduino (.1.3.6.1.4.1.36582) 50 | // 51 | // 52 | // RFC1213 local values 53 | static char locDescr[] = "Agentuino, a light-weight SNMP Agent."; // read-only (static) 54 | //static char locObjectID[] = "1.3.6.1.3.2009.0"; // read-only (static) 55 | static uint32_t locUpTime = 0; // read-only (static) 56 | static char locContact[20] = "Petr Domorazek"; // should be stored/read from EEPROM - read/write (not done for simplicity) 57 | static char locName[20] = "Agentuino"; // should be stored/read from EEPROM - read/write (not done for simplicity) 58 | static char locLocation[20] = "Czech Republic"; // should be stored/read from EEPROM - read/write (not done for simplicity) 59 | static int32_t locServices = 6; // read-only (static) 60 | 61 | uint32_t prevMillis = millis(); 62 | char oid[SNMP_MAX_OID_LEN]; 63 | SNMP_API_STAT_CODES api_status; 64 | SNMP_ERR_CODES status; 65 | 66 | void pduReceived() 67 | { 68 | SNMP_PDU pdu; 69 | api_status = Agentuino.requestPdu(&pdu); 70 | // 71 | if ((pdu.type == SNMP_PDU_GET || pdu.type == SNMP_PDU_GET_NEXT || pdu.type == SNMP_PDU_SET) 72 | && pdu.error == SNMP_ERR_NO_ERROR && api_status == SNMP_API_STAT_SUCCESS ) { 73 | // 74 | pdu.OID.toString(oid); 75 | // Implementation SNMP GET NEXT 76 | if ( pdu.type == SNMP_PDU_GET_NEXT ) { 77 | char tmpOIDfs[SNMP_MAX_OID_LEN]; 78 | if ( strcmp_P( oid, sysDescr ) == 0 ) { 79 | strcpy_P ( oid, sysUpTime ); 80 | strcpy_P ( tmpOIDfs, sysUpTime ); 81 | pdu.OID.fromString(tmpOIDfs); 82 | } else if ( strcmp_P(oid, sysUpTime ) == 0 ) { 83 | strcpy_P ( oid, sysContact ); 84 | strcpy_P ( tmpOIDfs, sysContact ); 85 | pdu.OID.fromString(tmpOIDfs); 86 | } else if ( strcmp_P(oid, sysContact ) == 0 ) { 87 | strcpy_P ( oid, sysName ); 88 | strcpy_P ( tmpOIDfs, sysName ); 89 | pdu.OID.fromString(tmpOIDfs); 90 | } else if ( strcmp_P(oid, sysName ) == 0 ) { 91 | strcpy_P ( oid, sysLocation ); 92 | strcpy_P ( tmpOIDfs, sysLocation ); 93 | pdu.OID.fromString(tmpOIDfs); 94 | } else if ( strcmp_P(oid, sysLocation ) == 0 ) { 95 | strcpy_P ( oid, sysServices ); 96 | strcpy_P ( tmpOIDfs, sysServices ); 97 | pdu.OID.fromString(tmpOIDfs); 98 | } else if ( strcmp_P(oid, sysServices ) == 0 ) { 99 | strcpy_P ( oid, "1.0" ); 100 | } else { 101 | int ilen = strlen(oid); 102 | if ( strncmp_P(oid, sysDescr, ilen ) == 0 ) { 103 | strcpy_P ( oid, sysDescr ); 104 | strcpy_P ( tmpOIDfs, sysDescr ); 105 | pdu.OID.fromString(tmpOIDfs); 106 | } else if ( strncmp_P(oid, sysUpTime, ilen ) == 0 ) { 107 | strcpy_P ( oid, sysUpTime ); 108 | strcpy_P ( tmpOIDfs, sysUpTime ); 109 | pdu.OID.fromString(tmpOIDfs); 110 | } else if ( strncmp_P(oid, sysContact, ilen ) == 0 ) { 111 | strcpy_P ( oid, sysContact ); 112 | strcpy_P ( tmpOIDfs, sysContact ); 113 | pdu.OID.fromString(tmpOIDfs); 114 | } else if ( strncmp_P(oid, sysName, ilen ) == 0 ) { 115 | strcpy_P ( oid, sysName ); 116 | strcpy_P ( tmpOIDfs, sysName ); 117 | pdu.OID.fromString(tmpOIDfs); 118 | } else if ( strncmp_P(oid, sysLocation, ilen ) == 0 ) { 119 | strcpy_P ( oid, sysLocation ); 120 | strcpy_P ( tmpOIDfs, sysLocation ); 121 | pdu.OID.fromString(tmpOIDfs); 122 | } else if ( strncmp_P(oid, sysServices, ilen ) == 0 ) { 123 | strcpy_P ( oid, sysServices ); 124 | strcpy_P ( tmpOIDfs, sysServices ); 125 | pdu.OID.fromString(tmpOIDfs); 126 | } 127 | } 128 | } 129 | // End of implementation SNMP GET NEXT / WALK 130 | 131 | if ( strcmp_P(oid, sysDescr ) == 0 ) { 132 | // handle sysDescr (set/get) requests 133 | if ( pdu.type == SNMP_PDU_SET ) { 134 | // response packet from set-request - object is read-only 135 | pdu.type = SNMP_PDU_RESPONSE; 136 | pdu.error = SNMP_ERR_READ_ONLY; 137 | } else { 138 | // response packet from get-request - locDescr 139 | status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locDescr); 140 | pdu.type = SNMP_PDU_RESPONSE; 141 | pdu.error = status; 142 | } 143 | // 144 | } else if ( strcmp_P(oid, sysUpTime ) == 0 ) { 145 | // handle sysName (set/get) requests 146 | if ( pdu.type == SNMP_PDU_SET ) { 147 | // response packet from set-request - object is read-only 148 | pdu.type = SNMP_PDU_RESPONSE; 149 | pdu.error = SNMP_ERR_READ_ONLY; 150 | } else { 151 | // response packet from get-request - locUpTime 152 | status = pdu.VALUE.encode(SNMP_SYNTAX_TIME_TICKS, locUpTime); 153 | pdu.type = SNMP_PDU_RESPONSE; 154 | pdu.error = status; 155 | } 156 | // 157 | } else if ( strcmp_P(oid, sysName ) == 0 ) { 158 | // handle sysName (set/get) requests 159 | if ( pdu.type == SNMP_PDU_SET ) { 160 | // response packet from set-request - object is read/write 161 | status = pdu.VALUE.decode(locName, strlen(locName)); 162 | pdu.type = SNMP_PDU_RESPONSE; 163 | pdu.error = status; 164 | } else { 165 | // response packet from get-request - locName 166 | status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locName); 167 | pdu.type = SNMP_PDU_RESPONSE; 168 | pdu.error = status; 169 | } 170 | // 171 | } else if ( strcmp_P(oid, sysContact ) == 0 ) { 172 | // handle sysContact (set/get) requests 173 | if ( pdu.type == SNMP_PDU_SET ) { 174 | // response packet from set-request - object is read/write 175 | status = pdu.VALUE.decode(locContact, strlen(locContact)); 176 | pdu.type = SNMP_PDU_RESPONSE; 177 | pdu.error = status; 178 | } else { 179 | // response packet from get-request - locContact 180 | status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locContact); 181 | pdu.type = SNMP_PDU_RESPONSE; 182 | pdu.error = status; 183 | } 184 | // 185 | } else if ( strcmp_P(oid, sysLocation ) == 0 ) { 186 | // handle sysLocation (set/get) requests 187 | if ( pdu.type == SNMP_PDU_SET ) { 188 | // response packet from set-request - object is read/write 189 | status = pdu.VALUE.decode(locLocation, strlen(locLocation)); 190 | pdu.type = SNMP_PDU_RESPONSE; 191 | pdu.error = status; 192 | } else { 193 | // response packet from get-request - locLocation 194 | status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locLocation); 195 | pdu.type = SNMP_PDU_RESPONSE; 196 | pdu.error = status; 197 | } 198 | // 199 | } else if ( strcmp_P(oid, sysServices) == 0 ) { 200 | // handle sysServices (set/get) requests 201 | if ( pdu.type == SNMP_PDU_SET ) { 202 | // response packet from set-request - object is read-only 203 | pdu.type = SNMP_PDU_RESPONSE; 204 | pdu.error = SNMP_ERR_READ_ONLY; 205 | } else { 206 | // response packet from get-request - locServices 207 | status = pdu.VALUE.encode(SNMP_SYNTAX_INT, locServices); 208 | pdu.type = SNMP_PDU_RESPONSE; 209 | pdu.error = status; 210 | } 211 | // 212 | } else { 213 | // oid does not exist 214 | // response packet - object not found 215 | pdu.type = SNMP_PDU_RESPONSE; 216 | pdu.error = SNMP_ERR_NO_SUCH_NAME; 217 | } 218 | // 219 | Agentuino.responsePdu(&pdu); 220 | } 221 | // 222 | Agentuino.freePdu(&pdu); 223 | // 224 | } 225 | 226 | void setup() 227 | { 228 | //Serial.begin(9600); 229 | Ethernet.begin(mac, ip); 230 | // 231 | api_status = Agentuino.begin(); 232 | // 233 | if ( api_status == SNMP_API_STAT_SUCCESS ) { 234 | // 235 | Agentuino.onPduReceive(pduReceived); 236 | // 237 | delay(10); 238 | // 239 | return; 240 | } 241 | // 242 | delay(10); 243 | } 244 | 245 | void loop() 246 | { 247 | // listen/handle for incoming SNMP requests 248 | Agentuino.listen(); 249 | // 250 | // sysUpTime - The time (in hundredths of a second) since 251 | // the network management portion of the system was last 252 | // re-initialized. 253 | if ( millis() - prevMillis > 1000 ) { 254 | // increment previous milliseconds 255 | prevMillis += 1000; 256 | // 257 | // increment up-time counter 258 | locUpTime += 100; 259 | } 260 | } 261 | --------------------------------------------------------------------------------