1 //==========================================================================
3 // ./agent/current/src/agent_trap.c
6 //==========================================================================
7 //####ECOSGPLCOPYRIGHTBEGIN####
8 // -------------------------------------------
9 // This file is part of eCos, the Embedded Configurable Operating System.
10 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // eCos is free software; you can redistribute it and/or modify it under
13 // the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 2 or (at your option) any later version.
16 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 // You should have received a copy of the GNU General Public License along
22 // with eCos; if not, write to the Free Software Foundation, Inc.,
23 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 // As a special exception, if other files instantiate templates or use macros
26 // or inline functions from this file, or you compile this file and link it
27 // with other works to produce a work based on this file, this file does not
28 // by itself cause the resulting work to be covered by the GNU General Public
29 // License. However the source code for this file must still be made available
30 // in accordance with section (3) of the GNU General Public License.
32 // This exception does not invalidate any other reasons why a work based on
33 // this file might be covered by the GNU General Public License.
35 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
36 // at http://sources.redhat.com/ecos/ecos-license/
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //####UCDSNMPCOPYRIGHTBEGIN####
41 // -------------------------------------------
43 // Portions of this software may have been derived from the UCD-SNMP
44 // project, <http://ucd-snmp.ucdavis.edu/> from the University of
45 // California at Davis, which was originally based on the Carnegie Mellon
46 // University SNMP implementation. Portions of this software are therefore
47 // covered by the appropriate copyright disclaimers included herein.
49 // The release used was version 4.1.2 of May 2000. "ucd-snmp-4.1.2"
50 // -------------------------------------------
52 //####UCDSNMPCOPYRIGHTEND####
53 //==========================================================================
54 //#####DESCRIPTIONBEGIN####
59 // Purpose: Port of UCD-SNMP distribution to eCos.
63 //####DESCRIPTIONEND####
65 //==========================================================================
66 /********************************************************************
67 Copyright 1989, 1991, 1992 by Carnegie Mellon University
70 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
74 Permission to use, copy, modify and distribute this software and its
75 documentation for any purpose and without fee is hereby granted,
76 provided that the above copyright notice appears in all copies and
77 that both that copyright notice and this permission notice appear in
78 supporting documentation, and that the name of CMU and The Regents of
79 the University of California not be used in advertising or publicity
80 pertaining to distribution of the software without specific written
83 CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
84 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
85 WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CMU OR
86 THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
87 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
88 FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
89 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
90 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
91 *********************************************************************/
92 /* agent_trap.c: define trap generation routines for mib modules, etc,
108 #if TIME_WITH_SYS_TIME
110 # include <sys/timeb.h>
112 # include <sys/time.h>
117 # include <sys/time.h>
122 #if HAVE_SYS_SOCKET_H
123 #include <sys/socket.h>
127 #if HAVE_NETINET_IN_H
128 #include <netinet/in.h>
132 #include "snmp_api.h"
133 #include "snmp_impl.h"
134 #include "snmp_client.h"
137 #include "read_config.h"
138 #include "snmp_debug.h"
141 struct snmp_session *sesp;
142 struct trap_sink *next;
147 struct trap_sink *sinks = NULL;
149 extern struct timeval starttime;
151 #define OID_LENGTH(x) (sizeof(x)/sizeof(x[0]))
153 oid objid_enterprisetrap[] = { EXTENSIBLEMIB, 251 };
154 oid version_id[] = { EXTENSIBLEMIB, AGENTID, OSTYPE };
155 int enterprisetrap_len = OID_LENGTH( objid_enterprisetrap );
156 int version_id_len = OID_LENGTH( version_id );
158 #define SNMPV2_TRAPS_PREFIX SNMP_OID_SNMPMODULES,1,1,5
159 oid cold_start_oid[] = { SNMPV2_TRAPS_PREFIX, 1 }; /* SNMPv2-MIB */
160 oid warm_start_oid[] = { SNMPV2_TRAPS_PREFIX, 2 }; /* SNMPv2-MIB */
161 oid link_down_oid[] = { SNMPV2_TRAPS_PREFIX, 3 }; /* IF-MIB */
162 oid link_up_oid[] = { SNMPV2_TRAPS_PREFIX, 4 }; /* IF-MIB */
163 oid auth_fail_oid[] = { SNMPV2_TRAPS_PREFIX, 5 }; /* SNMPv2-MIB */
164 oid egp_xxx_oid[] = { SNMPV2_TRAPS_PREFIX, 99 }; /* ??? */
166 #define SNMPV2_TRAP_OBJS_PREFIX SNMP_OID_SNMPMODULES,1,1,4
167 oid snmptrap_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 1, 0 };
168 oid snmptrapenterprise_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 3, 0 };
169 oid sysuptime_oid[] = { SNMP_OID_MIB2,1,3,0 };
170 int snmptrap_oid_len = OID_LENGTH(snmptrap_oid);
171 int snmptrapenterprise_oid_len = OID_LENGTH(snmptrapenterprise_oid);
172 int sysuptime_oid_len = OID_LENGTH(sysuptime_oid);
175 #define SNMP_AUTHENTICATED_TRAPS_ENABLED 1
176 #define SNMP_AUTHENTICATED_TRAPS_DISABLED 2
178 int snmp_enableauthentraps = SNMP_AUTHENTICATED_TRAPS_DISABLED;
179 char *snmp_trapcommunity = NULL;
183 static int create_v1_trap_session (const char *, u_short, const char *);
184 static int create_v2_trap_session (const char *, u_short, const char *);
185 static int create_v2_inform_session (const char *, u_short, const char *);
186 static void free_trap_session (struct trap_sink *sp);
187 static void send_v1_trap (struct snmp_session *, int, int);
188 static void send_v2_trap (struct snmp_session *, int, int, int);
194 * Trap session handling
197 int add_trap_session( struct snmp_session *ss, int pdutype, int version )
199 struct trap_sink *new_sink =
200 (struct trap_sink *) malloc (sizeof (*new_sink));
201 if ( new_sink == NULL )
205 new_sink->pdutype = pdutype;
206 new_sink->version = version;
207 new_sink->next = sinks;
212 int create_trap_session (char *sink, u_short sinkport,
214 int version, int pdutype)
216 struct snmp_session session, *sesp;
218 memset (&session, 0, sizeof (struct snmp_session));
219 session.peername = sink;
220 session.version = version;
222 session.community = (u_char *)com;
223 session.community_len = strlen (com);
225 session.remote_port = sinkport;
226 sesp = snmp_open (&session);
229 return( add_trap_session( sesp, pdutype, version ));
232 /* diagnose snmp_open errors with the input struct snmp_session pointer */
233 snmp_sess_perror("snmpd: create_trap_session", &session);
237 static int create_v1_trap_session (char *sink, u_short sinkport,
240 return create_trap_session( sink, sinkport, com,
241 SNMP_VERSION_1, SNMP_MSG_TRAP );
244 static int create_v2_trap_session (char *sink, u_short sinkport,
247 return create_trap_session( sink, sinkport, com,
248 SNMP_VERSION_2c, SNMP_MSG_TRAP2 );
251 static int create_v2_inform_session (char *sink, u_short sinkport,
254 return create_trap_session( sink, sinkport, com,
255 SNMP_VERSION_2c, SNMP_MSG_INFORM );
259 static void free_trap_session (struct trap_sink *sp)
261 snmp_close(sp->sesp);
266 void snmpd_free_trapsinks (void)
268 struct trap_sink *sp = sinks;
271 free_trap_session(sp);
282 void send_enterprise_trap_vars (int trap,
284 oid *enterprise, int enterprise_length,
285 struct variable_list *vars)
287 struct variable_list uptime_var, snmptrap_var, enterprise_var;
288 struct variable_list *v2_vars, *last_var=NULL;
289 struct snmp_pdu *template_pdu, *pdu;
292 struct sockaddr_in *pduIp;
293 struct trap_sink *sink;
294 oid temp_oid[MAX_OID_LEN];
297 * Initialise SNMPv2 required variables
299 gettimeofday(&now, NULL);
300 uptime = calculate_time_diff(&now, &starttime);
301 memset (&uptime_var, 0, sizeof (struct variable_list));
302 snmp_set_var_objid( &uptime_var, sysuptime_oid, OID_LENGTH(sysuptime_oid));
303 snmp_set_var_value( &uptime_var, (u_char *)&uptime, sizeof(uptime) );
304 uptime_var.type = ASN_TIMETICKS;
305 uptime_var.next_variable = &snmptrap_var;
307 memset (&snmptrap_var, 0, sizeof (struct variable_list));
308 snmp_set_var_objid( &snmptrap_var, snmptrap_oid, OID_LENGTH(snmptrap_oid));
309 /* value set later .... */
310 snmptrap_var.type = ASN_OBJECT_ID;
312 snmptrap_var.next_variable = vars;
314 snmptrap_var.next_variable = &enterprise_var;
316 /* find end of provided varbind list,
317 ready to append the enterprise info if necessary */
319 while ( last_var && last_var->next_variable )
320 last_var = last_var->next_variable;
322 memset (&enterprise_var, 0, sizeof (struct variable_list));
323 snmp_set_var_objid( &enterprise_var,
324 snmptrapenterprise_oid, OID_LENGTH(snmptrapenterprise_oid));
325 snmp_set_var_value( &enterprise_var, (u_char *)enterprise, enterprise_length*sizeof(oid));
326 enterprise_var.type = ASN_OBJECT_ID;
327 enterprise_var.next_variable = NULL;
329 v2_vars = &uptime_var;
332 * Create a template PDU, ready for sending
334 template_pdu = snmp_pdu_create( SNMP_MSG_TRAP );
335 if ( template_pdu == NULL ) {
336 /* Free memory if value stored dynamically */
337 snmp_set_var_value( &enterprise_var, NULL, 0);
340 template_pdu->trap_type = trap;
341 template_pdu->specific_type = specific;
342 if ( snmp_clone_mem((void **)&template_pdu->enterprise,
343 enterprise, enterprise_length*sizeof(oid))) {
344 snmp_free_pdu( template_pdu );
345 snmp_set_var_value( &enterprise_var, NULL, 0);
348 template_pdu->enterprise_length = enterprise_length;
349 template_pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY;
350 pduIp = (struct sockaddr_in *)&template_pdu->agent_addr;
351 pduIp->sin_family = AF_INET;
352 pduIp->sin_len = sizeof(*pduIp);
353 pduIp->sin_addr.s_addr = get_myaddr();
354 template_pdu->time = uptime;
357 * Now use the parameters to determine
358 * which v2 variables are needed,
359 * and what values they should take.
364 * Check to see whether the variables provided
365 * are sufficient for SNMPv2 notifications
367 if (vars && snmp_oid_compare(vars->name, vars->name_length,
368 sysuptime_oid, OID_LENGTH(sysuptime_oid)) == 0 )
371 if (vars && snmp_oid_compare(vars->name, vars->name_length,
372 snmptrap_oid, OID_LENGTH(snmptrap_oid)) == 0 )
373 uptime_var.next_variable = vars;
375 /* Hmmm... we don't seem to have a value - oops! */
376 snmptrap_var.next_variable = vars;
378 last_var = NULL; /* Don't need enterprise info */
381 /* "Standard" SNMPv1 traps */
383 case SNMP_TRAP_COLDSTART:
384 snmp_set_var_value( &snmptrap_var,
385 (u_char *)cold_start_oid,
386 sizeof(cold_start_oid));
388 case SNMP_TRAP_WARMSTART:
389 snmp_set_var_value( &snmptrap_var,
390 (u_char *)warm_start_oid,
391 sizeof(warm_start_oid));
393 case SNMP_TRAP_LINKDOWN:
394 snmp_set_var_value( &snmptrap_var,
395 (u_char *)link_down_oid,
396 sizeof(link_down_oid));
398 case SNMP_TRAP_LINKUP:
399 snmp_set_var_value( &snmptrap_var,
400 (u_char *)link_up_oid,
401 sizeof(link_up_oid));
403 case SNMP_TRAP_AUTHFAIL:
404 if (snmp_enableauthentraps == SNMP_AUTHENTICATED_TRAPS_DISABLED) {
405 snmp_free_pdu( template_pdu );
406 snmp_set_var_value( &enterprise_var, NULL, 0);
409 snmp_set_var_value( &snmptrap_var,
410 (u_char *)auth_fail_oid,
411 sizeof(auth_fail_oid));
413 case SNMP_TRAP_EGPNEIGHBORLOSS:
414 snmp_set_var_value( &snmptrap_var,
415 (u_char *)egp_xxx_oid,
416 sizeof(egp_xxx_oid));
419 case SNMP_TRAP_ENTERPRISESPECIFIC:
422 (enterprise_length)*sizeof(oid));
423 temp_oid[ enterprise_length ] = 0;
424 temp_oid[ enterprise_length+1 ] = specific;
425 snmp_set_var_value( &snmptrap_var,
427 (enterprise_length+2)*sizeof(oid));
428 snmptrap_var.next_variable = vars;
429 last_var = NULL; /* Don't need version info */
435 * Now loop through the list of trap sinks,
436 * sending an appropriately formatted PDU to each
438 for ( sink = sinks ; sink ; sink=sink->next ) {
439 if ( sink->version == SNMP_VERSION_1 && trap == -1 )
440 continue; /* Skip v1 sinks for v2 only traps */
441 template_pdu->version = sink->version;
442 template_pdu->command = sink->pdutype;
443 if ( sink->version != SNMP_VERSION_1 ) {
444 template_pdu->variables = v2_vars;
446 last_var->next_variable = &enterprise_var;
449 template_pdu->variables = vars;
451 pdu = snmp_clone_pdu( template_pdu );
452 pdu->sessid = sink->sesp->sessid; /* AgentX only ? */
453 if ( snmp_send( sink->sesp, pdu) == 0 ) {
454 snmp_sess_perror ("snmpd: send_trap", sink->sesp);
455 snmp_free_pdu( pdu );
458 snmp_increment_statistic(STAT_SNMPOUTTRAPS);
459 snmp_increment_statistic(STAT_SNMPOUTPKTS);
462 if ( sink->version != SNMP_VERSION_1 && last_var )
463 last_var->next_variable = NULL;
466 /* Free memory if values stored dynamically */
467 snmp_set_var_value( &enterprise_var, NULL, 0);
468 snmp_set_var_value( &snmptrap_var, NULL, 0);
469 /* Ensure we don't free anything we shouldn't */
471 last_var->next_variable = NULL;
472 template_pdu->variables = NULL;
473 snmp_free_pdu( template_pdu );
476 void send_trap_vars (int trap,
478 struct variable_list *vars)
480 if ( trap == SNMP_TRAP_ENTERPRISESPECIFIC )
481 send_enterprise_trap_vars( trap, specific, objid_enterprisetrap,
482 OID_LENGTH(objid_enterprisetrap), vars );
484 send_enterprise_trap_vars( trap, specific, version_id,
485 OID_LENGTH(version_id), vars );
488 void send_easy_trap (int trap,
491 send_trap_vars( trap, specific, NULL );
494 void send_v2trap ( struct variable_list *vars)
496 send_trap_vars( -1, -1, vars );
500 send_trap_pdu(struct snmp_pdu *pdu)
502 send_trap_vars( -1, -1, pdu->variables );
509 * Config file handling
513 void snmpd_parse_config_authtrap(const char *token,
520 if ( !strcmp( cptr, "enable" ))
521 i = SNMP_AUTHENTICATED_TRAPS_ENABLED;
522 else if ( !strcmp( cptr, "disable" ))
523 i = SNMP_AUTHENTICATED_TRAPS_DISABLED;
526 config_perror("authtrapenable must be 1 or 2");
528 snmp_enableauthentraps = i;
531 void snmpd_parse_config_trapsink(const char *token,
535 char *sp, *cp, *pp = NULL;
538 if (!snmp_trapcommunity) snmp_trapcommunity = strdup("public");
539 sp = strtok(cptr, " \t\n");
540 cp = strtok(NULL, " \t\n");
541 if (cp) pp = strtok(NULL, " \t\n");
544 if ((sinkport < 1) || (sinkport > 0xffff)) {
545 config_perror("trapsink port out of range");
546 sinkport = SNMP_TRAP_PORT;
549 sinkport = SNMP_TRAP_PORT;
551 if (create_v1_trap_session(sp, sinkport,
552 cp ? cp : snmp_trapcommunity) == 0) {
553 sprintf(tmpbuf,"cannot create trapsink: %s", cptr);
554 config_perror(tmpbuf);
560 snmpd_parse_config_trap2sink(const char *word, char *cptr)
563 char *sp, *cp, *pp = NULL;
566 if (!snmp_trapcommunity) snmp_trapcommunity = strdup("public");
567 sp = strtok(cptr, " \t\n");
568 cp = strtok(NULL, " \t\n");
569 if (cp) pp = strtok(NULL, " \t\n");
572 if ((sinkport < 1) || (sinkport > 0xffff)) {
573 config_perror("trapsink port out of range");
574 sinkport = SNMP_TRAP_PORT;
577 sinkport = SNMP_TRAP_PORT;
579 if (create_v2_trap_session(sp, sinkport,
580 cp ? cp : snmp_trapcommunity) == 0) {
581 sprintf(tmpbuf,"cannot create trap2sink: %s", cptr);
582 config_perror(tmpbuf);
587 snmpd_parse_config_informsink(const char *word, char *cptr)
590 char *sp, *cp, *pp = NULL;
593 if (!snmp_trapcommunity) snmp_trapcommunity = strdup("public");
594 sp = strtok(cptr, " \t\n");
595 cp = strtok(NULL, " \t\n");
596 if (cp) pp = strtok(NULL, " \t\n");
599 if ((sinkport < 1) || (sinkport > 0xffff)) {
600 config_perror("trapsink port out of range");
601 sinkport = SNMP_TRAP_PORT;
604 sinkport = SNMP_TRAP_PORT;
606 if (create_v2_inform_session(sp, sinkport,
607 cp ? cp : snmp_trapcommunity) == 0) {
608 sprintf(tmpbuf,"cannot create informsink: %s", cptr);
609 config_perror(tmpbuf);
614 snmpd_parse_config_trapcommunity(const char *word, char *cptr)
616 if (snmp_trapcommunity) free(snmp_trapcommunity);
617 snmp_trapcommunity = malloc (strlen(cptr)+1);
618 copy_word(cptr, snmp_trapcommunity);
621 void snmpd_free_trapcommunity (void)
623 if (snmp_trapcommunity) {
624 free(snmp_trapcommunity);
625 snmp_trapcommunity = NULL;