1/* SNMP support
2 * Copyright (C) 2012 Vincent Bernat <bernat@luffy.cx>
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING.  If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
24#if defined HAVE_SNMP && defined SNMP_AGENTX
25#include <net-snmp/net-snmp-config.h>
26#include <net-snmp/net-snmp-includes.h>
27
28#include "command.h"
29#include "smux.h"
30
31int agentx_enabled = 0;
32
33/* AgentX node. */
34static struct cmd_node agentx_node =
35{
36  SMUX_NODE,
37  ""                            /* AgentX has no interface. */
38};
39
40/* Logging NetSNMP messages */
41static int
42agentx_log_callback(int major, int minor,
43		    void *serverarg, void *clientarg)
44{
45  struct snmp_log_message *slm = (struct snmp_log_message *)serverarg;
46  char *msg = strdup (slm->msg);
47  if (msg) msg[strlen(msg)-1] = '\0';
48  switch (slm->priority)
49    {
50    case LOG_EMERG:   zlog_err   ("snmp[emerg]: %s",   msg?msg:slm->msg); break;
51    case LOG_ALERT:   zlog_err   ("snmp[alert]: %s",   msg?msg:slm->msg); break;
52    case LOG_CRIT:    zlog_err   ("snmp[crit]: %s",    msg?msg:slm->msg); break;
53    case LOG_ERR:     zlog_err   ("snmp[err]: %s",     msg?msg:slm->msg); break;
54    case LOG_WARNING: zlog_warn  ("snmp[warning]: %s", msg?msg:slm->msg); break;
55    case LOG_NOTICE:  zlog_notice("snmp[notice]: %s",  msg?msg:slm->msg); break;
56    case LOG_INFO:    zlog_info  ("snmp[info]: %s",    msg?msg:slm->msg); break;
57    case LOG_DEBUG:   zlog_debug ("snmp[debug]: %s",   msg?msg:slm->msg); break;
58    }
59  free(msg);
60  return SNMP_ERR_NOERROR;
61}
62
63static int
64config_write_agentx (struct vty *vty)
65{
66  if (agentx_enabled)
67      vty_out (vty, "agentx%s", VTY_NEWLINE);
68  return 0;
69}
70
71DEFUN (agentx_enable,
72       agentx_enable_cmd,
73       "agentx",
74       "SNMP AgentX protocol settings\n"
75       "SNMP AgentX settings\n")
76{
77  if (!agentx_enabled)
78    {
79      init_snmp("quagga");
80      agentx_enabled = 1;
81      return CMD_SUCCESS;
82    }
83  vty_out (vty, "SNMP AgentX already enabled%s", VTY_NEWLINE);
84  return CMD_WARNING;
85}
86
87DEFUN (no_agentx,
88       no_agentx_cmd,
89       "no agentx",
90       NO_STR
91       "SNMP AgentX protocol settings\n"
92       "SNMP AgentX settings\n")
93{
94  if (!agentx_enabled) return CMD_SUCCESS;
95  vty_out (vty, "SNMP AgentX support cannot be disabled once enabled%s", VTY_NEWLINE);
96  return CMD_WARNING;
97}
98
99void
100smux_init (struct thread_master *tm)
101{
102  netsnmp_enable_subagent ();
103  snmp_disable_log ();
104  snmp_enable_calllog ();
105  snmp_register_callback (SNMP_CALLBACK_LIBRARY,
106			  SNMP_CALLBACK_LOGGING,
107			  agentx_log_callback,
108			  NULL);
109  init_agent ("quagga");
110
111  install_node (&agentx_node, config_write_agentx);
112  install_element (CONFIG_NODE, &agentx_enable_cmd);
113  install_element (CONFIG_NODE, &no_agentx_cmd);
114}
115
116void
117smux_register_mib (const char *descr, struct variable *var,
118		   size_t width, int num,
119		   oid name[], size_t namelen)
120{
121  register_mib (descr, var, width, num, name, namelen);
122}
123
124int
125smux_trap (struct variable *vp, size_t vp_len,
126	   const oid *ename, size_t enamelen,
127	   const oid *name, size_t namelen,
128	   const oid *iname, size_t inamelen,
129	   const struct trap_object *trapobj, size_t trapobjlen,
130	   u_char sptrap)
131{
132  oid objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
133  size_t objid_snmptrap_len = sizeof objid_snmptrap / sizeof (oid);
134  oid notification_oid[MAX_OID_LEN];
135  size_t notification_oid_len;
136  unsigned int i;
137
138  netsnmp_variable_list *notification_vars = NULL;
139  if (!agentx_enabled) return 0;
140
141  /* snmpTrapOID */
142  oid_copy (notification_oid, ename, enamelen);
143  notification_oid[enamelen] = sptrap;
144  notification_oid_len = enamelen + 1;
145  snmp_varlist_add_variable (&notification_vars,
146			     objid_snmptrap, objid_snmptrap_len,
147			     ASN_OBJECT_ID,
148			     (u_char *) notification_oid,
149			     notification_oid_len * sizeof(oid));
150
151  /* Provided bindings */
152  for (i = 0; i < trapobjlen; i++)
153    {
154      unsigned int j;
155      oid oid[MAX_OID_LEN];
156      size_t oid_len, onamelen;
157      u_char *val;
158      size_t val_len;
159      WriteMethod *wm = NULL;
160      struct variable cvp;
161
162      /* Make OID. */
163      if (trapobj[i].namelen > 0)
164        {
165	  /* Columnar object */
166	  onamelen = trapobj[i].namelen;
167	  oid_copy (oid, name, namelen);
168	  oid_copy (oid + namelen, trapobj[i].name, onamelen);
169	  oid_copy (oid + namelen + onamelen, iname, inamelen);
170	  oid_len = namelen + onamelen + inamelen;
171        }
172      else
173        {
174	  /* Scalar object */
175	  onamelen = trapobj[i].namelen * (-1);
176	  oid_copy (oid, name, namelen);
177	  oid_copy (oid + namelen, trapobj[i].name, onamelen);
178	  oid[onamelen + namelen] = 0;
179	  oid_len = namelen + onamelen + 1;
180        }
181
182      /* Locate the appropriate function and type in the MIB registry. */
183      for (j = 0; j < vp_len; j++)
184	{
185	  if (oid_compare (trapobj[i].name, onamelen, vp[j].name, vp[j].namelen) != 0)
186	    continue;
187	  /* We found the appropriate variable in the MIB registry. */
188	  oid_copy(cvp.name, name, namelen);
189	  oid_copy(cvp.name + namelen, vp[j].name, vp[j].namelen);
190	  cvp.namelen = namelen + vp[j].namelen;
191	  cvp.type = vp[j].type;
192	  cvp.magic = vp[j].magic;
193	  cvp.acl = vp[j].acl;
194	  cvp.findVar = vp[j].findVar;
195	  /* Grab the result. */
196	  val = cvp.findVar (&cvp, oid, &oid_len, 1, &val_len, &wm);
197	  if (!val) break;
198	  snmp_varlist_add_variable (&notification_vars,
199				     oid, oid_len,
200				     vp[j].type,
201				     val,
202				     val_len);
203	  break;
204	}
205    }
206
207
208  send_v2trap (notification_vars);
209  snmp_free_varbind (notification_vars);
210  return 1;
211}
212
213#endif /* HAVE_SNMP */
214