blob: 1941cf8ca76fdb080c207d2d498a132d71596697 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* SNMP support
2 * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
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#ifdef HAVE_SNMP
paul07661cb2003-03-18 00:03:05 +000025#ifdef HAVE_NETSNMP
26#include <net-snmp/net-snmp-config.h>
Joakim Tjernlundfb62a3c2008-05-13 20:03:32 +020027#include <net-snmp/net-snmp-includes.h>
28#else
paul718e3742002-12-13 20:15:29 +000029#include <asn1.h>
30#include <snmp.h>
31#include <snmp_impl.h>
Joakim Tjernlundfb62a3c2008-05-13 20:03:32 +020032#endif
paul718e3742002-12-13 20:15:29 +000033
paul718e3742002-12-13 20:15:29 +000034#include "log.h"
35#include "thread.h"
36#include "linklist.h"
37#include "command.h"
gdt5e4fa162004-03-16 14:38:36 +000038#include <lib/version.h>
paul718e3742002-12-13 20:15:29 +000039#include "memory.h"
40#include "sockunion.h"
pauldd488a72003-06-19 01:21:07 +000041#include "smux.h"
paul718e3742002-12-13 20:15:29 +000042
43#define min(A,B) ((A) < (B) ? (A) : (B))
44
45enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
46
47void smux_event (enum smux_event, int);
48
49
50/* SMUX socket. */
51int smux_sock = -1;
52
53/* SMUX subtree list. */
54struct list *treelist;
55
56/* SMUX oid. */
hassoc75105a2004-10-13 10:33:26 +000057oid *smux_oid = NULL;
paul718e3742002-12-13 20:15:29 +000058size_t smux_oid_len;
59
paul718e3742002-12-13 20:15:29 +000060/* SMUX password. */
hassoc75105a2004-10-13 10:33:26 +000061char *smux_passwd = NULL;
paul718e3742002-12-13 20:15:29 +000062
63/* SMUX read threads. */
64struct thread *smux_read_thread;
65
66/* SMUX connect thrads. */
67struct thread *smux_connect_thread;
68
69/* SMUX debug flag. */
70int debug_smux = 0;
71
72/* SMUX failure count. */
73int fail = 0;
74
75/* SMUX node. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080076static struct cmd_node smux_node =
paul718e3742002-12-13 20:15:29 +000077{
78 SMUX_NODE,
79 "" /* SMUX has no interface. */
80};
pauldd488a72003-06-19 01:21:07 +000081
82/* thread master */
83static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +000084
85void *
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -070086oid_copy (void *dest, const void *src, size_t size)
paul718e3742002-12-13 20:15:29 +000087{
88 return memcpy (dest, src, size * sizeof (oid));
89}
90
91void
92oid2in_addr (oid oid[], int len, struct in_addr *addr)
93{
94 int i;
95 u_char *pnt;
96
97 if (len == 0)
98 return;
99
100 pnt = (u_char *) addr;
101
102 for (i = 0; i < len; i++)
103 *pnt++ = oid[i];
104}
105
106void
107oid_copy_addr (oid oid[], struct in_addr *addr, int len)
108{
109 int i;
110 u_char *pnt;
111
112 if (len == 0)
113 return;
114
115 pnt = (u_char *) addr;
116
117 for (i = 0; i < len; i++)
118 oid[i] = *pnt++;
119}
120
121int
122oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
123{
124 int i;
125
126 for (i = 0; i < min (o1_len, o2_len); i++)
127 {
128 if (o1[i] < o2[i])
129 return -1;
130 else if (o1[i] > o2[i])
131 return 1;
132 }
133 if (o1_len < o2_len)
134 return -1;
135 if (o1_len > o2_len)
136 return 1;
137
138 return 0;
139}
140
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100141static int
paul718e3742002-12-13 20:15:29 +0000142oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
143{
144 int i;
145
146 for (i = 0; i < min (o1_len, o2_len); i++)
147 {
148 if (o1[i] < o2[i])
149 return -1;
150 else if (o1[i] > o2[i])
151 return 1;
152 }
153 if (o1_len < o2_len)
154 return -1;
155
156 return 0;
157}
158
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100159static void
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -0700160smux_oid_dump (const char *prefix, const oid *oid, size_t oid_len)
paul718e3742002-12-13 20:15:29 +0000161{
paul9035efa2004-10-10 11:56:56 +0000162 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000163 int first = 1;
164 char buf[MAX_OID_LEN * 3];
165
166 buf[0] = '\0';
167
168 for (i = 0; i < oid_len; i++)
169 {
170 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
171 first = 0;
172 }
ajs8ddca702004-12-07 18:53:52 +0000173 zlog_debug ("%s: %s", prefix, buf);
paul718e3742002-12-13 20:15:29 +0000174}
175
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100176static int
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -0700177smux_socket (void)
paul718e3742002-12-13 20:15:29 +0000178{
179 int ret;
180#ifdef HAVE_IPV6
181 struct addrinfo hints, *res0, *res;
182 int gai;
183#else
184 struct sockaddr_in serv;
185 struct servent *sp;
186#endif
187 int sock = 0;
188
189#ifdef HAVE_IPV6
190 memset(&hints, 0, sizeof(hints));
191 hints.ai_family = PF_UNSPEC;
192 hints.ai_socktype = SOCK_STREAM;
193 gai = getaddrinfo(NULL, "smux", &hints, &res0);
194 if (gai == EAI_SERVICE)
195 {
196 char servbuf[NI_MAXSERV];
197 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
198 servbuf[sizeof (servbuf) - 1] = '\0';
199 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
200 }
201 if (gai)
202 {
203 zlog_warn("Cannot locate loopback service smux");
204 return -1;
205 }
206 for(res=res0; res; res=res->ai_next)
207 {
208 if (res->ai_family != AF_INET
209#ifdef HAVE_IPV6
210 && res->ai_family != AF_INET6
211#endif /* HAVE_IPV6 */
212 )
213 continue;
214
215 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
216 if (sock < 0)
217 continue;
218 sockopt_reuseaddr (sock);
219 sockopt_reuseport (sock);
220 ret = connect (sock, res->ai_addr, res->ai_addrlen);
221 if (ret < 0)
222 {
223 close(sock);
224 sock = -1;
225 continue;
226 }
227 break;
228 }
229 freeaddrinfo(res0);
230 if (sock < 0)
231 zlog_warn ("Can't connect to SNMP agent with SMUX");
232#else
233 sock = socket (AF_INET, SOCK_STREAM, 0);
234 if (sock < 0)
235 {
236 zlog_warn ("Can't make socket for SNMP");
237 return -1;
238 }
239
240 memset (&serv, 0, sizeof (struct sockaddr_in));
241 serv.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000242#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +0000243 serv.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000244#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +0000245
246 sp = getservbyname ("smux", "tcp");
247 if (sp != NULL)
248 serv.sin_port = sp->s_port;
249 else
250 serv.sin_port = htons (SMUX_PORT_DEFAULT);
251
252 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
253
254 sockopt_reuseaddr (sock);
255 sockopt_reuseport (sock);
256
257 ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
258 if (ret < 0)
259 {
260 close (sock);
261 smux_sock = -1;
262 zlog_warn ("Can't connect to SNMP agent with SMUX");
263 return -1;
264 }
265#endif
266 return sock;
267}
268
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100269static void
paul718e3742002-12-13 20:15:29 +0000270smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
271 long errindex, u_char val_type, void *arg, size_t arg_len)
272{
273 int ret;
274 u_char buf[BUFSIZ];
275 u_char *ptr, *h1, *h1e, *h2, *h2e;
paul70e149e2004-10-31 16:29:50 +0000276 size_t len, length;
paul718e3742002-12-13 20:15:29 +0000277
278 ptr = buf;
279 len = BUFSIZ;
280 length = len;
281
282 if (debug_smux)
283 {
ajs8ddca702004-12-07 18:53:52 +0000284 zlog_debug ("SMUX GETRSP send");
285 zlog_debug ("SMUX GETRSP reqid: %ld", reqid);
paul718e3742002-12-13 20:15:29 +0000286 }
287
288 h1 = ptr;
289 /* Place holder h1 for complete sequence */
290 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
291 h1e = ptr;
292
293 ptr = asn_build_int (ptr, &len,
294 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
295 &reqid, sizeof (reqid));
296
297 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000298 zlog_debug ("SMUX GETRSP errstat: %ld", errstat);
paul718e3742002-12-13 20:15:29 +0000299
300 ptr = asn_build_int (ptr, &len,
301 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
302 &errstat, sizeof (errstat));
303 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000304 zlog_debug ("SMUX GETRSP errindex: %ld", errindex);
paul718e3742002-12-13 20:15:29 +0000305
306 ptr = asn_build_int (ptr, &len,
307 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
308 &errindex, sizeof (errindex));
309
310 h2 = ptr;
311 /* Place holder h2 for one variable */
312 ptr = asn_build_sequence (ptr, &len,
313 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
314 0);
315 h2e = ptr;
316
317 ptr = snmp_build_var_op (ptr, objid, &objid_len,
318 val_type, arg_len, arg, &len);
319
320 /* Now variable size is known, fill in size */
321 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
322
323 /* Fill in size of whole sequence */
324 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
325
326 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100327 zlog_debug ("SMUX getresp send: %td", (ptr - buf));
paul718e3742002-12-13 20:15:29 +0000328
329 ret = send (smux_sock, buf, (ptr - buf), 0);
330}
331
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100332static u_char *
333smux_var (u_char *ptr, size_t len, oid objid[], size_t *objid_len,
paul718e3742002-12-13 20:15:29 +0000334 size_t *var_val_len,
335 u_char *var_val_type,
336 void **var_value)
337{
338 u_char type;
339 u_char val_type;
340 size_t val_len;
341 u_char *val;
342
343 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100344 zlog_debug ("SMUX var parse: len %zd", len);
paul718e3742002-12-13 20:15:29 +0000345
346 /* Parse header. */
347 ptr = asn_parse_header (ptr, &len, &type);
348
349 if (debug_smux)
350 {
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100351 zlog_debug ("SMUX var parse: type %d len %zd", type, len);
ajs8ddca702004-12-07 18:53:52 +0000352 zlog_debug ("SMUX var parse: type must be %d",
paul718e3742002-12-13 20:15:29 +0000353 (ASN_SEQUENCE | ASN_CONSTRUCTOR));
354 }
355
356 /* Parse var option. */
357 *objid_len = MAX_OID_LEN;
358 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
359 &val_len, &val, &len);
360
361 if (var_val_len)
362 *var_val_len = val_len;
363
364 if (var_value)
365 *var_value = (void*) val;
366
367 if (var_val_type)
368 *var_val_type = val_type;
369
370 /* Requested object id length is objid_len. */
371 if (debug_smux)
372 smux_oid_dump ("Request OID", objid, *objid_len);
373
374 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000375 zlog_debug ("SMUX val_type: %d", val_type);
paul718e3742002-12-13 20:15:29 +0000376
377 /* Check request value type. */
378 if (debug_smux)
379 switch (val_type)
380 {
381 case ASN_NULL:
382 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
383 ASN_NULL. */
ajs8ddca702004-12-07 18:53:52 +0000384 zlog_debug ("ASN_NULL");
paul718e3742002-12-13 20:15:29 +0000385 break;
386
387 case ASN_INTEGER:
ajs8ddca702004-12-07 18:53:52 +0000388 zlog_debug ("ASN_INTEGER");
paul718e3742002-12-13 20:15:29 +0000389 break;
390 case ASN_COUNTER:
391 case ASN_GAUGE:
392 case ASN_TIMETICKS:
393 case ASN_UINTEGER:
ajs8ddca702004-12-07 18:53:52 +0000394 zlog_debug ("ASN_COUNTER");
paul718e3742002-12-13 20:15:29 +0000395 break;
396 case ASN_COUNTER64:
ajs8ddca702004-12-07 18:53:52 +0000397 zlog_debug ("ASN_COUNTER64");
paul718e3742002-12-13 20:15:29 +0000398 break;
399 case ASN_IPADDRESS:
ajs8ddca702004-12-07 18:53:52 +0000400 zlog_debug ("ASN_IPADDRESS");
paul718e3742002-12-13 20:15:29 +0000401 break;
402 case ASN_OCTET_STR:
ajs8ddca702004-12-07 18:53:52 +0000403 zlog_debug ("ASN_OCTET_STR");
paul718e3742002-12-13 20:15:29 +0000404 break;
405 case ASN_OPAQUE:
406 case ASN_NSAP:
407 case ASN_OBJECT_ID:
ajs8ddca702004-12-07 18:53:52 +0000408 zlog_debug ("ASN_OPAQUE");
paul718e3742002-12-13 20:15:29 +0000409 break;
410 case SNMP_NOSUCHOBJECT:
ajs8ddca702004-12-07 18:53:52 +0000411 zlog_debug ("SNMP_NOSUCHOBJECT");
paul718e3742002-12-13 20:15:29 +0000412 break;
413 case SNMP_NOSUCHINSTANCE:
ajs8ddca702004-12-07 18:53:52 +0000414 zlog_debug ("SNMP_NOSUCHINSTANCE");
paul718e3742002-12-13 20:15:29 +0000415 break;
416 case SNMP_ENDOFMIBVIEW:
ajs8ddca702004-12-07 18:53:52 +0000417 zlog_debug ("SNMP_ENDOFMIBVIEW");
paul718e3742002-12-13 20:15:29 +0000418 break;
419 case ASN_BIT_STR:
ajs8ddca702004-12-07 18:53:52 +0000420 zlog_debug ("ASN_BIT_STR");
paul718e3742002-12-13 20:15:29 +0000421 break;
422 default:
ajs8ddca702004-12-07 18:53:52 +0000423 zlog_debug ("Unknown type");
paul718e3742002-12-13 20:15:29 +0000424 break;
425 }
426 return ptr;
427}
428
429/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
430 ucd-snmp smux and as such suppose, that the peer receives in the message
431 only one variable. Fortunately, IBM seems to do the same in AIX. */
432
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100433static int
paul718e3742002-12-13 20:15:29 +0000434smux_set (oid *reqid, size_t *reqid_len,
435 u_char val_type, void *val, size_t val_len, int action)
436{
437 int j;
438 struct subtree *subtree;
439 struct variable *v;
440 int subresult;
441 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000442 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000443 int result;
444 u_char *statP = NULL;
445 WriteMethod *write_method = NULL;
paul1eb8ef22005-04-07 07:30:20 +0000446 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000447
448 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000449 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +0000450 {
paul718e3742002-12-13 20:15:29 +0000451 subresult = oid_compare_part (reqid, *reqid_len,
452 subtree->name, subtree->name_len);
453
454 /* Subtree matched. */
455 if (subresult == 0)
456 {
457 /* Prepare suffix. */
458 suffix = reqid + subtree->name_len;
459 suffix_len = *reqid_len - subtree->name_len;
460 result = subresult;
461
462 /* Check variables. */
463 for (j = 0; j < subtree->variables_num; j++)
464 {
465 v = &subtree->variables[j];
466
467 /* Always check suffix */
468 result = oid_compare_part (suffix, suffix_len,
469 v->name, v->namelen);
470
471 /* This is exact match so result must be zero. */
472 if (result == 0)
473 {
474 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000475 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000476
477 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
478 &val_len, &write_method);
479
480 if (write_method)
481 {
482 return (*write_method)(action, val, val_type, val_len,
483 statP, suffix, suffix_len, v);
484 }
485 else
486 {
487 return SNMP_ERR_READONLY;
488 }
489 }
490
491 /* If above execution is failed or oid is small (so
492 there is no further match). */
493 if (result < 0)
494 return SNMP_ERR_NOSUCHNAME;
495 }
496 }
497 }
498 return SNMP_ERR_NOSUCHNAME;
499}
500
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100501static int
paul718e3742002-12-13 20:15:29 +0000502smux_get (oid *reqid, size_t *reqid_len, int exact,
503 u_char *val_type,void **val, size_t *val_len)
504{
505 int j;
506 struct subtree *subtree;
507 struct variable *v;
508 int subresult;
509 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000510 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000511 int result;
512 WriteMethod *write_method=NULL;
paul1eb8ef22005-04-07 07:30:20 +0000513 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000514
515 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000516 for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree))
paul718e3742002-12-13 20:15:29 +0000517 {
paul718e3742002-12-13 20:15:29 +0000518 subresult = oid_compare_part (reqid, *reqid_len,
519 subtree->name, subtree->name_len);
520
521 /* Subtree matched. */
522 if (subresult == 0)
523 {
524 /* Prepare suffix. */
525 suffix = reqid + subtree->name_len;
526 suffix_len = *reqid_len - subtree->name_len;
527 result = subresult;
528
529 /* Check variables. */
530 for (j = 0; j < subtree->variables_num; j++)
531 {
532 v = &subtree->variables[j];
533
534 /* Always check suffix */
535 result = oid_compare_part (suffix, suffix_len,
536 v->name, v->namelen);
537
538 /* This is exact match so result must be zero. */
539 if (result == 0)
540 {
541 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000542 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000543
544 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
545 val_len, &write_method);
546
547 /* There is no instance. */
548 if (*val == NULL)
549 return SNMP_NOSUCHINSTANCE;
550
551 /* Call is suceed. */
552 *val_type = v->type;
553
554 return 0;
555 }
556
557 /* If above execution is failed or oid is small (so
558 there is no further match). */
559 if (result < 0)
560 return SNMP_ERR_NOSUCHNAME;
561 }
562 }
563 }
564 return SNMP_ERR_NOSUCHNAME;
565}
566
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100567static int
paul718e3742002-12-13 20:15:29 +0000568smux_getnext (oid *reqid, size_t *reqid_len, int exact,
569 u_char *val_type,void **val, size_t *val_len)
570{
571 int j;
572 oid save[MAX_OID_LEN];
573 int savelen = 0;
574 struct subtree *subtree;
575 struct variable *v;
576 int subresult;
577 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000578 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000579 int result;
580 WriteMethod *write_method=NULL;
paul1eb8ef22005-04-07 07:30:20 +0000581 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000582
583
584 /* Save incoming request. */
585 oid_copy (save, reqid, *reqid_len);
586 savelen = *reqid_len;
587
588 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000589 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +0000590 {
paul718e3742002-12-13 20:15:29 +0000591 subresult = oid_compare_part (reqid, *reqid_len,
592 subtree->name, subtree->name_len);
593
594 /* If request is in the tree. The agent has to make sure we
595 only receive requests we have registered for. */
596 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
597 behave as if it manages the whole SNMP MIB tree itself. It's the
598 duty of the master agent to collect the best answer and return it
599 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
600 :-). ucd-snmp really behaves bad here as it actually might ask
601 multiple times for the same GETNEXT request as it throws away the
602 answer when it expects it in a different subtree and might come
603 back later with the very same request. --jochen */
604
605 if (subresult <= 0)
606 {
607 /* Prepare suffix. */
608 suffix = reqid + subtree->name_len;
609 suffix_len = *reqid_len - subtree->name_len;
610 if (subresult < 0)
611 {
612 oid_copy(reqid, subtree->name, subtree->name_len);
613 *reqid_len = subtree->name_len;
614 }
615 for (j = 0; j < subtree->variables_num; j++)
616 {
617 result = subresult;
618 v = &subtree->variables[j];
619
620 /* Next then check result >= 0. */
621 if (result == 0)
622 result = oid_compare_part (suffix, suffix_len,
623 v->name, v->namelen);
624
625 if (result <= 0)
626 {
627 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000628 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000629 if(result<0)
630 {
631 oid_copy(suffix, v->name, v->namelen);
632 suffix_len = v->namelen;
633 }
634 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
635 val_len, &write_method);
636 *reqid_len = suffix_len + subtree->name_len;
637 if (*val)
638 {
639 *val_type = v->type;
640 return 0;
641 }
642 }
643 }
644 }
645 }
646 memcpy (reqid, save, savelen * sizeof(oid));
647 *reqid_len = savelen;
648
649 return SNMP_ERR_NOSUCHNAME;
650}
651
652/* GET message header. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100653static u_char *
654smux_parse_get_header (u_char *ptr, size_t *len, long *reqid)
paul718e3742002-12-13 20:15:29 +0000655{
656 u_char type;
657 long errstat;
658 long errindex;
659
660 /* Request ID. */
661 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
662
663 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000664 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
paul718e3742002-12-13 20:15:29 +0000665
666 /* Error status. */
667 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
668
669 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100670 zlog_debug ("SMUX GET errstat %ld len: %zd", errstat, *len);
paul718e3742002-12-13 20:15:29 +0000671
672 /* Error index. */
673 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
674
675 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100676 zlog_debug ("SMUX GET errindex %ld len: %zd", errindex, *len);
paul718e3742002-12-13 20:15:29 +0000677
678 return ptr;
679}
680
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100681static void
682smux_parse_set (u_char *ptr, size_t len, int action)
paul718e3742002-12-13 20:15:29 +0000683{
684 long reqid;
685 oid oid[MAX_OID_LEN];
686 size_t oid_len;
687 u_char val_type;
688 void *val;
689 size_t val_len;
690 int ret;
691
692 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100693 zlog_debug ("SMUX SET(%s) message parse: len %zd",
paul718e3742002-12-13 20:15:29 +0000694 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
695 len);
696
697 /* Parse SET message header. */
698 ptr = smux_parse_get_header (ptr, &len, &reqid);
699
700 /* Parse SET message object ID. */
701 ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
702
703 ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
704 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000705 zlog_debug ("SMUX SET ret %d", ret);
paul718e3742002-12-13 20:15:29 +0000706
707 /* Return result. */
708 if (RESERVE1 == action)
709 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
710}
711
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100712static void
713smux_parse_get (u_char *ptr, size_t len, int exact)
paul718e3742002-12-13 20:15:29 +0000714{
715 long reqid;
716 oid oid[MAX_OID_LEN];
717 size_t oid_len;
718 u_char val_type;
719 void *val;
720 size_t val_len;
721 int ret;
722
723 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100724 zlog_debug ("SMUX GET message parse: len %zd", len);
paul718e3742002-12-13 20:15:29 +0000725
726 /* Parse GET message header. */
727 ptr = smux_parse_get_header (ptr, &len, &reqid);
728
729 /* Parse GET message object ID. We needn't the value come */
730 ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
731
732 /* Traditional getstatptr. */
733 if (exact)
734 ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
735 else
736 ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
737
738 /* Return result. */
739 if (ret == 0)
740 smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
741 else
742 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
743}
744
745/* Parse SMUX_CLOSE message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100746static void
747smux_parse_close (u_char *ptr, int len)
paul718e3742002-12-13 20:15:29 +0000748{
749 long reason = 0;
750
751 while (len--)
752 {
753 reason = (reason << 8) | (long) *ptr;
754 ptr++;
755 }
756 zlog_info ("SMUX_CLOSE with reason: %ld", reason);
757}
758
759/* SMUX_RRSP message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100760static void
761smux_parse_rrsp (u_char *ptr, size_t len)
paul718e3742002-12-13 20:15:29 +0000762{
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100763 u_char val;
paul718e3742002-12-13 20:15:29 +0000764 long errstat;
765
766 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
767
768 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000769 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
paul718e3742002-12-13 20:15:29 +0000770}
771
772/* Parse SMUX message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100773static int
774smux_parse (u_char *ptr, size_t len)
paul718e3742002-12-13 20:15:29 +0000775{
776 /* This buffer we'll use for SOUT message. We could allocate it with
777 malloc and save only static pointer/lenght, but IMHO static
778 buffer is a faster solusion. */
779 static u_char sout_save_buff[SMUXMAXPKTSIZE];
780 static int sout_save_len = 0;
781
782 int len_income = len; /* see note below: YYY */
783 u_char type;
784 u_char rollback;
785
786 rollback = ptr[2]; /* important only for SMUX_SOUT */
787
788process_rest: /* see note below: YYY */
789
790 /* Parse SMUX message type and subsequent length. */
791 ptr = asn_parse_header (ptr, &len, &type);
792
793 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100794 zlog_debug ("SMUX message received type: %d rest len: %zd", type, len);
paul718e3742002-12-13 20:15:29 +0000795
796 switch (type)
797 {
798 case SMUX_OPEN:
799 /* Open must be not send from SNMP agent. */
800 zlog_warn ("SMUX_OPEN received: resetting connection.");
801 return -1;
802 break;
803 case SMUX_RREQ:
804 /* SMUX_RREQ message is invalid for us. */
805 zlog_warn ("SMUX_RREQ received: resetting connection.");
806 return -1;
807 break;
808 case SMUX_SOUT:
809 /* SMUX_SOUT message is now valied for us. */
810 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000811 zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
paul718e3742002-12-13 20:15:29 +0000812
813 if (sout_save_len > 0)
814 {
815 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
816 sout_save_len = 0;
817 }
818 else
819 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
820
821 if (len_income > 3)
822 {
823 /* YYY: this strange code has to solve the "slow peer"
824 problem: When agent sends SMUX_SOUT message it doesn't
825 wait any responce and may send some next message to
826 subagent. Then the peer in 'smux_read()' will recieve
827 from socket the 'concatenated' buffer, contaning both
828 SMUX_SOUT message and the next one
829 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
830 the buffer is longer than 3 ( length of SMUX_SOUT ), we
831 must process the rest of it. This effect may be observed
832 if 'debug_smux' is set to '1' */
833 ptr++;
834 len = len_income - 3;
835 goto process_rest;
836 }
837 break;
838 case SMUX_GETRSP:
839 /* SMUX_GETRSP message is invalid for us. */
840 zlog_warn ("SMUX_GETRSP received: resetting connection.");
841 return -1;
842 break;
843 case SMUX_CLOSE:
844 /* Close SMUX connection. */
845 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000846 zlog_debug ("SMUX_CLOSE");
paul718e3742002-12-13 20:15:29 +0000847 smux_parse_close (ptr, len);
848 return -1;
849 break;
850 case SMUX_RRSP:
851 /* This is response for register message. */
852 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000853 zlog_debug ("SMUX_RRSP");
paul718e3742002-12-13 20:15:29 +0000854 smux_parse_rrsp (ptr, len);
855 break;
856 case SMUX_GET:
857 /* Exact request for object id. */
858 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000859 zlog_debug ("SMUX_GET");
paul718e3742002-12-13 20:15:29 +0000860 smux_parse_get (ptr, len, 1);
861 break;
862 case SMUX_GETNEXT:
863 /* Next request for object id. */
864 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000865 zlog_debug ("SMUX_GETNEXT");
paul718e3742002-12-13 20:15:29 +0000866 smux_parse_get (ptr, len, 0);
867 break;
868 case SMUX_SET:
869 /* SMUX_SET is supported with some limitations. */
870 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000871 zlog_debug ("SMUX_SET");
paul718e3742002-12-13 20:15:29 +0000872
873 /* save the data for future SMUX_SOUT */
874 memcpy (sout_save_buff, ptr, len);
875 sout_save_len = len;
876 smux_parse_set (ptr, len, RESERVE1);
877 break;
878 default:
879 zlog_info ("Unknown type: %d", type);
880 break;
881 }
882 return 0;
883}
884
885/* SMUX message read function. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100886static int
paul718e3742002-12-13 20:15:29 +0000887smux_read (struct thread *t)
888{
889 int sock;
890 int len;
891 u_char buf[SMUXMAXPKTSIZE];
892 int ret;
893
894 /* Clear thread. */
895 sock = THREAD_FD (t);
896 smux_read_thread = NULL;
897
898 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000899 zlog_debug ("SMUX read start");
paul718e3742002-12-13 20:15:29 +0000900
901 /* Read message from SMUX socket. */
902 len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
903
904 if (len < 0)
905 {
ajs6099b3b2004-11-20 02:06:59 +0000906 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000907 close (sock);
908 smux_sock = -1;
909 smux_event (SMUX_CONNECT, 0);
910 return -1;
911 }
912
913 if (len == 0)
914 {
915 zlog_warn ("SMUX connection closed: %d", sock);
916 close (sock);
917 smux_sock = -1;
918 smux_event (SMUX_CONNECT, 0);
919 return -1;
920 }
921
922 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000923 zlog_debug ("SMUX read len: %d", len);
paul718e3742002-12-13 20:15:29 +0000924
925 /* Parse the message. */
926 ret = smux_parse (buf, len);
927
928 if (ret < 0)
929 {
930 close (sock);
931 smux_sock = -1;
932 smux_event (SMUX_CONNECT, 0);
933 return -1;
934 }
935
936 /* Regiser read thread. */
937 smux_event (SMUX_READ, sock);
938
939 return 0;
940}
941
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100942static int
paul718e3742002-12-13 20:15:29 +0000943smux_open (int sock)
944{
945 u_char buf[BUFSIZ];
946 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +0000947 size_t len;
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100948 long version;
paul42053f42003-08-13 02:54:44 +0000949 u_char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION;
paul718e3742002-12-13 20:15:29 +0000950
951 if (debug_smux)
952 {
953 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
ajs8ddca702004-12-07 18:53:52 +0000954 zlog_debug ("SMUX open progname: %s", progname);
955 zlog_debug ("SMUX open password: %s", smux_passwd);
paul718e3742002-12-13 20:15:29 +0000956 }
957
958 ptr = buf;
959 len = BUFSIZ;
960
961 /* SMUX Header. As placeholder. */
962 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
963
964 /* SMUX Open. */
965 version = 0;
966 ptr = asn_build_int (ptr, &len,
967 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +0000968 &version, sizeof (version));
paul718e3742002-12-13 20:15:29 +0000969
970 /* SMUX connection oid. */
971 ptr = asn_build_objid (ptr, &len,
972 (u_char)
973 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
974 smux_oid, smux_oid_len);
975
976 /* SMUX connection description. */
977 ptr = asn_build_string (ptr, &len,
978 (u_char)
979 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
980 progname, strlen (progname));
981
982 /* SMUX connection password. */
983 ptr = asn_build_string (ptr, &len,
984 (u_char)
985 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100986 (u_char *)smux_passwd, strlen (smux_passwd));
paul718e3742002-12-13 20:15:29 +0000987
988 /* Fill in real SMUX header. We exclude ASN header size (2). */
989 len = BUFSIZ;
990 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
991
992 return send (sock, buf, (ptr - buf), 0);
993}
994
995int
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -0700996smux_trap (const oid *name, size_t namelen,
997 const oid *iname, size_t inamelen,
998 const struct trap_object *trapobj, size_t trapobjlen,
paul020709f2003-04-04 02:44:16 +0000999 unsigned int tick, u_char sptrap)
paul718e3742002-12-13 20:15:29 +00001000{
paul9035efa2004-10-10 11:56:56 +00001001 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001002 u_char buf[BUFSIZ];
1003 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +00001004 size_t len, length;
paul718e3742002-12-13 20:15:29 +00001005 struct in_addr addr;
1006 unsigned long val;
1007 u_char *h1, *h1e;
1008
1009 ptr = buf;
1010 len = BUFSIZ;
1011 length = len;
1012
1013 /* When SMUX connection is not established. */
1014 if (smux_sock < 0)
1015 return 0;
1016
1017 /* SMUX header. */
1018 ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
1019
1020 /* Sub agent enterprise oid. */
1021 ptr = asn_build_objid (ptr, &len,
1022 (u_char)
1023 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1024 smux_oid, smux_oid_len);
1025
1026 /* IP address. */
1027 addr.s_addr = 0;
1028 ptr = asn_build_string (ptr, &len,
1029 (u_char)
1030 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001031 (u_char *)&addr, sizeof (addr));
paul718e3742002-12-13 20:15:29 +00001032
1033 /* Generic trap integer. */
1034 val = SNMP_TRAP_ENTERPRISESPECIFIC;
1035 ptr = asn_build_int (ptr, &len,
1036 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001037 (long *)&val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001038
1039 /* Specific trap integer. */
paul020709f2003-04-04 02:44:16 +00001040 val = sptrap;
paul718e3742002-12-13 20:15:29 +00001041 ptr = asn_build_int (ptr, &len,
1042 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001043 (long *)&val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001044
1045 /* Timeticks timestamp. */
1046 val = 0;
1047 ptr = asn_build_unsigned_int (ptr, &len,
1048 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001049 &val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001050
1051 /* Variables. */
1052 h1 = ptr;
1053 ptr = asn_build_sequence (ptr, &len,
1054 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1055 0);
1056
1057
1058 /* Iteration for each objects. */
1059 h1e = ptr;
1060 for (i = 0; i < trapobjlen; i++)
1061 {
1062 int ret;
1063 oid oid[MAX_OID_LEN];
1064 size_t oid_len;
1065 void *val;
1066 size_t val_len;
1067 u_char val_type;
1068
1069 /* Make OID. */
vincent5e4914c2005-09-29 16:34:30 +00001070 if (trapobj[i].namelen > 0)
1071 {
1072 oid_copy (oid, name, namelen);
1073 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen);
1074 oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen);
1075 oid_len = namelen + trapobj[i].namelen + inamelen;
1076 }
1077 else
1078 {
1079 oid_copy (oid, name, namelen);
1080 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen * (-1));
1081 oid_len = namelen + trapobj[i].namelen * (-1) ;
1082 }
paul718e3742002-12-13 20:15:29 +00001083
vincent5e4914c2005-09-29 16:34:30 +00001084 if (debug_smux)
1085 {
1086 smux_oid_dump ("Trap", name, namelen);
1087 if (trapobj[i].namelen < 0)
1088 smux_oid_dump ("Trap",
1089 trapobj[i].name, (- 1) * (trapobj[i].namelen));
1090 else
1091 {
1092 smux_oid_dump ("Trap", trapobj[i].name, (trapobj[i].namelen));
1093 smux_oid_dump ("Trap", iname, inamelen);
1094 }
1095 smux_oid_dump ("Trap", oid, oid_len);
Andrew J. Schorreda9ba72007-04-27 18:13:15 +00001096 zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ, (u_long)oid_len);
vincent5e4914c2005-09-29 16:34:30 +00001097 }
paul718e3742002-12-13 20:15:29 +00001098
1099 ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
1100
1101 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +00001102 zlog_debug ("smux_get result %d", ret);
paul718e3742002-12-13 20:15:29 +00001103
1104 if (ret == 0)
1105 ptr = snmp_build_var_op (ptr, oid, &oid_len,
1106 val_type, val_len, val, &len);
1107 }
1108
1109 /* Now variable size is known, fill in size */
1110 asn_build_sequence(h1, &length,
1111 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1112 ptr - h1e);
1113
1114 /* Fill in size of whole sequence */
1115 len = BUFSIZ;
1116 asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
1117
1118 return send (smux_sock, buf, (ptr - buf), 0);
1119}
1120
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001121static int
paul718e3742002-12-13 20:15:29 +00001122smux_register (int sock)
1123{
1124 u_char buf[BUFSIZ];
1125 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +00001126 int ret;
1127 size_t len;
paul718e3742002-12-13 20:15:29 +00001128 long priority;
1129 long operation;
1130 struct subtree *subtree;
paul1eb8ef22005-04-07 07:30:20 +00001131 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00001132
1133 ret = 0;
1134
paul1eb8ef22005-04-07 07:30:20 +00001135 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +00001136 {
1137 ptr = buf;
1138 len = BUFSIZ;
1139
paul718e3742002-12-13 20:15:29 +00001140 /* SMUX RReq Header. */
1141 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
1142
1143 /* Register MIB tree. */
1144 ptr = asn_build_objid (ptr, &len,
1145 (u_char)
1146 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1147 subtree->name, subtree->name_len);
1148
1149 /* Priority. */
1150 priority = -1;
1151 ptr = asn_build_int (ptr, &len,
1152 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001153 &priority, sizeof (priority));
paul718e3742002-12-13 20:15:29 +00001154
1155 /* Operation. */
1156 operation = 2; /* Register R/W */
1157 ptr = asn_build_int (ptr, &len,
1158 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001159 &operation, sizeof (operation));
paul718e3742002-12-13 20:15:29 +00001160
1161 if (debug_smux)
1162 {
1163 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
ajs8ddca702004-12-07 18:53:52 +00001164 zlog_debug ("SMUX register priority: %ld", priority);
1165 zlog_debug ("SMUX register operation: %ld", operation);
paul718e3742002-12-13 20:15:29 +00001166 }
1167
1168 len = BUFSIZ;
1169 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
1170 ret = send (sock, buf, (ptr - buf), 0);
1171 if (ret < 0)
1172 return ret;
1173 }
1174 return ret;
1175}
1176
1177/* Try to connect to SNMP agent. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001178static int
paul718e3742002-12-13 20:15:29 +00001179smux_connect (struct thread *t)
1180{
1181 int ret;
1182
1183 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +00001184 zlog_debug ("SMUX connect try %d", fail + 1);
paul718e3742002-12-13 20:15:29 +00001185
1186 /* Clear thread poner of myself. */
1187 smux_connect_thread = NULL;
1188
1189 /* Make socket. Try to connect. */
1190 smux_sock = smux_socket ();
1191 if (smux_sock < 0)
1192 {
1193 if (++fail < SMUX_MAX_FAILURE)
1194 smux_event (SMUX_CONNECT, 0);
1195 return 0;
1196 }
1197
1198 /* Send OPEN PDU. */
1199 ret = smux_open (smux_sock);
1200 if (ret < 0)
1201 {
ajs6099b3b2004-11-20 02:06:59 +00001202 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001203 close (smux_sock);
1204 smux_sock = -1;
1205 if (++fail < SMUX_MAX_FAILURE)
1206 smux_event (SMUX_CONNECT, 0);
1207 return -1;
1208 }
1209
1210 /* Send any outstanding register PDUs. */
1211 ret = smux_register (smux_sock);
1212 if (ret < 0)
1213 {
ajs6099b3b2004-11-20 02:06:59 +00001214 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001215 close (smux_sock);
1216 smux_sock = -1;
1217 if (++fail < SMUX_MAX_FAILURE)
1218 smux_event (SMUX_CONNECT, 0);
1219 return -1;
1220 }
1221
1222 /* Everything goes fine. */
1223 smux_event (SMUX_READ, smux_sock);
1224
1225 return 0;
1226}
1227
1228/* Clear all SMUX related resources. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001229static void
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -07001230smux_stop (void)
paul718e3742002-12-13 20:15:29 +00001231{
1232 if (smux_read_thread)
Paul Jakmaa56ef882007-10-22 15:53:17 +00001233 {
1234 thread_cancel (smux_read_thread);
1235 smux_read_thread = NULL;
1236 }
1237
paul718e3742002-12-13 20:15:29 +00001238 if (smux_connect_thread)
Paul Jakmaa56ef882007-10-22 15:53:17 +00001239 {
1240 thread_cancel (smux_connect_thread);
1241 smux_connect_thread = NULL;
1242 }
paul718e3742002-12-13 20:15:29 +00001243
1244 if (smux_sock >= 0)
1245 {
1246 close (smux_sock);
1247 smux_sock = -1;
1248 }
1249}
1250
pauldd488a72003-06-19 01:21:07 +00001251
paul718e3742002-12-13 20:15:29 +00001252
1253void
1254smux_event (enum smux_event event, int sock)
1255{
1256 switch (event)
1257 {
1258 case SMUX_SCHEDULE:
1259 smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
1260 break;
1261 case SMUX_CONNECT:
1262 smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
1263 break;
1264 case SMUX_READ:
1265 smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
1266 break;
1267 default:
1268 break;
1269 }
1270}
1271
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001272static int
paul9035efa2004-10-10 11:56:56 +00001273smux_str2oid (const char *str, oid *oid, size_t *oid_len)
paul718e3742002-12-13 20:15:29 +00001274{
1275 int len;
1276 int val;
1277
1278 len = 0;
1279 val = 0;
1280 *oid_len = 0;
1281
1282 if (*str == '.')
1283 str++;
1284 if (*str == '\0')
1285 return 0;
1286
1287 while (1)
1288 {
1289 if (! isdigit (*str))
1290 return -1;
1291
1292 while (isdigit (*str))
1293 {
1294 val *= 10;
1295 val += (*str - '0');
1296 str++;
1297 }
1298
1299 if (*str == '\0')
1300 break;
1301 if (*str != '.')
1302 return -1;
1303
1304 oid[len++] = val;
1305 val = 0;
1306 str++;
1307 }
1308
1309 oid[len++] = val;
1310 *oid_len = len;
1311
1312 return 0;
1313}
1314
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001315static oid *
paul718e3742002-12-13 20:15:29 +00001316smux_oid_dup (oid *objid, size_t objid_len)
1317{
1318 oid *new;
1319
1320 new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
1321 oid_copy (new, objid, objid_len);
1322
1323 return new;
1324}
1325
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001326static int
paul9035efa2004-10-10 11:56:56 +00001327smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str)
paul718e3742002-12-13 20:15:29 +00001328{
1329 int ret;
1330 oid oid[MAX_OID_LEN];
1331 size_t oid_len;
1332
1333 ret = smux_str2oid (oid_str, oid, &oid_len);
1334 if (ret != 0)
1335 {
1336 vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
1337 return CMD_WARNING;
1338 }
1339
hassoc75105a2004-10-13 10:33:26 +00001340 if (smux_oid)
1341 {
1342 free (smux_oid);
1343 smux_oid = NULL;
1344 }
paul718e3742002-12-13 20:15:29 +00001345
paul9035efa2004-10-10 11:56:56 +00001346 /* careful, smux_passwd might point to string constant */
hassoc75105a2004-10-13 10:33:26 +00001347 if (smux_passwd)
paul718e3742002-12-13 20:15:29 +00001348 {
1349 free (smux_passwd);
1350 smux_passwd = NULL;
1351 }
1352
1353 smux_oid = smux_oid_dup (oid, oid_len);
1354 smux_oid_len = oid_len;
1355
1356 if (passwd_str)
1357 smux_passwd = strdup (passwd_str);
hassoc75105a2004-10-13 10:33:26 +00001358 else
1359 smux_passwd = strdup ("");
paul718e3742002-12-13 20:15:29 +00001360
hassoc75105a2004-10-13 10:33:26 +00001361 return 0;
paul718e3742002-12-13 20:15:29 +00001362}
1363
1364int
1365smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1366 size_t *var_len, WriteMethod **write_method)
1367{
1368 oid fulloid[MAX_OID_LEN];
1369 int ret;
1370
1371 oid_copy (fulloid, v->name, v->namelen);
1372 fulloid[v->namelen] = 0;
1373 /* Check against full instance. */
1374 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1375
1376 /* Check single instance. */
1377 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1378 return MATCH_FAILED;
1379
1380 /* In case of getnext, fill in full instance. */
1381 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1382 *length = v->namelen + 1;
1383
1384 *write_method = 0;
1385 *var_len = sizeof(long); /* default to 'long' results */
1386
1387 return MATCH_SUCCEEDED;
1388}
1389
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001390static int
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -07001391smux_peer_default (void)
paul718e3742002-12-13 20:15:29 +00001392{
hassoc75105a2004-10-13 10:33:26 +00001393 if (smux_oid)
paul718e3742002-12-13 20:15:29 +00001394 {
1395 free (smux_oid);
hassoc75105a2004-10-13 10:33:26 +00001396 smux_oid = NULL;
paul718e3742002-12-13 20:15:29 +00001397 }
paul9035efa2004-10-10 11:56:56 +00001398
1399 /* careful, smux_passwd might be pointing at string constant */
hassoc75105a2004-10-13 10:33:26 +00001400 if (smux_passwd)
paul718e3742002-12-13 20:15:29 +00001401 {
1402 free (smux_passwd);
hassoc75105a2004-10-13 10:33:26 +00001403 smux_passwd = NULL;
paul718e3742002-12-13 20:15:29 +00001404 }
hassoc75105a2004-10-13 10:33:26 +00001405
paul718e3742002-12-13 20:15:29 +00001406 return CMD_SUCCESS;
1407}
1408
1409DEFUN (smux_peer,
1410 smux_peer_cmd,
1411 "smux peer OID",
1412 "SNMP MUX protocol settings\n"
1413 "SNMP MUX peer settings\n"
1414 "Object ID used in SMUX peering\n")
1415{
hassoc75105a2004-10-13 10:33:26 +00001416 if (smux_peer_oid (vty, argv[0], NULL) == 0)
1417 {
1418 smux_start();
1419 return CMD_SUCCESS;
1420 }
1421 else
1422 return CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00001423}
1424
1425DEFUN (smux_peer_password,
1426 smux_peer_password_cmd,
1427 "smux peer OID PASSWORD",
1428 "SNMP MUX protocol settings\n"
1429 "SNMP MUX peer settings\n"
1430 "SMUX peering object ID\n"
1431 "SMUX peering password\n")
1432{
hassoc75105a2004-10-13 10:33:26 +00001433 if (smux_peer_oid (vty, argv[0], argv[1]) == 0)
1434 {
1435 smux_start();
1436 return CMD_SUCCESS;
1437 }
1438 else
1439 return CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00001440}
1441
1442DEFUN (no_smux_peer,
1443 no_smux_peer_cmd,
hassoc75105a2004-10-13 10:33:26 +00001444 "no smux peer",
1445 NO_STR
1446 "SNMP MUX protocol settings\n"
1447 "SNMP MUX peer settings\n")
1448{
1449 smux_stop();
1450 return smux_peer_default ();
1451}
1452
1453ALIAS (no_smux_peer,
1454 no_smux_peer_oid_cmd,
paul718e3742002-12-13 20:15:29 +00001455 "no smux peer OID",
1456 NO_STR
1457 "SNMP MUX protocol settings\n"
1458 "SNMP MUX peer settings\n"
hassoc75105a2004-10-13 10:33:26 +00001459 "SMUX peering object ID\n")
paul718e3742002-12-13 20:15:29 +00001460
hassoc75105a2004-10-13 10:33:26 +00001461ALIAS (no_smux_peer,
1462 no_smux_peer_oid_password_cmd,
paul718e3742002-12-13 20:15:29 +00001463 "no smux peer OID PASSWORD",
1464 NO_STR
1465 "SNMP MUX protocol settings\n"
1466 "SNMP MUX peer settings\n"
1467 "SMUX peering object ID\n"
1468 "SMUX peering password\n")
paul718e3742002-12-13 20:15:29 +00001469
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001470static int
paul718e3742002-12-13 20:15:29 +00001471config_write_smux (struct vty *vty)
1472{
1473 int first = 1;
paul9035efa2004-10-10 11:56:56 +00001474 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001475
hassoc75105a2004-10-13 10:33:26 +00001476 if (smux_oid)
paul718e3742002-12-13 20:15:29 +00001477 {
1478 vty_out (vty, "smux peer ");
1479 for (i = 0; i < smux_oid_len; i++)
1480 {
1481 vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
1482 first = 0;
1483 }
1484 vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
1485 }
1486 return 0;
1487}
1488
1489/* Register subtree to smux master tree. */
1490void
paulc9eca012004-10-11 11:28:44 +00001491smux_register_mib (const char *descr, struct variable *var,
1492 size_t width, int num,
paul718e3742002-12-13 20:15:29 +00001493 oid name[], size_t namelen)
1494{
1495 struct subtree *tree;
1496
1497 tree = (struct subtree *)malloc(sizeof(struct subtree));
1498 oid_copy (tree->name, name, namelen);
1499 tree->name_len = namelen;
1500 tree->variables = var;
1501 tree->variables_num = num;
1502 tree->variables_width = width;
1503 tree->registered = 0;
1504 listnode_add_sort(treelist, tree);
1505}
1506
paul718e3742002-12-13 20:15:29 +00001507/* Compare function to keep treelist sorted */
1508static int
1509smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
1510{
1511 return oid_compare(tree1->name, tree1->name_len,
1512 tree2->name, tree2->name_len);
1513}
1514
1515/* Initialize some values then schedule first SMUX connection. */
1516void
hassoc75105a2004-10-13 10:33:26 +00001517smux_init (struct thread_master *tm)
paul718e3742002-12-13 20:15:29 +00001518{
pauldd488a72003-06-19 01:21:07 +00001519 /* copy callers thread master */
1520 master = tm;
paul718e3742002-12-13 20:15:29 +00001521
1522 /* Make MIB tree. */
1523 treelist = list_new();
1524 treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
1525
1526 /* Install commands. */
1527 install_node (&smux_node, config_write_smux);
1528
1529 install_element (CONFIG_NODE, &smux_peer_cmd);
1530 install_element (CONFIG_NODE, &smux_peer_password_cmd);
1531 install_element (CONFIG_NODE, &no_smux_peer_cmd);
hassoc75105a2004-10-13 10:33:26 +00001532 install_element (CONFIG_NODE, &no_smux_peer_oid_cmd);
1533 install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd);
paul718e3742002-12-13 20:15:29 +00001534}
1535
1536void
1537smux_start(void)
1538{
Paul Jakmaa56ef882007-10-22 15:53:17 +00001539 /* Close any existing connections. */
1540 smux_stop();
1541
paul718e3742002-12-13 20:15:29 +00001542 /* Schedule first connection. */
1543 smux_event (SMUX_SCHEDULE, 0);
1544}
1545#endif /* HAVE_SNMP */