and added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / agent_trap.c
1 /*
2  * agent_trap.c: define trap generation routines for mib modules, etc,
3  * to use 
4  */
5
6 #include <net-snmp/net-snmp-config.h>
7
8 #if HAVE_UNISTD_H
9 #include <unistd.h>
10 #endif
11 #if HAVE_NETDB_H
12 #include <netdb.h>
13 #endif
14 #if HAVE_STDLIB_H
15 #include <stdlib.h>
16 #endif
17 #if HAVE_STRING_H
18 #include <string.h>
19 #else
20 #include <strings.h>
21 #endif
22 #if TIME_WITH_SYS_TIME
23 # ifdef WIN32
24 #  include <sys/timeb.h>
25 # else
26 #  include <sys/time.h>
27 # endif
28 # include <time.h>
29 #else
30 # if HAVE_SYS_TIME_H
31 #  include <sys/time.h>
32 # else
33 #  include <time.h>
34 # endif
35 #endif
36 #if HAVE_SYS_SOCKET_H
37 #include <sys/socket.h>
38 #elif HAVE_WINSOCK_H
39 #include <winsock.h>
40 #endif
41 #if HAVE_NETINET_IN_H
42 #include <netinet/in.h>
43 #endif
44 #include <net-snmp/utilities.h>
45
46 #if HAVE_DMALLOC_H
47 #include <dmalloc.h>
48 #endif
49
50 #include <net-snmp/net-snmp-includes.h>
51 #include <net-snmp/agent/agent_trap.h>
52 #include <net-snmp/agent/snmp_agent.h>
53 #include <net-snmp/agent/agent_callbacks.h>
54
55 #include <net-snmp/agent/mib_module_config.h>
56
57 struct trap_sink {
58     netsnmp_session *sesp;
59     struct trap_sink *next;
60     int             pdutype;
61     int             version;
62 };
63
64 struct trap_sink *sinks = NULL;
65
66 extern struct timeval starttime;
67
68 #ifdef BRCM_SNMP_MIB_SUPPORT
69 oid             objid_enterprisetrap[] = { NOTIFICATION_MIB };
70 #endif
71 oid             trap_version_id[] = { SYSTEM_MIB };
72 int             enterprisetrap_len;
73 int             trap_version_id_len;
74
75 #define SNMPV2_TRAPS_PREFIX     SNMP_OID_SNMPMODULES,1,1,5
76 oid             cold_start_oid[] = { SNMPV2_TRAPS_PREFIX, 1 };  /* SNMPv2-MIB */
77 oid             warm_start_oid[] = { SNMPV2_TRAPS_PREFIX, 2 };  /* SNMPv2-MIB */
78 oid             link_down_oid[] = { SNMPV2_TRAPS_PREFIX, 3 };   /* IF-MIB */
79 oid             link_up_oid[] = { SNMPV2_TRAPS_PREFIX, 4 };     /* IF-MIB */
80 oid             auth_fail_oid[] = { SNMPV2_TRAPS_PREFIX, 5 };   /* SNMPv2-MIB */
81 oid             egp_xxx_oid[] = { SNMPV2_TRAPS_PREFIX, 99 };    /* ??? */
82
83 #define SNMPV2_TRAP_OBJS_PREFIX SNMP_OID_SNMPMODULES,1,1,4
84 oid             snmptrap_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 1, 0 };
85 oid             snmptrapenterprise_oid[] =
86     { SNMPV2_TRAP_OBJS_PREFIX, 3, 0 };
87 oid             sysuptime_oid[] = { SNMP_OID_MIB2, 1, 3, 0 };
88 size_t          snmptrap_oid_len;
89 size_t          snmptrapenterprise_oid_len;
90 size_t          sysuptime_oid_len;
91
92
93 #define SNMP_AUTHENTICATED_TRAPS_ENABLED        1
94 #define SNMP_AUTHENTICATED_TRAPS_DISABLED       2
95
96 int             snmp_enableauthentraps = SNMP_AUTHENTICATED_TRAPS_DISABLED;
97 int             snmp_enableauthentrapsset = 0;
98 char           *snmp_trapcommunity = NULL;
99
100 /*
101  * Prototypes 
102  */
103  /*
104   * static int create_v1_trap_session (const char *, u_short, const char *);
105   * static int create_v2_trap_session (const char *, u_short, const char *);
106   * static int create_v2_inform_session (const char *, u_short, const char *);
107   * static void free_trap_session (struct trap_sink *sp);
108   * static void send_v1_trap (netsnmp_session *, int, int);
109   * static void send_v2_trap (netsnmp_session *, int, int, int);
110   */
111
112
113         /*******************
114          *
115          * Trap session handling
116          *
117          *******************/
118
119 void
120 init_traps(void)
121 {
122 #ifdef BRCM_SNMP_MIB_SUPPORT
123     enterprisetrap_len = OID_LENGTH(objid_enterprisetrap);
124 #endif
125     trap_version_id_len = OID_LENGTH(trap_version_id);
126     snmptrap_oid_len = OID_LENGTH(snmptrap_oid);
127 #ifdef BRCM_SNMP_MIB_SUPPORT
128     snmptrapenterprise_oid_len = OID_LENGTH(snmptrapenterprise_oid);
129 #endif
130     sysuptime_oid_len = OID_LENGTH(sysuptime_oid);
131 }
132
133 static void
134 free_trap_session(struct trap_sink *sp)
135 {
136     snmp_close(sp->sesp);
137     free(sp);
138 }
139
140 int
141 add_trap_session(netsnmp_session * ss, int pdutype, int confirm,
142                  int version)
143 {
144     if (snmp_callback_available(SNMP_CALLBACK_APPLICATION,
145                                 SNMPD_CALLBACK_REGISTER_NOTIFICATIONS) ==
146         SNMPERR_SUCCESS) {
147         /*
148          * something else wants to handle notification registrations 
149          */
150         struct agent_add_trap_args args;
151         DEBUGMSGTL(("trap", "adding callback trap sink\n"));
152         args.ss = ss;
153         args.confirm = confirm;
154         snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
155                             SNMPD_CALLBACK_REGISTER_NOTIFICATIONS,
156                             (void *) &args);
157     } else {
158         /*
159          * no other support exists, handle it ourselves. 
160          */
161         struct trap_sink *new_sink;
162
163         DEBUGMSGTL(("trap", "adding internal trap sink\n"));
164         new_sink = (struct trap_sink *) malloc(sizeof(*new_sink));
165         if (new_sink == NULL)
166             return 0;
167
168         new_sink->sesp = ss;
169         new_sink->pdutype = pdutype;
170         new_sink->version = version;
171         new_sink->next = sinks;
172         sinks = new_sink;
173     }
174     return 1;
175 }
176
177 int
178 remove_trap_session(netsnmp_session * ss)
179 {
180     struct trap_sink *sp = sinks, *prev = 0;
181
182     while (sp) {
183         if (sp->sesp == ss) {
184             if (prev) {
185                 prev->next = sp->next;
186             } else {
187                 sinks = sp->next;
188             }
189             /*
190              * I don't believe you *really* want to close the session here;
191              * it may still be in use for other purposes.  In particular this
192              * is awkward for AgentX, since we want to call this function
193              * from the session's callback.  Let's just free the trapsink
194              * data structure.  [jbpn]  
195              */
196             /*
197              * free_trap_session(sp);  
198              */
199             free(sp);
200             return 1;
201         }
202         prev = sp;
203         sp = sp->next;
204     }
205     return 0;
206 }
207
208 int
209 create_trap_session(char *sink, u_short sinkport,
210                     char *com, int version, int pdutype)
211 {
212     netsnmp_session session, *sesp;
213     char           *peername = NULL;
214
215     if ((peername = malloc(strlen(sink) + 4 + 32)) == NULL) {
216         return 0;
217     } else {
218         snprintf(peername, strlen(sink) + 4 + 32, "udp:%s:%hu", sink,
219                  sinkport);
220     }
221
222     memset(&session, 0, sizeof(netsnmp_session));
223     session.peername = peername;
224     session.version = version;
225     if (com) {
226         session.community = (u_char *) com;
227         session.community_len = strlen(com);
228     }
229     sesp = snmp_open(&session);
230     free(peername);
231
232     if (sesp) {
233         return add_trap_session(sesp, pdutype,
234                                 (pdutype == SNMP_MSG_INFORM), version);
235     }
236
237     /*
238      * diagnose snmp_open errors with the input netsnmp_session pointer 
239      */
240     snmp_sess_perror("snmpd: create_trap_session", &session);
241     return 0;
242 }
243
244 static int
245 create_v1_trap_session(char *sink, u_short sinkport, char *com)
246 {
247     return create_trap_session(sink, sinkport, com,
248                                SNMP_VERSION_1, SNMP_MSG_TRAP);
249 }
250
251 static int
252 create_v2_trap_session(char *sink, u_short sinkport, char *com)
253 {
254     return create_trap_session(sink, sinkport, com,
255                                SNMP_VERSION_2c, SNMP_MSG_TRAP2);
256 }
257
258 #ifdef BRCM_SNMP_CONFIG_SUPPORT
259 static int
260 create_v2_inform_session(char *sink, u_short sinkport, char *com)
261 {
262     return create_trap_session(sink, sinkport, com,
263                                SNMP_VERSION_2c, SNMP_MSG_INFORM);
264 }
265 #endif /* BRCM_SNMP_CONFIG_SUPPORT */
266
267 void
268 snmpd_free_trapsinks(void)
269 {
270     struct trap_sink *sp = sinks;
271     while (sp) {
272         sinks = sinks->next;
273         free_trap_session(sp);
274         sp = sinks;
275     }
276 }
277
278         /*******************
279          *
280          * Trap handling
281          *
282          *******************/
283
284 void
285 convert_v2_to_v1(netsnmp_variable_list * vars, netsnmp_pdu *template_pdu)
286 {
287     netsnmp_variable_list *v, *trap_v = NULL, *ent_v = NULL;
288     oid             trap_prefix[] = { SNMPV2_TRAPS_PREFIX };
289     int             len;
290
291     for (v = vars; v; v = v->next_variable) {
292         if (netsnmp_oid_equals(v->name, v->name_length,
293                              snmptrap_oid, OID_LENGTH(snmptrap_oid)) == 0)
294             trap_v = v;
295         if (netsnmp_oid_equals(v->name, v->name_length,
296                              snmptrapenterprise_oid,
297                              OID_LENGTH(snmptrapenterprise_oid)) == 0)
298             ent_v = v;
299     }
300
301     if (!trap_v)
302         return;                 /* Can't find v2 snmpTrapOID varbind */
303
304     /*
305      * Is this a 'standard' trap?
306      *  Or at least, does it have the correct prefix?
307      */
308     if (netsnmp_oid_equals(trap_v->val.objid, OID_LENGTH(trap_prefix),
309                          trap_prefix, OID_LENGTH(trap_prefix)) == 0) {
310         template_pdu->trap_type =
311             trap_v->val.objid[OID_LENGTH(trap_prefix)] - 1;
312         template_pdu->specific_type = 0;
313     } else {
314         len = trap_v->val_len / sizeof(oid);
315         template_pdu->trap_type = 6;    /* enterprise specific */
316         template_pdu->specific_type = trap_v->val.objid[len - 1];
317     }
318
319     /*
320      *  TODO:
321      *    Extract the appropriate enterprise value from 'ent_v'
322      *    Remove uptime/trapOID varbinds from 'vars' list
323      */
324
325 }
326
327 void
328 send_enterprise_trap_vars(int trap,
329                           int specific,
330                           oid * enterprise, int enterprise_length,
331                           netsnmp_variable_list * vars)
332 {
333     netsnmp_variable_list uptime_var, snmptrap_var, enterprise_var;
334     netsnmp_variable_list *v2_vars, *last_var = NULL;
335     netsnmp_pdu    *template_pdu;
336     u_long          uptime;
337     in_addr_t      *pdu_in_addr_t;
338     struct trap_sink *sink;
339 #ifdef BRCM_SNMP_MIB_SUPPORT
340     oid             temp_oid[MAX_OID_LEN];
341 #endif
342     /*
343      * Initialise SNMPv2 required variables
344      */
345     uptime = netsnmp_get_agent_uptime();
346     memset(&uptime_var, 0, sizeof(netsnmp_variable_list));
347     snmp_set_var_objid(&uptime_var, sysuptime_oid,
348                        OID_LENGTH(sysuptime_oid));
349     snmp_set_var_value(&uptime_var, (u_char *) & uptime, sizeof(uptime));
350     uptime_var.type = ASN_TIMETICKS;
351     uptime_var.next_variable = &snmptrap_var;
352
353     memset(&snmptrap_var, 0, sizeof(netsnmp_variable_list));
354     snmp_set_var_objid(&snmptrap_var, snmptrap_oid,
355                        OID_LENGTH(snmptrap_oid));
356     /*
357      * value set later .... 
358      */
359     snmptrap_var.type = ASN_OBJECT_ID;
360     if (vars)
361         snmptrap_var.next_variable = vars;
362     else
363         snmptrap_var.next_variable = &enterprise_var;
364
365     /*
366      * find end of provided varbind list,
367      * ready to append the enterprise info if necessary 
368      */
369     last_var = vars;
370     while (last_var && last_var->next_variable)
371         last_var = last_var->next_variable;
372
373     memset(&enterprise_var, 0, sizeof(netsnmp_variable_list));
374     snmp_set_var_objid(&enterprise_var,
375                        snmptrapenterprise_oid,
376                        OID_LENGTH(snmptrapenterprise_oid));
377     snmp_set_var_value(&enterprise_var, (u_char *) enterprise,
378                        enterprise_length * sizeof(oid));
379     enterprise_var.type = ASN_OBJECT_ID;
380     enterprise_var.next_variable = NULL;
381
382     v2_vars = &uptime_var;
383
384     /*
385      *  Create a template PDU, ready for sending
386      */
387     template_pdu = snmp_pdu_create(SNMP_MSG_TRAP);
388     if (template_pdu == NULL) {
389         /*
390          * Free memory if value stored dynamically 
391          */
392         snmp_set_var_value(&enterprise_var, NULL, 0);
393         return;
394     }
395     template_pdu->trap_type = trap;
396     template_pdu->specific_type = specific;
397     if (snmp_clone_mem((void **) &template_pdu->enterprise,
398                        enterprise, enterprise_length * sizeof(oid))) {
399         snmp_free_pdu(template_pdu);
400         snmp_set_var_value(&enterprise_var, NULL, 0);
401         return;
402     }
403     template_pdu->enterprise_length = enterprise_length;
404     template_pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY;
405
406     pdu_in_addr_t = (in_addr_t *) template_pdu->agent_addr;
407     *pdu_in_addr_t = get_myaddr();
408     template_pdu->time = uptime;
409
410     /*
411      *  Now use the parameters to determine
412      *    which v2 variables are needed,
413      *    and what values they should take.
414      */
415     switch (trap) {
416     case -1:                   /*
417                                  *      SNMPv2 only
418                                  *  Check to see whether the variables provided
419                                  *    are sufficient for SNMPv2 notifications
420                                  */
421         if (vars && netsnmp_oid_equals(vars->name, vars->name_length,
422                                      sysuptime_oid,
423                                      OID_LENGTH(sysuptime_oid)) == 0)
424             v2_vars = vars;
425         else if (vars && netsnmp_oid_equals(vars->name, vars->name_length,
426                                           snmptrap_oid,
427                                           OID_LENGTH(snmptrap_oid)) == 0)
428             uptime_var.next_variable = vars;
429         else {
430             /*
431              * Hmmm... we don't seem to have a value - oops! 
432              */
433             snmptrap_var.next_variable = vars;
434         }
435         last_var = NULL;        /* Don't need enterprise info */
436         convert_v2_to_v1(vars, template_pdu);
437         break;
438
439         /*
440          * "Standard" SNMPv1 traps 
441          */
442
443     case SNMP_TRAP_COLDSTART:
444         snmp_set_var_value(&snmptrap_var,
445                            (u_char *) cold_start_oid,
446                            sizeof(cold_start_oid));
447         break;
448     case SNMP_TRAP_WARMSTART:
449         snmp_set_var_value(&snmptrap_var,
450                            (u_char *) warm_start_oid,
451                            sizeof(warm_start_oid));
452         break;
453     case SNMP_TRAP_LINKDOWN:
454         snmp_set_var_value(&snmptrap_var,
455                            (u_char *) link_down_oid,
456                            sizeof(link_down_oid));
457         break;
458     case SNMP_TRAP_LINKUP:
459         snmp_set_var_value(&snmptrap_var,
460                            (u_char *) link_up_oid, sizeof(link_up_oid));
461         break;
462     case SNMP_TRAP_AUTHFAIL:
463         if (snmp_enableauthentraps == SNMP_AUTHENTICATED_TRAPS_DISABLED) {
464             snmp_free_pdu(template_pdu);
465             snmp_set_var_value(&enterprise_var, NULL, 0);
466             return;
467         }
468         snmp_set_var_value(&snmptrap_var,
469                            (u_char *) auth_fail_oid,
470                            sizeof(auth_fail_oid));
471         break;
472     case SNMP_TRAP_EGPNEIGHBORLOSS:
473         snmp_set_var_value(&snmptrap_var,
474                            (u_char *) egp_xxx_oid, sizeof(egp_xxx_oid));
475         break;
476
477 #ifdef BRCM_SNMP_MIB_SUPPORT
478     case SNMP_TRAP_ENTERPRISESPECIFIC:
479         memcpy(temp_oid,
480                (char *) enterprise, (enterprise_length) * sizeof(oid));
481         temp_oid[enterprise_length] = 0;
482         temp_oid[enterprise_length + 1] = specific;
483         snmp_set_var_value(&snmptrap_var,
484                            (u_char *) temp_oid,
485                            (enterprise_length + 2) * sizeof(oid));
486         snmptrap_var.next_variable = vars;
487         last_var = NULL;        /* Don't need version info */
488         break;
489 #endif /* BRCM_SNMP_MIB_SUPPORT */
490     }
491
492
493     /*
494      *  Now loop through the list of trap sinks,
495      *   sending an appropriately formatted PDU to each
496      */
497     for (sink = sinks; sink; sink = sink->next) {
498         if (sink->version == SNMP_VERSION_1 && trap == -1)
499             continue;           /* Skip v1 sinks for v2 only traps */
500         template_pdu->command = sink->pdutype;
501
502         if (sink->version != SNMP_VERSION_1) {
503             template_pdu->variables = v2_vars;
504             if (last_var)
505                 last_var->next_variable = &enterprise_var;
506         } else
507             template_pdu->variables = vars;
508
509         send_trap_to_sess(sink->sesp, template_pdu);
510
511         if (sink->version != SNMP_VERSION_1 && last_var)
512             last_var->next_variable = NULL;
513     }
514
515     /*
516      * send stuff to registered callbacks 
517      */
518     /*
519      * v2 traps/informs 
520      */
521     template_pdu->variables = v2_vars;
522     if (last_var)
523         last_var->next_variable = &enterprise_var;
524
525     snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
526                         SNMPD_CALLBACK_SEND_TRAP2, template_pdu);
527
528     if (last_var)
529         last_var->next_variable = NULL;
530
531     /*
532      * v1 traps 
533      */
534     template_pdu->command = SNMP_MSG_TRAP;
535     template_pdu->variables = vars;
536
537     snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
538                         SNMPD_CALLBACK_SEND_TRAP1, template_pdu);
539
540     /*
541      * Free memory if values stored dynamically 
542      */
543     snmp_set_var_value(&enterprise_var, NULL, 0);
544     snmp_set_var_value(&snmptrap_var, NULL, 0);
545     /*
546      * Ensure we don't free anything we shouldn't 
547      */
548     if (last_var)
549         last_var->next_variable = NULL;
550     template_pdu->variables = NULL;
551     snmp_free_pdu(template_pdu);
552 }
553
554 /*
555  * send_trap_to_sess: sends a trap to a session but assumes that the
556  * pdu is constructed correctly for the session type. 
557  */
558 void
559 send_trap_to_sess(netsnmp_session * sess, netsnmp_pdu *template_pdu)
560 {
561     netsnmp_pdu    *pdu;
562
563     if (!sess || !template_pdu)
564         return;
565
566     DEBUGMSGTL(("trap", "sending trap type=%d, version=%d\n",
567                 template_pdu->command, sess->version));
568
569     if (sess->version == SNMP_VERSION_1 &&
570         (template_pdu->command == SNMP_MSG_TRAP2 ||
571          template_pdu->command == SNMP_MSG_INFORM))
572         return;                 /* Skip v1 sinks for v2 only traps */
573     template_pdu->version = sess->version;
574     pdu = snmp_clone_pdu(template_pdu);
575     pdu->sessid = sess->sessid; /* AgentX only ? */
576     if (snmp_send(sess, pdu) == 0) {
577         snmp_sess_perror("snmpd: send_trap", sess);
578         snmp_free_pdu(pdu);
579     } else {
580         snmp_increment_statistic(STAT_SNMPOUTTRAPS);
581         snmp_increment_statistic(STAT_SNMPOUTPKTS);
582     }
583 }
584
585 void
586 send_trap_vars(int trap, int specific, netsnmp_variable_list * vars)
587 {
588 #ifdef BRCM_SNMP_MIB_SUPPORT
589     if (trap == SNMP_TRAP_ENTERPRISESPECIFIC)
590         send_enterprise_trap_vars(trap, specific, objid_enterprisetrap,
591                                   OID_LENGTH(objid_enterprisetrap), vars);
592     else
593 #endif
594         send_enterprise_trap_vars(trap, specific, trap_version_id,
595                                   OID_LENGTH(trap_version_id), vars);
596 }
597
598 void
599 send_easy_trap(int trap, int specific)
600 {
601     send_trap_vars(trap, specific, NULL);
602 }
603
604 void
605 send_v2trap(netsnmp_variable_list * vars)
606 {
607     send_trap_vars(-1, -1, vars);
608 }
609
610 void
611 send_trap_pdu(netsnmp_pdu *pdu)
612 {
613     send_trap_vars(-1, -1, pdu->variables);
614 }
615
616
617 #ifdef BRCM_SNMP_CONFIG_SUPPORT
618         /*******************
619          *
620          * Config file handling
621          *
622          *******************/
623
624 void
625 snmpd_parse_config_authtrap(const char *token, char *cptr)
626 {
627     int             i;
628
629     i = atoi(cptr);
630     if (i == 0) {
631         if (strcmp(cptr, "enable") == 0) {
632             i = SNMP_AUTHENTICATED_TRAPS_ENABLED;
633         } else if (strcmp(cptr, "disable") == 0) {
634             i = SNMP_AUTHENTICATED_TRAPS_DISABLED;
635         }
636     }
637     if (i < 1 || i > 2) {
638         config_perror("authtrapenable must be 1 or 2");
639     } else {
640         if (strcmp(token, "pauthtrapenable") == 0) {
641             if (snmp_enableauthentrapsset < 0) {
642                 /*
643                  * This is bogus (and shouldn't happen anyway) -- the value
644                  * of snmpEnableAuthenTraps.0 is already configured
645                  * read-only.  
646                  */
647                 snmp_log(LOG_WARNING,
648                          "ignoring attempted override of read-only snmpEnableAuthenTraps.0\n");
649                 return;
650             } else {
651                 snmp_enableauthentrapsset++;
652             }
653         } else {
654             if (snmp_enableauthentrapsset > 0) {
655                 /*
656                  * This is bogus (and shouldn't happen anyway) -- we already
657                  * read a persistent value of snmpEnableAuthenTraps.0, which
658                  * we should ignore in favour of this one.  
659                  */
660                 snmp_log(LOG_WARNING,
661                          "ignoring attempted override of read-only snmpEnableAuthenTraps.0\n");
662                 /*
663                  * Fall through and copy in this value.  
664                  */
665             }
666             snmp_enableauthentrapsset = -1;
667         }
668         snmp_enableauthentraps = i;
669     }
670 }
671 #endif /* BRCM_SNMP_CONFIG_SUPPORT */
672
673 void
674 snmpd_parse_config_trapsink(const char *token, char *cptr)
675 {
676     char            tmpbuf[1024];
677     char           *sp, *cp, *pp = NULL;
678     u_short         sinkport;
679
680     if (!snmp_trapcommunity)
681         snmp_trapcommunity = strdup("public");
682     sp = strtok(cptr, " \t\n");
683     cp = strtok(NULL, " \t\n");
684     if (cp)
685         pp = strtok(NULL, " \t\n");
686     if (cp && pp) {
687         sinkport = atoi(pp);
688         if ((sinkport < 1) || (sinkport > 0xffff)) {
689             config_perror("trapsink port out of range");
690             sinkport = SNMP_TRAP_PORT;
691         }
692     } else {
693         sinkport = SNMP_TRAP_PORT;
694     }
695     if (create_v1_trap_session(sp, sinkport,
696                                cp ? cp : snmp_trapcommunity) == 0) {
697         snprintf(tmpbuf, sizeof(tmpbuf), "cannot create trapsink: %s", cptr);
698         tmpbuf[sizeof(tmpbuf)-1] = '\0';
699         config_perror(tmpbuf);
700     }
701 }
702
703
704 void
705 snmpd_parse_config_trap2sink(const char *word, char *cptr)
706 {
707     char            tmpbuf[1024];
708     char           *sp, *cp, *pp = NULL;
709     u_short         sinkport;
710
711     if (!snmp_trapcommunity)
712         snmp_trapcommunity = strdup("public");
713     sp = strtok(cptr, " \t\n");
714     cp = strtok(NULL, " \t\n");
715     if (cp)
716         pp = strtok(NULL, " \t\n");
717     if (cp && pp) {
718         sinkport = atoi(pp);
719         if ((sinkport < 1) || (sinkport > 0xffff)) {
720             config_perror("trapsink port out of range");
721             sinkport = SNMP_TRAP_PORT;
722         }
723     } else {
724         sinkport = SNMP_TRAP_PORT;
725     }
726     if (create_v2_trap_session(sp, sinkport,
727                                cp ? cp : snmp_trapcommunity) == 0) {
728         snprintf(tmpbuf, sizeof(tmpbuf), "cannot create trap2sink: %s", cptr);
729         tmpbuf[sizeof(tmpbuf)-1] = '\0';
730         config_perror(tmpbuf);
731     }
732 }
733
734 #ifdef BRCM_SNMP_CONFIG_SUPPORT
735 void
736 snmpd_parse_config_informsink(const char *word, char *cptr)
737 {
738     char            tmpbuf[1024];
739     char           *sp, *cp, *pp = NULL;
740     u_short         sinkport;
741
742     if (!snmp_trapcommunity)
743         snmp_trapcommunity = strdup("public");
744     sp = strtok(cptr, " \t\n");
745     cp = strtok(NULL, " \t\n");
746     if (cp)
747         pp = strtok(NULL, " \t\n");
748     if (cp && pp) {
749         sinkport = atoi(pp);
750         if ((sinkport < 1) || (sinkport > 0xffff)) {
751             config_perror("trapsink port out of range");
752             sinkport = SNMP_TRAP_PORT;
753         }
754     } else {
755         sinkport = SNMP_TRAP_PORT;
756     }
757     if (create_v2_inform_session(sp, sinkport,
758                                  cp ? cp : snmp_trapcommunity) == 0) {
759         snprintf(tmpbuf, sizeof(tmpbuf), "cannot create informsink: %s", cptr);
760         tmpbuf[sizeof(tmpbuf)-1] = '\0';
761         config_perror(tmpbuf);
762     }
763 }
764
765 /*
766  * this must be standardized somewhere, right? 
767  */
768 #define MAX_ARGS 128
769
770 static int      traptype;
771
772 static void
773 trapOptProc(int argc, char *const *argv, int opt)
774 {
775     switch (opt) {
776     case 'C':
777         while (*optarg) {
778             switch (*optarg++) {
779             case 'i':
780                 traptype = SNMP_MSG_INFORM;
781                 break;
782             default:
783                 config_perror("unknown argument passed to -C");
784                 break;
785             }
786         }
787         break;
788     }
789 }
790
791 void
792 snmpd_parse_config_trapsess(const char *word, char *cptr)
793 {
794     char           *argv[MAX_ARGS], *cp = cptr, tmp[SPRINT_MAX_LEN];
795     int             argn, arg;
796     netsnmp_session session, *ss;
797
798     /*
799      * inform or trap?  default to trap 
800      */
801     traptype = SNMP_MSG_TRAP2;
802
803     /*
804      * create the argv[] like array 
805      */
806     argv[0] = strdup("snmpd-trapsess"); /* bogus entry for getopt() */
807     for (argn = 1; cp && argn < MAX_ARGS; argn++) {
808         cp = copy_nword(cp, tmp, SPRINT_MAX_LEN);
809         argv[argn] = strdup(tmp);
810     }
811
812     arg = snmp_parse_args(argn, argv, &session, "C:", trapOptProc);
813     ss = snmp_open(&session);
814
815     for (; argn > 0; argn--) {
816         free(argv[argn - 1]);
817     }
818
819     if (!ss) {
820         config_perror
821             ("snmpd: failed to parse this line or the remote trap receiver is down.  Possible cause:");
822         snmp_sess_perror("snmpd: snmpd_parse_config_trapsess()", &session);
823         return;
824     }
825
826     if (ss->version == SNMP_VERSION_1) {
827         add_trap_session(ss, SNMP_MSG_TRAP, 0, SNMP_VERSION_1);
828     } else {
829         add_trap_session(ss, traptype, (traptype == SNMP_MSG_INFORM),
830                          ss->version);
831     }
832 }
833 #endif /* BRCM_SNMP_CONFIG_SUPPORT */
834
835 void
836 snmpd_parse_config_trapcommunity(const char *word, char *cptr)
837 {
838     if (snmp_trapcommunity != NULL) {
839         free(snmp_trapcommunity);
840     }
841     snmp_trapcommunity = (char *) malloc(strlen(cptr) + 1);
842     if (snmp_trapcommunity != NULL) {
843         copy_nword(cptr, snmp_trapcommunity, strlen(cptr) + 1);
844     }
845 }
846
847 void
848 snmpd_free_trapcommunity(void)
849 {
850     if (snmp_trapcommunity) {
851         free(snmp_trapcommunity);
852         snmp_trapcommunity = NULL;
853     }
854 }