2 //=============================================================================
6 * Adapter class. Converts between raw wire format and Pdu objects
7 * that can be stuffed out a I/O port or reconstructed
9 * @author Michael R. MacFaden rework the class api and impl using ACEPeter E Mellquist implementation/code from snmp++ snmpmsg class
11 //=============================================================================
14 #include "asnmp/wpdu.h"
15 #include "ace/Log_Msg.h"
16 #include "ace/OS_NS_string.h"
17 #include "ace/OS_NS_stdio.h"
19 #define DEFINE_TRAP_CONSTANTS_
20 #include "asnmp/enttraps.h"
22 #define MAX_COMM_STR_LEN 255
23 #define V1_COLD_START 0
24 #define V1_WARM_START 1
25 #define V1_LINK_DOWN 2
27 #define V1_AUTH_FAILURE 4
28 #define V1_EGP_NEIGHBOR_LOSS 5
29 #define V1_ENT_SPECIFIC 6
32 void reset_iov(iovec
& iov
)
38 wpdu::wpdu(const Pdu
& pdu
, const UdpTarget
& target
):
39 valid_flag_(SNMP_CLASS_INVALID
), comm_len(MAX_COMM_STR_LEN
)
42 version_
= target
.get_version();
46 community_name
[0] = 0;
48 snmp_pdu
*raw_pdu
; // create a raw pdu
49 raw_pdu
= cmu_snmp::pdu_create( (int) pdu
.get_type());
51 valid_flag_
= SNMP_CLASS_RESOURCE_UNAVAIL
;
55 raw_pdu
->reqid
= pdu
.get_request_id();
56 raw_pdu
->errstat
= (unsigned long) pdu
.get_error_status();
57 raw_pdu
->errindex
= (unsigned long) pdu
.get_error_index();
59 switch (raw_pdu
->command
) {
61 case sNMP_PDU_GETNEXT
:
62 target
.get_read_community(comm_str
);
66 target
.get_write_community(comm_str
);
70 target
.get_read_community(comm_str
);
71 if (set_trap_info(raw_pdu
, pdu
)) // will free raw_pdu
74 case sNMP_PDU_RESPONSE
:
82 if (load_vbs(raw_pdu
, pdu
)) {
83 cmu_snmp::free_pdu( raw_pdu
);
84 valid_flag_
= SNMP_CLASS_RESOURCE_UNAVAIL
;
88 // TODO: determine how big raw_pdu serializes out to
89 iovec_
.iov_len
= target
.get_max_pdu_size();
90 ACE_NEW(iovec_
.iov_base
, char [iovec_
.iov_len
]);
92 // create raw byte stream
93 // The intermediate integer is to avoid type-punned pointer
95 int out_length
= iovec_
.iov_len
;
96 status
= cmu_snmp::build( raw_pdu
,
97 (unsigned char *)iovec_
.iov_base
,
102 iovec_
.iov_len
= out_length
;
105 valid_flag_
= SNMP_ERROR_WRONG_ENCODING
;
106 cmu_snmp::free_pdu( raw_pdu
);
110 cmu_snmp::free_pdu( raw_pdu
);
111 valid_flag_
= SNMP_CLASS_SUCCESS
;
114 int wpdu::set_trap_info(snmp_pdu
*raw_pdu
, const Pdu
& pdu
) const
117 Oid trapid
; // validate caller has set this correctly
118 pdu
.get_notify_id( trapid
);
119 if ( !trapid
.valid() || trapid
.length() < 2 ) {
120 cmu_snmp::free_pdu( raw_pdu
);
121 return SNMP_CLASS_INVALID_NOTIFYID
;
124 raw_pdu
->specific_type
=0;
126 // TODO: object should emit numeric instead of this kind of mess...
127 if ( trapid
== coldStart
)
128 raw_pdu
->trap_type
= V1_COLD_START
; // cold start
129 else if ( trapid
== warmStart
)
130 raw_pdu
->trap_type
= V1_WARM_START
; // warm start
131 else if( trapid
== linkDown
)
132 raw_pdu
->trap_type
= V1_LINK_DOWN
; // link down
133 else if ( trapid
== linkUp
)
134 raw_pdu
->trap_type
= V1_LINK_UP
; // link up
135 else if ( trapid
== authenticationFailure
)
136 raw_pdu
->trap_type
= V1_AUTH_FAILURE
; // authentication failure
137 else if ( trapid
== egpNeighborLoss
)
138 raw_pdu
->trap_type
= V1_EGP_NEIGHBOR_LOSS
; // egp neighbor loss
140 raw_pdu
->trap_type
= V1_ENT_SPECIFIC
; // enterprise specific
141 // last oid subid is the specific value
142 // if 2nd to last subid is "0", remove it
143 // enterprise is always the notify oid prefix
144 raw_pdu
->specific_type
= (int) trapid
[(int) (trapid
.length() - 1)];
146 if ( trapid
[(int)(trapid
.length() - 1)] == 0 )
151 if ( raw_pdu
->trap_type
!= V1_ENT_SPECIFIC
)
152 pdu
.get_notify_enterprise( enterprise
);
153 if ( enterprise
.length() > 0) {
154 // note!! To the contrary, enterprise OID val is
155 // copied here and raw_pdu->enterprise is freed in free_pdu
156 // as it should be (HDN)
157 // these are hooks into an SNMP++ oid
158 // and therefor the raw_pdu enterprise
159 // should not free them. null them out!!
161 rawOid
= enterprise
.oidval();
162 // HDN - enterprise is a local object, cannot simply assign pointer
163 //raw_pdu->enterprise = rawOid->ptr;
164 raw_pdu
->enterprise_length
= (int) rawOid
->len
;
165 ACE_NEW_RETURN(raw_pdu
->enterprise
,
166 oid
[raw_pdu
->enterprise_length
],-1);
167 ACE_OS::memcpy((char *)raw_pdu
->enterprise
,(char *)rawOid
->ptr
,
168 raw_pdu
->enterprise_length
* sizeof(oid
));
172 pdu
.get_notify_timestamp( timestamp
);
173 raw_pdu
->time
= ( unsigned long) timestamp
;
175 // HDN - set agent addr using the local hostname if possible
176 char localHostName
[MAXHOSTNAMELEN
];
177 Snmp::get_host_name(localHostName
, MAXHOSTNAMELEN
);
178 if (ACE_OS::strlen(localHostName
) > 0) {
179 GenAddress
addr(localHostName
);
181 addr
.to_octet(octet
);
182 ACE_OS::memcpy(&(raw_pdu
->agent_addr
.sin_addr
),
190 wpdu::wpdu(const iovec
& iov
): valid_flag_(0),comm_len(MAX_COMM_STR_LEN
)
192 community_name
[0] = 0;
194 version_
= version1
; // TODO: figure where this should come from
195 ACE_NEW(iovec_
.iov_base
, char[iov
.iov_len
]);
196 if (!iovec_
.iov_base
) {
197 valid_flag_
= SNMP_CLASS_RESOURCE_UNAVAIL
;
201 copy_iovec(iovec_
, iov
);
202 valid_flag_
= SNMP_CLASS_SUCCESS
;
205 wpdu::wpdu(): valid_flag_(0), comm_len(MAX_COMM_STR_LEN
)
207 community_name
[0] = 0;
209 version_
= version1
; // TODO: figure where this should come from
212 int wpdu::valid() const
214 return (valid_flag_
== SNMP_CLASS_SUCCESS
);
217 int wpdu::load_vbs(snmp_pdu
*raw_pdu
, const Pdu
& pdu
)
221 // load up the payload
222 // for all Vbs in list, add them to the pdu
229 vb_count
= pdu
.get_vb_count();
231 for (int z
= 0; z
< vb_count
; z
++) {
232 pdu
.get_vb( tempvb
, z
);
233 tempvb
.get_oid( tempoid
);
234 smioid
= tempoid
.oidval();
235 // what are we trying to convert here (vb oid part or value part)
236 status
= convert_vb_to_smival( tempvb
, &smival
);
237 if ( status
!= SNMP_CLASS_SUCCESS
)
240 // add the var to the raw pdu
241 cmu_snmp::add_var(raw_pdu
, smioid
->ptr
, (int) smioid
->len
, &smival
);
242 free_smival_descriptor( &smival
);
248 // supports overlapped copies
250 void wpdu::copy_iovec(iovec
& dest
, const iovec
& src
)
255 ACE_OS::memmove( dest
.iov_base
, src
.iov_base
, src
.iov_len
);
256 dest
.iov_len
= src
.iov_len
;
259 int wpdu::convert_vb_to_smival( Vb
&tempvb
, SmiVALUE
*smival
)
261 smival
->syntax
= tempvb
.get_syntax();
263 switch ( smival
->syntax
) {
264 case sNMP_SYNTAX_NULL
:
267 // case sNMP_SYNTAX_INT32:
268 case sNMP_SYNTAX_INT
:
271 tempvb
.get_value(tmp
);
272 smival
->value
.sNumber
= tmp
;
276 // case sNMP_SYNTAX_UINT32:
277 case sNMP_SYNTAX_GAUGE32
:
278 case sNMP_SYNTAX_CNTR32
:
279 case sNMP_SYNTAX_TIMETICKS
:
282 tempvb
.get_value(tmp
);
283 smival
->value
.uNumber
= tmp
;
288 case sNMP_SYNTAX_CNTR64
:
291 tempvb
.get_value(c64
);
292 smival
->value
.hNumber
.hipart
= c64
.high();
293 smival
->value
.hNumber
.lopart
= c64
.low();
298 case sNMP_SYNTAX_OID
:
302 tempvb
.get_value(tmpoid
);
303 SmiLPOID smi
= tmpoid
.oidval();
304 smival
->value
.oid
.len
= tmpoid
.length();
305 ACE_NEW_RETURN(smival
->value
.oid
.ptr
,
306 SmiUINT32
[smival
->value
.oid
.len
], 1);
307 ACE_OS::memcpy(smival
->value
.oid
.ptr
, smi
->ptr
,
308 smival
->value
.oid
.len
*sizeof(SmiUINT32
));
312 case sNMP_SYNTAX_BITS
:
313 case sNMP_SYNTAX_OCTETS
:
314 case sNMP_SYNTAX_IPADDR
:
317 tempvb
.get_value(os
);
318 smival
->value
.string
.ptr
= 0;
319 smival
->value
.string
.len
= os
.length();
320 if ( smival
->value
.string
.len
> 0 ) {
321 ACE_NEW_RETURN(smival
->value
.string
.ptr
,
322 SmiBYTE
[smival
->value
.string
.len
], 1);
323 if ( smival
->value
.string
.ptr
) {
324 for (int i
=0; i
<(int) smival
->value
.string
.len
; i
++)
325 smival
->value
.string
.ptr
[i
] = os
[i
];
328 smival
->syntax
= sNMP_SYNTAX_NULL
; // invalidate the smival
329 return SNMP_CLASS_RESOURCE_UNAVAIL
;
336 ACE_DEBUG((LM_DEBUG
, "wpdu::convert_vb_to_smival did not convert vb\n"));
344 void wpdu::free_smival_descriptor( SmiVALUE
*smival
)
346 switch ( smival
->syntax
) {
347 case sNMP_SYNTAX_OCTETS
:
348 case sNMP_SYNTAX_OPAQUE
:
349 case sNMP_SYNTAX_IPADDR
:
350 case sNMP_SYNTAX_BITS
: // obsoleted in SNMPv2 Draft Std
351 delete [] smival
->value
.string
.ptr
;
354 case sNMP_SYNTAX_OID
:
355 delete [] smival
->value
.oid
.ptr
;
358 smival
->syntax
= sNMP_SYNTAX_NULL
;
364 delete [] (char*) iovec_
.iov_base
;
367 const iovec
& wpdu::get_buffer() const
372 // return a pdu from a buffer
373 int wpdu::get_pdu(Pdu
& pdu
, snmp_version
& version
)
375 if (iovec_
.iov_len
== 0)
376 return -1; // NO DATA
378 snmp_pdu
*raw_pdu
= cmu_snmp::pdu_create(0);
380 return SNMP_CLASS_RESOURCE_UNAVAIL
;
383 // max value a client can send us - TODO: replace this with an
384 // api to get actual string length
385 int status
= cmu_snmp::parse( raw_pdu
, (unsigned char *)iovec_
.iov_base
,
386 community_name
, comm_len
,
387 version
, iovec_
.iov_len
);
389 return SNMP_CLASS_INTERNAL_ERROR
;
391 community_name
[comm_len
] = 0; // set null based on returned length
392 set_request_id( &pdu
, raw_pdu
->reqid
);
393 set_error_status( &pdu
, (int) raw_pdu
->errstat
);
394 set_error_index( &pdu
, (int) raw_pdu
->errindex
);
395 pdu
.set_type( raw_pdu
->command
);
397 if (restore_vbs(pdu
, raw_pdu
)) {
398 cmu_snmp::free_pdu(raw_pdu
);
399 return SNMP_CLASS_INTERNAL_ERROR
;
402 cmu_snmp::free_pdu(raw_pdu
);
406 int wpdu::restore_vbs(Pdu
& pdu
, const snmp_pdu
*raw_pdu
) const
410 struct variable_list
*vp
;
412 for(vp
= raw_pdu
->variables
; vp
; vp
= vp
->next_variable
) {
413 // extract the oid portion
414 tempoid
.set_data( (unsigned long *)vp
->name
,
415 ( unsigned int) vp
->name_length
);
416 tempvb
.set_oid( tempoid
);
418 // extract the value portion
421 case sNMP_SYNTAX_OCTETS
:
422 case sNMP_SYNTAX_OPAQUE
:
424 OctetStr
octets( (char *) vp
->val
.string
,
426 tempvb
.set_value( octets
);
431 case sNMP_SYNTAX_OID
:
433 Oid
oid( (unsigned long*) vp
->val
.objid
,
435 tempvb
.set_value( oid
);
440 case sNMP_SYNTAX_TIMETICKS
:
442 TimeTicks
timeticks( (unsigned long) *(vp
->val
.integer
));
443 tempvb
.set_value( timeticks
);
448 case sNMP_SYNTAX_GAUGE32
:
450 Gauge32
gauge32( (unsigned long) *(vp
->val
.integer
));
451 tempvb
.set_value( gauge32
);
456 case sNMP_SYNTAX_CNTR32
:
458 Counter32
counter32( (unsigned long) *(vp
->val
.integer
));
459 tempvb
.set_value( counter32
);
464 case sNMP_SYNTAX_IPADDR
:
467 ACE_OS::sprintf( buffer
,"%d.%d.%d.%d",
472 IpAddress
ipaddress( buffer
);
473 tempvb
.set_value( ipaddress
);
478 case sNMP_SYNTAX_INT
:
480 SnmpInt32
int32( (long) *(vp
->val
.integer
));
481 tempvb
.set_value( int32
);
485 // 32 bit unsigned integer
486 case sNMP_SYNTAX_UINT32
:
488 SnmpUInt32
uint32( (unsigned long) *(vp
->val
.integer
));
489 tempvb
.set_value( uint32
);
494 case sNMP_SYNTAX_CNTR64
:
497 case sNMP_SYNTAX_NULL
:
502 case sNMP_SYNTAX_NOSUCHOBJECT
:
503 case sNMP_SYNTAX_NOSUCHINSTANCE
:
504 case sNMP_SYNTAX_ENDOFMIBVIEW
:
505 set_exception_status( &tempvb
, vp
->type
);
512 // append the vb to the pdu
519 const unsigned char *wpdu::get_community() const
521 return community_name
;