You've already forked Frequency_Inverter
mirror of
https://github.com/Indemsys/Frequency_Inverter.git
synced 2026-05-03 04:25:42 +00:00
808 lines
23 KiB
C
808 lines
23 KiB
C
/**HEADER********************************************************************
|
|
*
|
|
* Copyright (c) 2008 Freescale Semiconductor;
|
|
* All Rights Reserved
|
|
*
|
|
* Copyright (c) 2004-2008 Embedded Access Inc.;
|
|
* All Rights Reserved
|
|
*
|
|
* Copyright (c) 1989-2008 ARC International;
|
|
* All Rights Reserved
|
|
*
|
|
***************************************************************************
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
**************************************************************************
|
|
*
|
|
* $FileName: snmp.c$
|
|
* $Version : 3.8.16.0$
|
|
* $Date : Jun-14-2012$
|
|
*
|
|
* Comments:
|
|
*
|
|
* This file contains an implementation of an
|
|
* SNMP{v1,v2c} agent.
|
|
*
|
|
*END************************************************************************/
|
|
|
|
#include <rtcs.h>
|
|
#include <rtcs_prv.h>
|
|
|
|
#if RTCSCFG_ENABLE_SNMP && RTCSCFG_ENABLE_UDP
|
|
#if RTCSCFG_ENABLE_IP4
|
|
|
|
#include <string.h>
|
|
#include "snmpcfg.h"
|
|
#include "asn1.h"
|
|
#include "snmp.h"
|
|
|
|
typedef struct snmp_context {
|
|
uint_32 UDPSOCK;
|
|
} SNMP_CONTEXT, _PTR_ SNMP_CONTEXT_PTR;
|
|
|
|
_rtcs_taskid SNMP_task_id = 0;
|
|
|
|
#ifdef __MQX__
|
|
void SNMP_Exit_handler(void);
|
|
#endif
|
|
|
|
|
|
static uchar inbuf[SNMPCFG_BUFFER_SIZE];
|
|
static uchar outbuf[SNMPCFG_BUFFER_SIZE];
|
|
|
|
void SNMP_task (pointer, pointer);
|
|
|
|
/*
|
|
** This agent generates GetResponse PDUs to GetRequests,
|
|
** GetNextRequests and GetBulkRequests. All GetResponses
|
|
** have the same format, specifically:
|
|
**
|
|
** 30 <len>
|
|
** 02 01 <00-01>
|
|
** 04 <len> <community>
|
|
** A2 <len>
|
|
** 02 <len> <id>
|
|
** 02 01 00
|
|
** 02 01 00
|
|
** 30 <len>
|
|
**
|
|
** 30 <len>
|
|
** 06 <len> <object-id>
|
|
** <tag> <len> <value>
|
|
** 30 <len>
|
|
** 06 <len> <object-id>
|
|
** <tag> <len> <value>
|
|
** 30 <len>
|
|
** 06 <len> <object-id>
|
|
** <tag> <len> <value>
|
|
** ...
|
|
**
|
|
** Building this packet is a bit problematic.
|
|
**
|
|
** If we start from the top, we can't fill in the <len>
|
|
** fields, because
|
|
** 1) we don't yet know the length of the remainder
|
|
** of the packet, and
|
|
** 2) since we don't know the length, we don't know
|
|
** how many bytes the length field will occupy
|
|
** (each <len> is 1 byte for lengths 00-7F,
|
|
** 2 bytes for lengths 80-FF, or 3 bytes for
|
|
** lengths 0100-FFFF).
|
|
**
|
|
** We'd have to assume the worst case for each <len>
|
|
** and reserve 3 bytes for each, and make a second
|
|
** pass to fill them.
|
|
**
|
|
** If we start from the bottom, then building responses
|
|
** to GetBulkRequests becomes hard.
|
|
**
|
|
** So what do we do? We start from the middle. :)
|
|
**
|
|
** We reserve space for the maximum header (the first eight
|
|
** lines above). To do this, we make an assumption: that
|
|
** no <len> ever gets a value larger than FFFF. This is
|
|
** pretty safe, since SNMP packets have to fit inside IP
|
|
** datagrams, and IP datagrams only have 16-bit length
|
|
** fields.
|
|
**
|
|
** Then we make repeated MIB calls to fill in the
|
|
** VarBindList.
|
|
**
|
|
** Once the VarBindList is written, we write the header
|
|
** backwards.
|
|
**
|
|
*/
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : SNMP_request
|
|
* Returned Value :
|
|
* Comments : Parse a VarBindList in a PDU.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static boolean SNMP_request
|
|
(
|
|
SNMP_PARSE_PTR snmp,
|
|
uchar_ptr invarp,
|
|
uint_32 invarlen,
|
|
uchar_ptr outvarp,
|
|
uint_32 outvarlen,
|
|
uint_32 _PTR_ writelen
|
|
)
|
|
{ /* Body */
|
|
|
|
IF_SNMP_STATS_ENABLED(snmp->STATS.ST_RX_VAR_GETS++);
|
|
snmp->errstat = RTCSMIB_request(snmp->pdutype, invarp, invarlen, outvarp, outvarlen, writelen);
|
|
|
|
if (snmp->errstat == SNMP_ERROR_noError) {
|
|
return TRUE;
|
|
} /* Endif */
|
|
|
|
if (snmp->errstat == SNMP_ERROR_PARSE) {
|
|
snmp->errstat = SNMP_ERROR_noError;
|
|
return FALSE;
|
|
} /* Endif */
|
|
|
|
if (snmp->version == 0) {
|
|
switch (snmp->errstat) {
|
|
case SNMP_ERROR_noSuchObject:
|
|
case SNMP_ERROR_noSuchInstance:
|
|
case SNMP_ERROR_endOfMibView:
|
|
case SNMP_ERROR_notWritable:
|
|
snmp->errstat = SNMP_ERROR_noSuchName;
|
|
break;
|
|
case SNMP_ERROR_noAccess:
|
|
case SNMP_ERROR_wrongType:
|
|
case SNMP_ERROR_wrongLength:
|
|
case SNMP_ERROR_wrongEncoding:
|
|
case SNMP_ERROR_wrongValue:
|
|
case SNMP_ERROR_noCreation:
|
|
case SNMP_ERROR_inconsistentValue:
|
|
case SNMP_ERROR_resourceUnavailable:
|
|
snmp->errstat = SNMP_ERROR_badValue;
|
|
break;
|
|
} /* Endswitch */
|
|
return FALSE;
|
|
} /* Endif */
|
|
|
|
if ((snmp->version == 1) && (snmp->errstat >= 0x80)) {
|
|
uint_32 oidlen, varlen, totlen;
|
|
|
|
invarp++;
|
|
if (*invarp < 0x80) {
|
|
invarp++;
|
|
} else {
|
|
invarp += (*invarp & 0x7F) + 1;
|
|
} /* Endif */
|
|
|
|
invarp++;
|
|
if (*invarp < 0x80) {
|
|
oidlen = *invarp++;
|
|
} else {
|
|
uint_32 lenlen = *invarp++ & 0x7F;
|
|
oidlen = 0;
|
|
|
|
while (lenlen--) {
|
|
oidlen <<= 8;
|
|
oidlen += *invarp++;
|
|
} /* Endwhile */
|
|
} /* Endif */
|
|
|
|
varlen = oidlen;
|
|
if (varlen < 0x80) {
|
|
varlen += 2;
|
|
} else if (varlen < 0x100) {
|
|
varlen += 3;
|
|
} else {
|
|
varlen += 4;
|
|
} /* Endif */
|
|
varlen += 2;
|
|
|
|
totlen = varlen;
|
|
if (totlen < 0x80) {
|
|
totlen += 2;
|
|
} else if (totlen < 0x100) {
|
|
totlen += 3;
|
|
} else {
|
|
totlen += 4;
|
|
} /* Endif */
|
|
|
|
if (totlen > outvarlen) {
|
|
snmp->errstat = SNMP_ERROR_tooBig;
|
|
return FALSE;
|
|
} /* Endif */
|
|
|
|
*outvarp++ = ASN1_TYPE_SEQUENCE;
|
|
if (varlen < 0x80) {
|
|
*outvarp++ = varlen;
|
|
} else if (varlen < 0x100) {
|
|
*outvarp++ = 0x81;
|
|
*outvarp++ = varlen;
|
|
} else {
|
|
*outvarp++ = 0x82;
|
|
htons(outvarp, varlen);
|
|
outvarp += 2;
|
|
} /* Endif */
|
|
|
|
*outvarp++ = ASN1_TYPE_OBJECT;
|
|
if (oidlen < 0x80) {
|
|
*outvarp++ = oidlen;
|
|
} else if (oidlen < 0x100) {
|
|
*outvarp++ = 0x81;
|
|
*outvarp++ = oidlen;
|
|
} else {
|
|
*outvarp++ = 0x82;
|
|
htons(outvarp, oidlen);
|
|
outvarp += 2;
|
|
} /* Endif */
|
|
_mem_copy(invarp, outvarp, oidlen);
|
|
outvarp += oidlen;
|
|
|
|
*outvarp++ = snmp->errstat;
|
|
*outvarp++ = 0;
|
|
|
|
*writelen = totlen;
|
|
return TRUE;
|
|
} /* Endif */
|
|
|
|
return FALSE;
|
|
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : SNMP_parse_varbindlist
|
|
* Returned Value :
|
|
* Comments : Parse a VarBindList in a PDU.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static boolean SNMP_parse_varbindlist
|
|
(
|
|
SNMP_PARSE_PTR snmp,
|
|
uint_32_ptr writelen
|
|
)
|
|
{ /* Body */
|
|
uchar_ptr outp, varp;
|
|
uint_32 outlen, varlen, varcount, index;
|
|
|
|
outp = snmp->outbuf;
|
|
outlen = snmp->outlen;
|
|
index = 0;
|
|
*writelen = 0;
|
|
|
|
/*
|
|
** Set the value of non repeaters variable to zero
|
|
** if it is less than zero
|
|
*/
|
|
#if 0 // nonrep is unsigned
|
|
if(snmp->nonrep < 0) {
|
|
snmp->nonrep = 0;
|
|
}
|
|
#endif
|
|
|
|
while (snmp->nonrep && snmp->inlen) {
|
|
snmp->nonrep--;
|
|
varp = snmp->inbuf;
|
|
varlen = snmp->inlen;
|
|
index++;
|
|
if (!SNMP_request(snmp, varp, varlen, outp, outlen, &varlen)) {
|
|
if (SNMP_ERROR_USEINDEX(snmp->errstat)) {
|
|
snmp->errindex = index;
|
|
} /* Endif */
|
|
return FALSE;
|
|
} /* Endif */
|
|
outp += varlen;
|
|
outlen -= varlen;
|
|
*writelen += varlen;
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_SEQUENCE, varlen);
|
|
ASN1_READ_IGNORE(snmp, varlen);
|
|
} /* Endwhile */
|
|
|
|
while (snmp->inlen) {
|
|
varp = snmp->inbuf;
|
|
varlen = snmp->inlen;
|
|
index++;
|
|
for (varcount = 0; varcount < snmp->reps; varcount++) {
|
|
if (!SNMP_request(snmp, varp, varlen, outp, outlen, &varlen)) {
|
|
if (SNMP_ERROR_USEINDEX(snmp->errstat)) {
|
|
snmp->errindex = index;
|
|
} /* Endif */
|
|
return FALSE;
|
|
} /* Endif */
|
|
varp = outp;
|
|
outp += varlen;
|
|
outlen -= varlen;
|
|
*writelen += varlen;
|
|
} /* Endfor */
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_SEQUENCE, varlen);
|
|
ASN1_READ_IGNORE(snmp, varlen);
|
|
} /* Endwhile */
|
|
|
|
return TRUE;
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : SNMP_parse_pduv1
|
|
* Returned Value :
|
|
* Comments : Parse a {Get,GetNext,Set}Request PDU.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static boolean SNMP_parse_pduv1
|
|
(
|
|
SNMP_PARSE_PTR snmp
|
|
)
|
|
{ /* Body */
|
|
uint_32 typelen;
|
|
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_INTEGER, typelen);
|
|
if (typelen == 0) return FALSE;
|
|
snmp->errstatp = snmp->inbuf + (typelen - 1);
|
|
ASN1_READZERO_IGNORE(snmp, typelen);
|
|
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_INTEGER, typelen);
|
|
if (typelen == 0) return FALSE;
|
|
snmp->errindexp = snmp->inbuf + (typelen - 1);
|
|
ASN1_READZERO_IGNORE(snmp, typelen);
|
|
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_SEQUENCE, typelen);
|
|
snmp->inlen = typelen;
|
|
|
|
/*
|
|
** We want nonrep to be (at least) the number of VarBinds in
|
|
** the VarBindList. We pick typelen, because each VarBind is
|
|
** guaranteed to be at least one byte (in fact, they're guaranteed
|
|
** to be at least five bytes), so typelen is a guaranteed upper
|
|
** bound. We pick reps = 1, because if ever nonrep weren't big
|
|
** enough (which will never happen), the remaining VarBinds will
|
|
** still be treated as non-repeaters.
|
|
*/
|
|
snmp->nonrep = typelen;
|
|
snmp->reps = 1;
|
|
|
|
return TRUE;
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : SNMP_parse_awesome_pdubulk
|
|
* Returned Value :
|
|
* Comments : Parse a GetBulkRequest PDU.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static boolean SNMP_parse_awesome_pdubulk
|
|
(
|
|
SNMP_PARSE_PTR snmp
|
|
)
|
|
{ /* Body */
|
|
uint_32 typelen;
|
|
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_INTEGER, typelen);
|
|
if (typelen == 0) return FALSE;
|
|
snmp->errstatp = snmp->inbuf + (typelen - 1);
|
|
ASN1_READZERO_INT(snmp, typelen, snmp->nonrep);
|
|
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_INTEGER, typelen);
|
|
if (typelen == 0) return FALSE;
|
|
snmp->errindexp = snmp->inbuf + (typelen - 1);
|
|
ASN1_READZERO_INT(snmp, typelen, snmp->reps);
|
|
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_SEQUENCE, typelen);
|
|
snmp->inlen = typelen;
|
|
|
|
return TRUE;
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : SNMP_parse
|
|
* Returned Value :
|
|
* Comments : Parse an SNMP packet.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static boolean SNMP_parse
|
|
(
|
|
SNMP_PARSE_PTR snmp,
|
|
uint_32_ptr writelen
|
|
)
|
|
{ /* Body */
|
|
uint_32 typelen, maxheadlen;
|
|
uint_32 ctylen, idlen;
|
|
uchar_ptr ctyp, idp, pdup;
|
|
volatile uint_8 tmp;
|
|
|
|
maxheadlen = 0;
|
|
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_SEQUENCE, typelen);
|
|
maxheadlen += 4;
|
|
snmp->inlen = typelen;
|
|
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_INTEGER, typelen);
|
|
ASN1_READ_INT(snmp, typelen, snmp->version);
|
|
maxheadlen += 3;
|
|
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_OCTET, ctylen);
|
|
ctyp = snmp->inbuf;
|
|
|
|
/* test for community string match */
|
|
for (tmp=0; tmp < SNMPCFG_NUM_COMMUNITY; tmp++) {
|
|
if (ctylen == snmp->communitylen[tmp]) {
|
|
if( !memcmp(ctyp, snmp->community[tmp], ctylen) ) {
|
|
break;
|
|
}
|
|
}
|
|
} /* Endfor */
|
|
|
|
/* if community string is bad, return */
|
|
if(tmp == SNMPCFG_NUM_COMMUNITY) {
|
|
IF_SNMP_STATS_ENABLED(snmp->STATS.ST_RX_BAD_COMMUNITY++);
|
|
/* Check before decrement, because SNMP_task will increment it */
|
|
IF_SNMP_STATS_ENABLED(if(snmp->STATS.ST_RX_BAD_PARSE > 0) snmp->STATS.ST_RX_BAD_PARSE--);
|
|
return FALSE;
|
|
} /* Endif */
|
|
|
|
ASN1_READ_IGNORE(snmp, ctylen);
|
|
maxheadlen += ctylen + 4;
|
|
|
|
pdup = snmp->inbuf;
|
|
ASN1_READ_TYPELEN(snmp, snmp->pdutype, typelen);
|
|
*pdup = ASN1_TYPE_PDU_RESPONSE;
|
|
maxheadlen += 4;
|
|
snmp->inlen = typelen;
|
|
|
|
ASN1_READ_TYPELEN_EXPECT(snmp, ASN1_TYPE_INTEGER, idlen);
|
|
idp = snmp->inbuf;
|
|
ASN1_READ_IGNORE(snmp, idlen);
|
|
maxheadlen += idlen + 4;
|
|
|
|
maxheadlen += 10; /* two INTEGERs and a SEQUENCE */
|
|
|
|
snmp->outbuf += maxheadlen;
|
|
snmp->outlen -= maxheadlen;
|
|
|
|
#if RTCSCFG_ENABLE_SNMP_STATS
|
|
switch (snmp->pdutype) {
|
|
case ASN1_TYPE_PDU_GET: snmp->STATS.ST_RX_GETREQ++; break;
|
|
case ASN1_TYPE_PDU_GETNEXT: snmp->STATS.ST_RX_GETNEXTREQ++; break;
|
|
case ASN1_TYPE_PDU_RESPONSE: snmp->STATS.ST_RX_RESPONSE++; break;
|
|
case ASN1_TYPE_PDU_SET: snmp->STATS.ST_RX_SETREQ++; break;
|
|
case ASN1_TYPE_PDU_TRAP: snmp->STATS.ST_RX_TRAP++; break;
|
|
case ASN1_TYPE_PDU_GETBULK: snmp->STATS.ST_RX_GETBULKREQ++; break;
|
|
case ASN1_TYPE_PDU_INFORM: snmp->STATS.ST_RX_INFORM++; break;
|
|
case ASN1_TYPE_PDU_TRAPV2: snmp->STATS.ST_RX_V2TRAP++; break;
|
|
case ASN1_TYPE_PDU_REPORT: snmp->STATS.ST_RX_REPORT++; break;
|
|
default: snmp->STATS.ST_RX_OTHER++; break;
|
|
} /* Endswitch */
|
|
#endif
|
|
|
|
switch (snmp->pdutype) {
|
|
case ASN1_TYPE_PDU_GET:
|
|
case ASN1_TYPE_PDU_GETNEXT:
|
|
case ASN1_TYPE_PDU_SET:
|
|
if (snmp->version > 1) {
|
|
IF_SNMP_STATS_ENABLED(snmp->STATS.ST_RX_BAD_VERSION++);
|
|
IF_SNMP_STATS_ENABLED(snmp->STATS.ST_RX_BAD_PARSE--); /* because SNMP_task will increment it */
|
|
return FALSE;
|
|
} /* Endif */
|
|
if (!SNMP_parse_pduv1(snmp)) return FALSE;
|
|
break;
|
|
case ASN1_TYPE_PDU_GETBULK:
|
|
if (snmp->version != 1) {
|
|
IF_SNMP_STATS_ENABLED(snmp->STATS.ST_RX_BAD_VERSION++);
|
|
IF_SNMP_STATS_ENABLED(snmp->STATS.ST_RX_BAD_PARSE--); /* because SNMP_task will increment it */
|
|
return FALSE;
|
|
} /* Endif */
|
|
if (!SNMP_parse_awesome_pdubulk(snmp)) return FALSE;
|
|
snmp->pdutype = ASN1_TYPE_PDU_GETNEXT;
|
|
break;
|
|
default:
|
|
IF_SNMP_STATS_ENABLED(snmp->STATS.ST_RX_BAD_PDU++);
|
|
IF_SNMP_STATS_ENABLED(snmp->STATS.ST_RX_BAD_PARSE--); /* because SNMP_task will increment it */
|
|
return FALSE;
|
|
} /* Endswitch */
|
|
|
|
if (!SNMP_parse_varbindlist(snmp, &typelen)) return FALSE;
|
|
|
|
ASN1_BKWRITE_TYPELEN (snmp, typelen, ASN1_TYPE_SEQUENCE, typelen);
|
|
ASN1_BKWRITE_TYPELEN_INT (snmp, typelen, 0);
|
|
ASN1_BKWRITE_TYPELEN_INT (snmp, typelen, 0);
|
|
ASN1_BKWRITE_TYPELEN_BYTES (snmp, typelen, ASN1_TYPE_INTEGER, idp, idlen);
|
|
ASN1_BKWRITE_TYPELEN (snmp, typelen, ASN1_TYPE_PDU_RESPONSE, typelen);
|
|
ASN1_BKWRITE_TYPELEN_BYTES (snmp, typelen, ASN1_TYPE_OCTET, ctyp, ctylen);
|
|
ASN1_BKWRITE_TYPELEN_INT (snmp, typelen, snmp->version);
|
|
ASN1_BKWRITE_TYPELEN (snmp, typelen, ASN1_TYPE_SEQUENCE, typelen);
|
|
|
|
*writelen = typelen;
|
|
return TRUE;
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : SNMP_init_with_traps
|
|
* Returned Value : error code
|
|
* Comments : Start the SNMP agent.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
uint_32 SNMP_init_with_traps
|
|
(
|
|
char_ptr name,
|
|
uint_32 priority,
|
|
uint_32 stacksize,
|
|
/* Address to an array of IP addresses, NULL terminated */
|
|
_ip_address _PTR_ traplist
|
|
)
|
|
{ /* Body */
|
|
return RTCS_task_create(name, priority, stacksize, SNMP_task, traplist);
|
|
} /* Endbody */
|
|
|
|
|
|
/*TASK*-----------------------------------------------------------------
|
|
*
|
|
* Function Name : SNMP_task
|
|
* Returned Value : none
|
|
* Comments : SNMP agent.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
void SNMP_task
|
|
(
|
|
pointer traps,
|
|
pointer creator
|
|
)
|
|
{ /* Body */
|
|
SNMP_PARSE snmp;
|
|
sockaddr_in addr;
|
|
uint_32 sock, error, count;
|
|
int_32 inlen, j;
|
|
uint_32 outlen,time;
|
|
uint_16 addrlen;
|
|
uint_32 option;
|
|
char_ptr community_array[] = SNMPCFG_COMMUNITY_LIST;
|
|
_ip_address _PTR_ trap_receiver_list_ptr = (_ip_address _PTR_)traps;
|
|
|
|
SNMP_CONTEXT snmp_context = { 0 };
|
|
|
|
SNMP_task_id = RTCS_task_getid();
|
|
#ifdef __MQX__
|
|
/* Set up exit handler and context so that we can clean up if the SNMP agent is terminated */
|
|
_task_set_environment( _task_get_id(), (pointer) &snmp_context );
|
|
_task_set_exit_handler( _task_get_id(), SNMP_Exit_handler );
|
|
#endif
|
|
|
|
/* SNMP agent services port 161 */
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = IPPORT_SNMP;
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
/* Bind to UDP port */
|
|
snmp_context.UDPSOCK = socket(PF_INET, SOCK_DGRAM, 0);
|
|
sock = snmp_context.UDPSOCK;
|
|
|
|
if (sock == RTCS_SOCKET_ERROR) {
|
|
RTCS_task_exit(creator, RTCSERR_OUT_OF_SOCKETS);
|
|
} /* Endif */
|
|
|
|
/* Begin ENGR00243356 */
|
|
/* Set socket options to no wait */
|
|
option = TRUE;
|
|
setsockopt(sock, SOL_UDP, OPT_SEND_NOWAIT, &option, sizeof(option));
|
|
/* End ENGR00243356 */
|
|
|
|
error = bind(sock, &addr, sizeof(addr));
|
|
if (error) {
|
|
RTCS_task_exit(creator, error);
|
|
} /* Endif */
|
|
|
|
IF_SNMP_STATS_ENABLED(_mem_zero(&snmp.STATS, sizeof(snmp.STATS)));
|
|
snmp.trapsock = sock;
|
|
|
|
snmp.currentcommunity = 0;
|
|
|
|
for (j = 0; j < SNMPCFG_NUM_COMMUNITY; j++) {
|
|
snmp.community[j] = community_array[j];
|
|
snmp.communitylen[j] = strlen((const char *)(community_array[j]));
|
|
} /* Endfor */
|
|
|
|
for (j = 0; j < SNMPCFG_MAX_TRAP_RECEIVERS; j++)
|
|
snmp.trap_receiver_list[j] = 0;
|
|
|
|
if(trap_receiver_list_ptr != NULL) {
|
|
count = 0;
|
|
while(*trap_receiver_list_ptr != 0 && count < SNMPCFG_MAX_TRAP_RECEIVERS) {
|
|
snmp.trap_receiver_list[count] = *trap_receiver_list_ptr;
|
|
trap_receiver_list_ptr++;
|
|
count++;
|
|
} /* Endwhile */
|
|
} /* Endif */
|
|
|
|
SNMP_set_data(&snmp);
|
|
|
|
RTCS_task_resume_creator(creator, RTCS_OK);
|
|
|
|
/* Send some traps -- but only if the application has added some traps receivers */
|
|
if (RTCS_count_trap_receivers_internal() != 0) {
|
|
SNMP_trap_select_community(snmp.community[0]);
|
|
time = RTCS_time_get();
|
|
if(time < 30) {
|
|
#ifdef SNMPCFG_SEND_V2_TRAPS
|
|
SNMPv2_trap_coldStart();
|
|
#else
|
|
SNMP_trap_coldStart();
|
|
#endif
|
|
} else {
|
|
#ifdef SNMPCFG_SEND_V2_TRAPS
|
|
SNMPv2_trap_warmStart();
|
|
#else
|
|
SNMP_trap_warmStart();
|
|
#endif
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
for (;;) {
|
|
|
|
addrlen = sizeof(addr);
|
|
inlen = recvfrom(sock, inbuf, SNMPCFG_BUFFER_SIZE, 0, &addr, &addrlen);
|
|
IF_SNMP_STATS_ENABLED(snmp.STATS.COMMON.ST_RX_TOTAL++);
|
|
|
|
snmp.inbuf = inbuf;
|
|
snmp.inlen = inlen;
|
|
snmp.outbuf = outbuf;
|
|
snmp.outlen = SNMPCFG_BUFFER_SIZE;
|
|
snmp.pdutype = 0; /* anything except ASN1_TYPE_PDU_SET */
|
|
snmp.errstat = SNMP_ERROR_noError;
|
|
snmp.errindex = 0;
|
|
if (SNMP_parse(&snmp, &outlen)) {
|
|
IF_SNMP_STATS_ENABLED(snmp.STATS.COMMON.ST_TX_TOTAL++);
|
|
IF_SNMP_STATS_ENABLED(snmp.STATS.ST_TX_RESPONSE++);
|
|
sendto(sock, snmp.outbuf, outlen, 0, &addr, addrlen);
|
|
} else if (snmp.errstat || snmp.pdutype == ASN1_TYPE_PDU_SET) {
|
|
if (snmp.errindex >= 0xFF) {
|
|
snmp.errstat = SNMP_ERROR_tooBig;
|
|
snmp.errindex = 0;
|
|
} /* Endif */
|
|
*snmp.errstatp = snmp.errstat;
|
|
*snmp.errindexp = snmp.errindex;
|
|
#if RTCSCFG_ENABLE_SNMP_STATS
|
|
snmp.STATS.COMMON.ST_TX_TOTAL++;
|
|
snmp.STATS.ST_TX_RESPONSE++;
|
|
switch (snmp.errstat) {
|
|
case SNMP_ERROR_noError: break;
|
|
case SNMP_ERROR_tooBig: snmp.STATS.ST_TX_TOOBIG++; break;
|
|
case SNMP_ERROR_noSuchName: snmp.STATS.ST_TX_NOSUCHNAME++; break;
|
|
case SNMP_ERROR_badValue: snmp.STATS.ST_TX_BADVALUE++; break;
|
|
case SNMP_ERROR_readOnly: snmp.STATS.ST_TX_READONLY++; break;
|
|
case SNMP_ERROR_genErr: snmp.STATS.ST_TX_GENERR++; break;
|
|
default: snmp.STATS.ST_TX_OTHER++; break;
|
|
} /* Endswitch */
|
|
#endif
|
|
sendto(sock, inbuf, inlen, 0, &addr, addrlen);
|
|
} else {
|
|
IF_SNMP_STATS_ENABLED(snmp.STATS.ST_RX_BAD_PARSE++);
|
|
IF_SNMP_STATS_ENABLED(snmp.STATS.COMMON.ST_RX_DISCARDED++);
|
|
} /* Endif */
|
|
|
|
} /* Endfor */
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : SNMP_Exit_handler
|
|
* Returned Value : error code
|
|
* Comments : Start the EDS task.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
void SNMP_Exit_handler( void )
|
|
{ /* Body */
|
|
SNMP_CONTEXT_PTR snmp_context_ptr;
|
|
|
|
snmp_context_ptr = (SNMP_CONTEXT_PTR) _task_get_environment( _task_get_id() );
|
|
if (snmp_context_ptr != NULL) {
|
|
if (snmp_context_ptr->UDPSOCK) {
|
|
shutdown(snmp_context_ptr->UDPSOCK, 0);
|
|
snmp_context_ptr->UDPSOCK = 0;
|
|
}
|
|
}
|
|
SNMP_task_id = 0;
|
|
} /* Endbody */
|
|
|
|
|
|
#endif /* RTCSCFG_ENABLE_IP4 */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : SNMP_init
|
|
* Returned Value : error code
|
|
* Comments : Start the SNMP agent.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
uint_32 SNMP_init
|
|
(
|
|
char_ptr name,
|
|
uint_32 priority,
|
|
uint_32 stacksize
|
|
)
|
|
{ /* Body */
|
|
|
|
#if RTCSCFG_ENABLE_IP4
|
|
|
|
if (SNMP_task_id == 0) {
|
|
return RTCS_task_create(name, priority, stacksize, SNMP_task, NULL);
|
|
} else {
|
|
return RTCSERR_SERVER_ALREADY_RUNNING;
|
|
}
|
|
#else
|
|
|
|
return RTCSERR_IP_IS_DISABLED;
|
|
|
|
#endif /* RTCSCFG_ENABLE_IP4 */
|
|
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : SNMP_stop
|
|
* Returned Value : error code
|
|
* Comments : Start the EDS task.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
uint_32 SNMP_stop( void )
|
|
{ /* Body */
|
|
|
|
#if RTCSCFG_ENABLE_IP4
|
|
|
|
if (SNMP_task_id == 0) {
|
|
return RTCSERR_SERVER_NOT_RUNNING;
|
|
}
|
|
RTCS_task_abort(SNMP_task_id);
|
|
SNMP_task_id = 0;
|
|
return RTCS_OK;
|
|
|
|
#else
|
|
|
|
return RTCSERR_IP_IS_DISABLED;
|
|
|
|
#endif /* RTCSCFG_ENABLE_IP4 */
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
#endif /* RTCSCFG_ENABLE_SNMP && RTCSCFG_ENABLE_UDP */
|
|
/* EOF */
|