blob: b7cd18d14d644a7a35fba38eae9b7d6711e9fbba [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{
paul718e3742002-12-13 20:15:29 +0000273 u_char buf[BUFSIZ];
274 u_char *ptr, *h1, *h1e, *h2, *h2e;
paul70e149e2004-10-31 16:29:50 +0000275 size_t len, length;
paul718e3742002-12-13 20:15:29 +0000276
277 ptr = buf;
278 len = BUFSIZ;
279 length = len;
280
281 if (debug_smux)
282 {
ajs8ddca702004-12-07 18:53:52 +0000283 zlog_debug ("SMUX GETRSP send");
284 zlog_debug ("SMUX GETRSP reqid: %ld", reqid);
paul718e3742002-12-13 20:15:29 +0000285 }
286
287 h1 = ptr;
288 /* Place holder h1 for complete sequence */
289 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
290 h1e = ptr;
291
292 ptr = asn_build_int (ptr, &len,
293 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
294 &reqid, sizeof (reqid));
295
296 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000297 zlog_debug ("SMUX GETRSP errstat: %ld", errstat);
paul718e3742002-12-13 20:15:29 +0000298
299 ptr = asn_build_int (ptr, &len,
300 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
301 &errstat, sizeof (errstat));
302 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000303 zlog_debug ("SMUX GETRSP errindex: %ld", errindex);
paul718e3742002-12-13 20:15:29 +0000304
305 ptr = asn_build_int (ptr, &len,
306 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
307 &errindex, sizeof (errindex));
308
309 h2 = ptr;
310 /* Place holder h2 for one variable */
311 ptr = asn_build_sequence (ptr, &len,
312 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
313 0);
314 h2e = ptr;
315
316 ptr = snmp_build_var_op (ptr, objid, &objid_len,
317 val_type, arg_len, arg, &len);
318
319 /* Now variable size is known, fill in size */
320 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
321
322 /* Fill in size of whole sequence */
323 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
324
325 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100326 zlog_debug ("SMUX getresp send: %td", (ptr - buf));
paul718e3742002-12-13 20:15:29 +0000327
Stephen Hemminger004b1232011-12-07 00:55:15 +0400328 send (smux_sock, buf, (ptr - buf), 0);
paul718e3742002-12-13 20:15:29 +0000329}
330
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100331static u_char *
332smux_var (u_char *ptr, size_t len, oid objid[], size_t *objid_len,
paul718e3742002-12-13 20:15:29 +0000333 size_t *var_val_len,
334 u_char *var_val_type,
335 void **var_value)
336{
337 u_char type;
338 u_char val_type;
339 size_t val_len;
340 u_char *val;
341
342 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100343 zlog_debug ("SMUX var parse: len %zd", len);
paul718e3742002-12-13 20:15:29 +0000344
345 /* Parse header. */
346 ptr = asn_parse_header (ptr, &len, &type);
347
348 if (debug_smux)
349 {
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100350 zlog_debug ("SMUX var parse: type %d len %zd", type, len);
ajs8ddca702004-12-07 18:53:52 +0000351 zlog_debug ("SMUX var parse: type must be %d",
paul718e3742002-12-13 20:15:29 +0000352 (ASN_SEQUENCE | ASN_CONSTRUCTOR));
353 }
354
355 /* Parse var option. */
356 *objid_len = MAX_OID_LEN;
357 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
358 &val_len, &val, &len);
359
360 if (var_val_len)
361 *var_val_len = val_len;
362
363 if (var_value)
364 *var_value = (void*) val;
365
366 if (var_val_type)
367 *var_val_type = val_type;
368
369 /* Requested object id length is objid_len. */
370 if (debug_smux)
371 smux_oid_dump ("Request OID", objid, *objid_len);
372
373 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000374 zlog_debug ("SMUX val_type: %d", val_type);
paul718e3742002-12-13 20:15:29 +0000375
376 /* Check request value type. */
377 if (debug_smux)
378 switch (val_type)
379 {
380 case ASN_NULL:
381 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
382 ASN_NULL. */
ajs8ddca702004-12-07 18:53:52 +0000383 zlog_debug ("ASN_NULL");
paul718e3742002-12-13 20:15:29 +0000384 break;
385
386 case ASN_INTEGER:
ajs8ddca702004-12-07 18:53:52 +0000387 zlog_debug ("ASN_INTEGER");
paul718e3742002-12-13 20:15:29 +0000388 break;
389 case ASN_COUNTER:
390 case ASN_GAUGE:
391 case ASN_TIMETICKS:
392 case ASN_UINTEGER:
ajs8ddca702004-12-07 18:53:52 +0000393 zlog_debug ("ASN_COUNTER");
paul718e3742002-12-13 20:15:29 +0000394 break;
395 case ASN_COUNTER64:
ajs8ddca702004-12-07 18:53:52 +0000396 zlog_debug ("ASN_COUNTER64");
paul718e3742002-12-13 20:15:29 +0000397 break;
398 case ASN_IPADDRESS:
ajs8ddca702004-12-07 18:53:52 +0000399 zlog_debug ("ASN_IPADDRESS");
paul718e3742002-12-13 20:15:29 +0000400 break;
401 case ASN_OCTET_STR:
ajs8ddca702004-12-07 18:53:52 +0000402 zlog_debug ("ASN_OCTET_STR");
paul718e3742002-12-13 20:15:29 +0000403 break;
404 case ASN_OPAQUE:
405 case ASN_NSAP:
406 case ASN_OBJECT_ID:
ajs8ddca702004-12-07 18:53:52 +0000407 zlog_debug ("ASN_OPAQUE");
paul718e3742002-12-13 20:15:29 +0000408 break;
409 case SNMP_NOSUCHOBJECT:
ajs8ddca702004-12-07 18:53:52 +0000410 zlog_debug ("SNMP_NOSUCHOBJECT");
paul718e3742002-12-13 20:15:29 +0000411 break;
412 case SNMP_NOSUCHINSTANCE:
ajs8ddca702004-12-07 18:53:52 +0000413 zlog_debug ("SNMP_NOSUCHINSTANCE");
paul718e3742002-12-13 20:15:29 +0000414 break;
415 case SNMP_ENDOFMIBVIEW:
ajs8ddca702004-12-07 18:53:52 +0000416 zlog_debug ("SNMP_ENDOFMIBVIEW");
paul718e3742002-12-13 20:15:29 +0000417 break;
418 case ASN_BIT_STR:
ajs8ddca702004-12-07 18:53:52 +0000419 zlog_debug ("ASN_BIT_STR");
paul718e3742002-12-13 20:15:29 +0000420 break;
421 default:
ajs8ddca702004-12-07 18:53:52 +0000422 zlog_debug ("Unknown type");
paul718e3742002-12-13 20:15:29 +0000423 break;
424 }
425 return ptr;
426}
427
428/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
429 ucd-snmp smux and as such suppose, that the peer receives in the message
430 only one variable. Fortunately, IBM seems to do the same in AIX. */
431
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100432static int
paul718e3742002-12-13 20:15:29 +0000433smux_set (oid *reqid, size_t *reqid_len,
434 u_char val_type, void *val, size_t val_len, int action)
435{
436 int j;
437 struct subtree *subtree;
438 struct variable *v;
439 int subresult;
440 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000441 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000442 int result;
443 u_char *statP = NULL;
444 WriteMethod *write_method = NULL;
paul1eb8ef22005-04-07 07:30:20 +0000445 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000446
447 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000448 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +0000449 {
paul718e3742002-12-13 20:15:29 +0000450 subresult = oid_compare_part (reqid, *reqid_len,
451 subtree->name, subtree->name_len);
452
453 /* Subtree matched. */
454 if (subresult == 0)
455 {
456 /* Prepare suffix. */
457 suffix = reqid + subtree->name_len;
458 suffix_len = *reqid_len - subtree->name_len;
459 result = subresult;
460
461 /* Check variables. */
462 for (j = 0; j < subtree->variables_num; j++)
463 {
464 v = &subtree->variables[j];
465
466 /* Always check suffix */
467 result = oid_compare_part (suffix, suffix_len,
468 v->name, v->namelen);
469
470 /* This is exact match so result must be zero. */
471 if (result == 0)
472 {
473 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000474 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000475
476 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
477 &val_len, &write_method);
478
479 if (write_method)
480 {
481 return (*write_method)(action, val, val_type, val_len,
482 statP, suffix, suffix_len, v);
483 }
484 else
485 {
486 return SNMP_ERR_READONLY;
487 }
488 }
489
490 /* If above execution is failed or oid is small (so
491 there is no further match). */
492 if (result < 0)
493 return SNMP_ERR_NOSUCHNAME;
494 }
495 }
496 }
497 return SNMP_ERR_NOSUCHNAME;
498}
499
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100500static int
paul718e3742002-12-13 20:15:29 +0000501smux_get (oid *reqid, size_t *reqid_len, int exact,
502 u_char *val_type,void **val, size_t *val_len)
503{
504 int j;
505 struct subtree *subtree;
506 struct variable *v;
507 int subresult;
508 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000509 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000510 int result;
511 WriteMethod *write_method=NULL;
paul1eb8ef22005-04-07 07:30:20 +0000512 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000513
514 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000515 for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree))
paul718e3742002-12-13 20:15:29 +0000516 {
paul718e3742002-12-13 20:15:29 +0000517 subresult = oid_compare_part (reqid, *reqid_len,
518 subtree->name, subtree->name_len);
519
520 /* Subtree matched. */
521 if (subresult == 0)
522 {
523 /* Prepare suffix. */
524 suffix = reqid + subtree->name_len;
525 suffix_len = *reqid_len - subtree->name_len;
526 result = subresult;
527
528 /* Check variables. */
529 for (j = 0; j < subtree->variables_num; j++)
530 {
531 v = &subtree->variables[j];
532
533 /* Always check suffix */
534 result = oid_compare_part (suffix, suffix_len,
535 v->name, v->namelen);
536
537 /* This is exact match so result must be zero. */
538 if (result == 0)
539 {
540 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000541 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000542
543 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
544 val_len, &write_method);
545
546 /* There is no instance. */
547 if (*val == NULL)
548 return SNMP_NOSUCHINSTANCE;
549
550 /* Call is suceed. */
551 *val_type = v->type;
552
553 return 0;
554 }
555
556 /* If above execution is failed or oid is small (so
557 there is no further match). */
558 if (result < 0)
559 return SNMP_ERR_NOSUCHNAME;
560 }
561 }
562 }
563 return SNMP_ERR_NOSUCHNAME;
564}
565
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100566static int
paul718e3742002-12-13 20:15:29 +0000567smux_getnext (oid *reqid, size_t *reqid_len, int exact,
568 u_char *val_type,void **val, size_t *val_len)
569{
570 int j;
571 oid save[MAX_OID_LEN];
572 int savelen = 0;
573 struct subtree *subtree;
574 struct variable *v;
575 int subresult;
576 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000577 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000578 int result;
579 WriteMethod *write_method=NULL;
paul1eb8ef22005-04-07 07:30:20 +0000580 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000581
582
583 /* Save incoming request. */
584 oid_copy (save, reqid, *reqid_len);
585 savelen = *reqid_len;
586
587 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000588 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +0000589 {
paul718e3742002-12-13 20:15:29 +0000590 subresult = oid_compare_part (reqid, *reqid_len,
591 subtree->name, subtree->name_len);
592
593 /* If request is in the tree. The agent has to make sure we
594 only receive requests we have registered for. */
595 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
596 behave as if it manages the whole SNMP MIB tree itself. It's the
597 duty of the master agent to collect the best answer and return it
598 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
599 :-). ucd-snmp really behaves bad here as it actually might ask
600 multiple times for the same GETNEXT request as it throws away the
601 answer when it expects it in a different subtree and might come
602 back later with the very same request. --jochen */
603
604 if (subresult <= 0)
605 {
606 /* Prepare suffix. */
607 suffix = reqid + subtree->name_len;
608 suffix_len = *reqid_len - subtree->name_len;
609 if (subresult < 0)
610 {
611 oid_copy(reqid, subtree->name, subtree->name_len);
612 *reqid_len = subtree->name_len;
613 }
614 for (j = 0; j < subtree->variables_num; j++)
615 {
616 result = subresult;
617 v = &subtree->variables[j];
618
619 /* Next then check result >= 0. */
620 if (result == 0)
621 result = oid_compare_part (suffix, suffix_len,
622 v->name, v->namelen);
623
624 if (result <= 0)
625 {
626 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000627 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000628 if(result<0)
629 {
630 oid_copy(suffix, v->name, v->namelen);
631 suffix_len = v->namelen;
632 }
633 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
634 val_len, &write_method);
635 *reqid_len = suffix_len + subtree->name_len;
636 if (*val)
637 {
638 *val_type = v->type;
639 return 0;
640 }
641 }
642 }
643 }
644 }
645 memcpy (reqid, save, savelen * sizeof(oid));
646 *reqid_len = savelen;
647
648 return SNMP_ERR_NOSUCHNAME;
649}
650
651/* GET message header. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100652static u_char *
653smux_parse_get_header (u_char *ptr, size_t *len, long *reqid)
paul718e3742002-12-13 20:15:29 +0000654{
655 u_char type;
656 long errstat;
657 long errindex;
658
659 /* Request ID. */
660 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
661
662 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000663 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
paul718e3742002-12-13 20:15:29 +0000664
665 /* Error status. */
666 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
667
668 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100669 zlog_debug ("SMUX GET errstat %ld len: %zd", errstat, *len);
paul718e3742002-12-13 20:15:29 +0000670
671 /* Error index. */
672 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
673
674 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100675 zlog_debug ("SMUX GET errindex %ld len: %zd", errindex, *len);
paul718e3742002-12-13 20:15:29 +0000676
677 return ptr;
678}
679
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100680static void
681smux_parse_set (u_char *ptr, size_t len, int action)
paul718e3742002-12-13 20:15:29 +0000682{
683 long reqid;
684 oid oid[MAX_OID_LEN];
685 size_t oid_len;
686 u_char val_type;
687 void *val;
688 size_t val_len;
689 int ret;
690
691 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100692 zlog_debug ("SMUX SET(%s) message parse: len %zd",
paul718e3742002-12-13 20:15:29 +0000693 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
694 len);
695
696 /* Parse SET message header. */
697 ptr = smux_parse_get_header (ptr, &len, &reqid);
698
699 /* Parse SET message object ID. */
700 ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
701
702 ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
703 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000704 zlog_debug ("SMUX SET ret %d", ret);
paul718e3742002-12-13 20:15:29 +0000705
706 /* Return result. */
707 if (RESERVE1 == action)
708 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
709}
710
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100711static void
712smux_parse_get (u_char *ptr, size_t len, int exact)
paul718e3742002-12-13 20:15:29 +0000713{
714 long reqid;
715 oid oid[MAX_OID_LEN];
716 size_t oid_len;
717 u_char val_type;
718 void *val;
719 size_t val_len;
720 int ret;
721
722 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100723 zlog_debug ("SMUX GET message parse: len %zd", len);
paul718e3742002-12-13 20:15:29 +0000724
725 /* Parse GET message header. */
726 ptr = smux_parse_get_header (ptr, &len, &reqid);
727
728 /* Parse GET message object ID. We needn't the value come */
729 ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
730
731 /* Traditional getstatptr. */
732 if (exact)
733 ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
734 else
735 ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
736
737 /* Return result. */
738 if (ret == 0)
739 smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
740 else
741 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
742}
743
744/* Parse SMUX_CLOSE message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100745static void
746smux_parse_close (u_char *ptr, int len)
paul718e3742002-12-13 20:15:29 +0000747{
748 long reason = 0;
749
750 while (len--)
751 {
752 reason = (reason << 8) | (long) *ptr;
753 ptr++;
754 }
755 zlog_info ("SMUX_CLOSE with reason: %ld", reason);
756}
757
758/* SMUX_RRSP message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100759static void
760smux_parse_rrsp (u_char *ptr, size_t len)
paul718e3742002-12-13 20:15:29 +0000761{
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100762 u_char val;
paul718e3742002-12-13 20:15:29 +0000763 long errstat;
764
765 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
766
767 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000768 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
paul718e3742002-12-13 20:15:29 +0000769}
770
771/* Parse SMUX message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100772static int
773smux_parse (u_char *ptr, size_t len)
paul718e3742002-12-13 20:15:29 +0000774{
775 /* This buffer we'll use for SOUT message. We could allocate it with
776 malloc and save only static pointer/lenght, but IMHO static
777 buffer is a faster solusion. */
778 static u_char sout_save_buff[SMUXMAXPKTSIZE];
779 static int sout_save_len = 0;
780
781 int len_income = len; /* see note below: YYY */
782 u_char type;
783 u_char rollback;
784
785 rollback = ptr[2]; /* important only for SMUX_SOUT */
786
787process_rest: /* see note below: YYY */
788
789 /* Parse SMUX message type and subsequent length. */
790 ptr = asn_parse_header (ptr, &len, &type);
791
792 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100793 zlog_debug ("SMUX message received type: %d rest len: %zd", type, len);
paul718e3742002-12-13 20:15:29 +0000794
795 switch (type)
796 {
797 case SMUX_OPEN:
798 /* Open must be not send from SNMP agent. */
799 zlog_warn ("SMUX_OPEN received: resetting connection.");
800 return -1;
801 break;
802 case SMUX_RREQ:
803 /* SMUX_RREQ message is invalid for us. */
804 zlog_warn ("SMUX_RREQ received: resetting connection.");
805 return -1;
806 break;
807 case SMUX_SOUT:
808 /* SMUX_SOUT message is now valied for us. */
809 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000810 zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
paul718e3742002-12-13 20:15:29 +0000811
812 if (sout_save_len > 0)
813 {
814 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
815 sout_save_len = 0;
816 }
817 else
818 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
819
820 if (len_income > 3)
821 {
822 /* YYY: this strange code has to solve the "slow peer"
823 problem: When agent sends SMUX_SOUT message it doesn't
824 wait any responce and may send some next message to
825 subagent. Then the peer in 'smux_read()' will recieve
826 from socket the 'concatenated' buffer, contaning both
827 SMUX_SOUT message and the next one
828 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
829 the buffer is longer than 3 ( length of SMUX_SOUT ), we
830 must process the rest of it. This effect may be observed
831 if 'debug_smux' is set to '1' */
832 ptr++;
833 len = len_income - 3;
834 goto process_rest;
835 }
836 break;
837 case SMUX_GETRSP:
838 /* SMUX_GETRSP message is invalid for us. */
839 zlog_warn ("SMUX_GETRSP received: resetting connection.");
840 return -1;
841 break;
842 case SMUX_CLOSE:
843 /* Close SMUX connection. */
844 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000845 zlog_debug ("SMUX_CLOSE");
paul718e3742002-12-13 20:15:29 +0000846 smux_parse_close (ptr, len);
847 return -1;
848 break;
849 case SMUX_RRSP:
850 /* This is response for register message. */
851 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000852 zlog_debug ("SMUX_RRSP");
paul718e3742002-12-13 20:15:29 +0000853 smux_parse_rrsp (ptr, len);
854 break;
855 case SMUX_GET:
856 /* Exact request for object id. */
857 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000858 zlog_debug ("SMUX_GET");
paul718e3742002-12-13 20:15:29 +0000859 smux_parse_get (ptr, len, 1);
860 break;
861 case SMUX_GETNEXT:
862 /* Next request for object id. */
863 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000864 zlog_debug ("SMUX_GETNEXT");
paul718e3742002-12-13 20:15:29 +0000865 smux_parse_get (ptr, len, 0);
866 break;
867 case SMUX_SET:
868 /* SMUX_SET is supported with some limitations. */
869 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000870 zlog_debug ("SMUX_SET");
paul718e3742002-12-13 20:15:29 +0000871
872 /* save the data for future SMUX_SOUT */
873 memcpy (sout_save_buff, ptr, len);
874 sout_save_len = len;
875 smux_parse_set (ptr, len, RESERVE1);
876 break;
877 default:
878 zlog_info ("Unknown type: %d", type);
879 break;
880 }
881 return 0;
882}
883
884/* SMUX message read function. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100885static int
paul718e3742002-12-13 20:15:29 +0000886smux_read (struct thread *t)
887{
888 int sock;
889 int len;
890 u_char buf[SMUXMAXPKTSIZE];
891 int ret;
892
893 /* Clear thread. */
894 sock = THREAD_FD (t);
895 smux_read_thread = NULL;
896
897 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000898 zlog_debug ("SMUX read start");
paul718e3742002-12-13 20:15:29 +0000899
900 /* Read message from SMUX socket. */
901 len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
902
903 if (len < 0)
904 {
ajs6099b3b2004-11-20 02:06:59 +0000905 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000906 close (sock);
907 smux_sock = -1;
908 smux_event (SMUX_CONNECT, 0);
909 return -1;
910 }
911
912 if (len == 0)
913 {
914 zlog_warn ("SMUX connection closed: %d", sock);
915 close (sock);
916 smux_sock = -1;
917 smux_event (SMUX_CONNECT, 0);
918 return -1;
919 }
920
921 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000922 zlog_debug ("SMUX read len: %d", len);
paul718e3742002-12-13 20:15:29 +0000923
924 /* Parse the message. */
925 ret = smux_parse (buf, len);
926
927 if (ret < 0)
928 {
929 close (sock);
930 smux_sock = -1;
931 smux_event (SMUX_CONNECT, 0);
932 return -1;
933 }
934
935 /* Regiser read thread. */
936 smux_event (SMUX_READ, sock);
937
938 return 0;
939}
940
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100941static int
paul718e3742002-12-13 20:15:29 +0000942smux_open (int sock)
943{
944 u_char buf[BUFSIZ];
945 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +0000946 size_t len;
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100947 long version;
Stephen Hemminger004b1232011-12-07 00:55:15 +0400948 const char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION;
paul718e3742002-12-13 20:15:29 +0000949
950 if (debug_smux)
951 {
952 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
ajs8ddca702004-12-07 18:53:52 +0000953 zlog_debug ("SMUX open progname: %s", progname);
954 zlog_debug ("SMUX open password: %s", smux_passwd);
paul718e3742002-12-13 20:15:29 +0000955 }
956
957 ptr = buf;
958 len = BUFSIZ;
959
960 /* SMUX Header. As placeholder. */
961 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
962
963 /* SMUX Open. */
964 version = 0;
965 ptr = asn_build_int (ptr, &len,
966 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +0000967 &version, sizeof (version));
paul718e3742002-12-13 20:15:29 +0000968
969 /* SMUX connection oid. */
970 ptr = asn_build_objid (ptr, &len,
971 (u_char)
972 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
973 smux_oid, smux_oid_len);
974
975 /* SMUX connection description. */
976 ptr = asn_build_string (ptr, &len,
977 (u_char)
978 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
Stephen Hemminger004b1232011-12-07 00:55:15 +0400979 (const u_char *) progname, strlen (progname));
paul718e3742002-12-13 20:15:29 +0000980
981 /* SMUX connection password. */
982 ptr = asn_build_string (ptr, &len,
983 (u_char)
984 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100985 (u_char *)smux_passwd, strlen (smux_passwd));
paul718e3742002-12-13 20:15:29 +0000986
987 /* Fill in real SMUX header. We exclude ASN header size (2). */
988 len = BUFSIZ;
989 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
990
991 return send (sock, buf, (ptr - buf), 0);
992}
993
994int
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -0700995smux_trap (const oid *name, size_t namelen,
996 const oid *iname, size_t inamelen,
997 const struct trap_object *trapobj, size_t trapobjlen,
paul020709f2003-04-04 02:44:16 +0000998 unsigned int tick, u_char sptrap)
paul718e3742002-12-13 20:15:29 +0000999{
paul9035efa2004-10-10 11:56:56 +00001000 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001001 u_char buf[BUFSIZ];
1002 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +00001003 size_t len, length;
paul718e3742002-12-13 20:15:29 +00001004 struct in_addr addr;
1005 unsigned long val;
1006 u_char *h1, *h1e;
1007
1008 ptr = buf;
1009 len = BUFSIZ;
1010 length = len;
1011
1012 /* When SMUX connection is not established. */
1013 if (smux_sock < 0)
1014 return 0;
1015
1016 /* SMUX header. */
1017 ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
1018
1019 /* Sub agent enterprise oid. */
1020 ptr = asn_build_objid (ptr, &len,
1021 (u_char)
1022 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1023 smux_oid, smux_oid_len);
1024
1025 /* IP address. */
1026 addr.s_addr = 0;
1027 ptr = asn_build_string (ptr, &len,
1028 (u_char)
1029 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001030 (u_char *)&addr, sizeof (addr));
paul718e3742002-12-13 20:15:29 +00001031
1032 /* Generic trap integer. */
1033 val = SNMP_TRAP_ENTERPRISESPECIFIC;
1034 ptr = asn_build_int (ptr, &len,
1035 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001036 (long *)&val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001037
1038 /* Specific trap integer. */
paul020709f2003-04-04 02:44:16 +00001039 val = sptrap;
paul718e3742002-12-13 20:15:29 +00001040 ptr = asn_build_int (ptr, &len,
1041 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001042 (long *)&val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001043
1044 /* Timeticks timestamp. */
1045 val = 0;
1046 ptr = asn_build_unsigned_int (ptr, &len,
1047 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001048 &val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001049
1050 /* Variables. */
1051 h1 = ptr;
1052 ptr = asn_build_sequence (ptr, &len,
1053 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1054 0);
1055
1056
1057 /* Iteration for each objects. */
1058 h1e = ptr;
1059 for (i = 0; i < trapobjlen; i++)
1060 {
1061 int ret;
1062 oid oid[MAX_OID_LEN];
1063 size_t oid_len;
1064 void *val;
1065 size_t val_len;
1066 u_char val_type;
1067
1068 /* Make OID. */
vincent5e4914c2005-09-29 16:34:30 +00001069 if (trapobj[i].namelen > 0)
1070 {
1071 oid_copy (oid, name, namelen);
1072 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen);
1073 oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen);
1074 oid_len = namelen + trapobj[i].namelen + inamelen;
1075 }
1076 else
1077 {
1078 oid_copy (oid, name, namelen);
1079 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen * (-1));
1080 oid_len = namelen + trapobj[i].namelen * (-1) ;
1081 }
paul718e3742002-12-13 20:15:29 +00001082
vincent5e4914c2005-09-29 16:34:30 +00001083 if (debug_smux)
1084 {
1085 smux_oid_dump ("Trap", name, namelen);
1086 if (trapobj[i].namelen < 0)
1087 smux_oid_dump ("Trap",
1088 trapobj[i].name, (- 1) * (trapobj[i].namelen));
1089 else
1090 {
1091 smux_oid_dump ("Trap", trapobj[i].name, (trapobj[i].namelen));
1092 smux_oid_dump ("Trap", iname, inamelen);
1093 }
1094 smux_oid_dump ("Trap", oid, oid_len);
Andrew J. Schorreda9ba72007-04-27 18:13:15 +00001095 zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ, (u_long)oid_len);
vincent5e4914c2005-09-29 16:34:30 +00001096 }
paul718e3742002-12-13 20:15:29 +00001097
1098 ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
1099
1100 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +00001101 zlog_debug ("smux_get result %d", ret);
paul718e3742002-12-13 20:15:29 +00001102
1103 if (ret == 0)
1104 ptr = snmp_build_var_op (ptr, oid, &oid_len,
1105 val_type, val_len, val, &len);
1106 }
1107
1108 /* Now variable size is known, fill in size */
1109 asn_build_sequence(h1, &length,
1110 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1111 ptr - h1e);
1112
1113 /* Fill in size of whole sequence */
1114 len = BUFSIZ;
1115 asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
1116
1117 return send (smux_sock, buf, (ptr - buf), 0);
1118}
1119
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001120static int
paul718e3742002-12-13 20:15:29 +00001121smux_register (int sock)
1122{
1123 u_char buf[BUFSIZ];
1124 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +00001125 int ret;
1126 size_t len;
paul718e3742002-12-13 20:15:29 +00001127 long priority;
1128 long operation;
1129 struct subtree *subtree;
paul1eb8ef22005-04-07 07:30:20 +00001130 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00001131
1132 ret = 0;
1133
paul1eb8ef22005-04-07 07:30:20 +00001134 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +00001135 {
1136 ptr = buf;
1137 len = BUFSIZ;
1138
paul718e3742002-12-13 20:15:29 +00001139 /* SMUX RReq Header. */
1140 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
1141
1142 /* Register MIB tree. */
1143 ptr = asn_build_objid (ptr, &len,
1144 (u_char)
1145 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1146 subtree->name, subtree->name_len);
1147
1148 /* Priority. */
1149 priority = -1;
1150 ptr = asn_build_int (ptr, &len,
1151 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001152 &priority, sizeof (priority));
paul718e3742002-12-13 20:15:29 +00001153
1154 /* Operation. */
1155 operation = 2; /* Register R/W */
1156 ptr = asn_build_int (ptr, &len,
1157 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001158 &operation, sizeof (operation));
paul718e3742002-12-13 20:15:29 +00001159
1160 if (debug_smux)
1161 {
1162 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
ajs8ddca702004-12-07 18:53:52 +00001163 zlog_debug ("SMUX register priority: %ld", priority);
1164 zlog_debug ("SMUX register operation: %ld", operation);
paul718e3742002-12-13 20:15:29 +00001165 }
1166
1167 len = BUFSIZ;
1168 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
1169 ret = send (sock, buf, (ptr - buf), 0);
1170 if (ret < 0)
1171 return ret;
1172 }
1173 return ret;
1174}
1175
1176/* Try to connect to SNMP agent. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001177static int
paul718e3742002-12-13 20:15:29 +00001178smux_connect (struct thread *t)
1179{
1180 int ret;
1181
1182 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +00001183 zlog_debug ("SMUX connect try %d", fail + 1);
paul718e3742002-12-13 20:15:29 +00001184
1185 /* Clear thread poner of myself. */
1186 smux_connect_thread = NULL;
1187
1188 /* Make socket. Try to connect. */
1189 smux_sock = smux_socket ();
1190 if (smux_sock < 0)
1191 {
1192 if (++fail < SMUX_MAX_FAILURE)
1193 smux_event (SMUX_CONNECT, 0);
1194 return 0;
1195 }
1196
1197 /* Send OPEN PDU. */
1198 ret = smux_open (smux_sock);
1199 if (ret < 0)
1200 {
ajs6099b3b2004-11-20 02:06:59 +00001201 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001202 close (smux_sock);
1203 smux_sock = -1;
1204 if (++fail < SMUX_MAX_FAILURE)
1205 smux_event (SMUX_CONNECT, 0);
1206 return -1;
1207 }
1208
1209 /* Send any outstanding register PDUs. */
1210 ret = smux_register (smux_sock);
1211 if (ret < 0)
1212 {
ajs6099b3b2004-11-20 02:06:59 +00001213 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001214 close (smux_sock);
1215 smux_sock = -1;
1216 if (++fail < SMUX_MAX_FAILURE)
1217 smux_event (SMUX_CONNECT, 0);
1218 return -1;
1219 }
1220
1221 /* Everything goes fine. */
1222 smux_event (SMUX_READ, smux_sock);
1223
1224 return 0;
1225}
1226
1227/* Clear all SMUX related resources. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001228static void
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -07001229smux_stop (void)
paul718e3742002-12-13 20:15:29 +00001230{
1231 if (smux_read_thread)
Paul Jakmaa56ef882007-10-22 15:53:17 +00001232 {
1233 thread_cancel (smux_read_thread);
1234 smux_read_thread = NULL;
1235 }
1236
paul718e3742002-12-13 20:15:29 +00001237 if (smux_connect_thread)
Paul Jakmaa56ef882007-10-22 15:53:17 +00001238 {
1239 thread_cancel (smux_connect_thread);
1240 smux_connect_thread = NULL;
1241 }
paul718e3742002-12-13 20:15:29 +00001242
1243 if (smux_sock >= 0)
1244 {
1245 close (smux_sock);
1246 smux_sock = -1;
1247 }
1248}
1249
pauldd488a72003-06-19 01:21:07 +00001250
paul718e3742002-12-13 20:15:29 +00001251
1252void
1253smux_event (enum smux_event event, int sock)
1254{
1255 switch (event)
1256 {
1257 case SMUX_SCHEDULE:
1258 smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
1259 break;
1260 case SMUX_CONNECT:
1261 smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
1262 break;
1263 case SMUX_READ:
1264 smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
1265 break;
1266 default:
1267 break;
1268 }
1269}
1270
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001271static int
paul9035efa2004-10-10 11:56:56 +00001272smux_str2oid (const char *str, oid *oid, size_t *oid_len)
paul718e3742002-12-13 20:15:29 +00001273{
1274 int len;
1275 int val;
1276
1277 len = 0;
1278 val = 0;
1279 *oid_len = 0;
1280
1281 if (*str == '.')
1282 str++;
1283 if (*str == '\0')
1284 return 0;
1285
1286 while (1)
1287 {
1288 if (! isdigit (*str))
1289 return -1;
1290
1291 while (isdigit (*str))
1292 {
1293 val *= 10;
1294 val += (*str - '0');
1295 str++;
1296 }
1297
1298 if (*str == '\0')
1299 break;
1300 if (*str != '.')
1301 return -1;
1302
1303 oid[len++] = val;
1304 val = 0;
1305 str++;
1306 }
1307
1308 oid[len++] = val;
1309 *oid_len = len;
1310
1311 return 0;
1312}
1313
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001314static oid *
paul718e3742002-12-13 20:15:29 +00001315smux_oid_dup (oid *objid, size_t objid_len)
1316{
1317 oid *new;
1318
1319 new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
1320 oid_copy (new, objid, objid_len);
1321
1322 return new;
1323}
1324
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001325static int
paul9035efa2004-10-10 11:56:56 +00001326smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str)
paul718e3742002-12-13 20:15:29 +00001327{
1328 int ret;
1329 oid oid[MAX_OID_LEN];
1330 size_t oid_len;
1331
1332 ret = smux_str2oid (oid_str, oid, &oid_len);
1333 if (ret != 0)
1334 {
1335 vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
1336 return CMD_WARNING;
1337 }
1338
hassoc75105a2004-10-13 10:33:26 +00001339 if (smux_oid)
1340 {
1341 free (smux_oid);
1342 smux_oid = NULL;
1343 }
paul718e3742002-12-13 20:15:29 +00001344
paul9035efa2004-10-10 11:56:56 +00001345 /* careful, smux_passwd might point to string constant */
hassoc75105a2004-10-13 10:33:26 +00001346 if (smux_passwd)
paul718e3742002-12-13 20:15:29 +00001347 {
1348 free (smux_passwd);
1349 smux_passwd = NULL;
1350 }
1351
1352 smux_oid = smux_oid_dup (oid, oid_len);
1353 smux_oid_len = oid_len;
1354
1355 if (passwd_str)
1356 smux_passwd = strdup (passwd_str);
hassoc75105a2004-10-13 10:33:26 +00001357 else
1358 smux_passwd = strdup ("");
paul718e3742002-12-13 20:15:29 +00001359
hassoc75105a2004-10-13 10:33:26 +00001360 return 0;
paul718e3742002-12-13 20:15:29 +00001361}
1362
1363int
1364smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1365 size_t *var_len, WriteMethod **write_method)
1366{
1367 oid fulloid[MAX_OID_LEN];
1368 int ret;
1369
1370 oid_copy (fulloid, v->name, v->namelen);
1371 fulloid[v->namelen] = 0;
1372 /* Check against full instance. */
1373 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1374
1375 /* Check single instance. */
1376 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1377 return MATCH_FAILED;
1378
1379 /* In case of getnext, fill in full instance. */
1380 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1381 *length = v->namelen + 1;
1382
1383 *write_method = 0;
1384 *var_len = sizeof(long); /* default to 'long' results */
1385
1386 return MATCH_SUCCEEDED;
1387}
1388
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001389static int
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -07001390smux_peer_default (void)
paul718e3742002-12-13 20:15:29 +00001391{
hassoc75105a2004-10-13 10:33:26 +00001392 if (smux_oid)
paul718e3742002-12-13 20:15:29 +00001393 {
1394 free (smux_oid);
hassoc75105a2004-10-13 10:33:26 +00001395 smux_oid = NULL;
paul718e3742002-12-13 20:15:29 +00001396 }
paul9035efa2004-10-10 11:56:56 +00001397
1398 /* careful, smux_passwd might be pointing at string constant */
hassoc75105a2004-10-13 10:33:26 +00001399 if (smux_passwd)
paul718e3742002-12-13 20:15:29 +00001400 {
1401 free (smux_passwd);
hassoc75105a2004-10-13 10:33:26 +00001402 smux_passwd = NULL;
paul718e3742002-12-13 20:15:29 +00001403 }
hassoc75105a2004-10-13 10:33:26 +00001404
paul718e3742002-12-13 20:15:29 +00001405 return CMD_SUCCESS;
1406}
1407
1408DEFUN (smux_peer,
1409 smux_peer_cmd,
1410 "smux peer OID",
1411 "SNMP MUX protocol settings\n"
1412 "SNMP MUX peer settings\n"
1413 "Object ID used in SMUX peering\n")
1414{
hassoc75105a2004-10-13 10:33:26 +00001415 if (smux_peer_oid (vty, argv[0], NULL) == 0)
1416 {
1417 smux_start();
1418 return CMD_SUCCESS;
1419 }
1420 else
1421 return CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00001422}
1423
1424DEFUN (smux_peer_password,
1425 smux_peer_password_cmd,
1426 "smux peer OID PASSWORD",
1427 "SNMP MUX protocol settings\n"
1428 "SNMP MUX peer settings\n"
1429 "SMUX peering object ID\n"
1430 "SMUX peering password\n")
1431{
hassoc75105a2004-10-13 10:33:26 +00001432 if (smux_peer_oid (vty, argv[0], argv[1]) == 0)
1433 {
1434 smux_start();
1435 return CMD_SUCCESS;
1436 }
1437 else
1438 return CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00001439}
1440
1441DEFUN (no_smux_peer,
1442 no_smux_peer_cmd,
hassoc75105a2004-10-13 10:33:26 +00001443 "no smux peer",
1444 NO_STR
1445 "SNMP MUX protocol settings\n"
1446 "SNMP MUX peer settings\n")
1447{
1448 smux_stop();
1449 return smux_peer_default ();
1450}
1451
1452ALIAS (no_smux_peer,
1453 no_smux_peer_oid_cmd,
paul718e3742002-12-13 20:15:29 +00001454 "no smux peer OID",
1455 NO_STR
1456 "SNMP MUX protocol settings\n"
1457 "SNMP MUX peer settings\n"
hassoc75105a2004-10-13 10:33:26 +00001458 "SMUX peering object ID\n")
paul718e3742002-12-13 20:15:29 +00001459
hassoc75105a2004-10-13 10:33:26 +00001460ALIAS (no_smux_peer,
1461 no_smux_peer_oid_password_cmd,
paul718e3742002-12-13 20:15:29 +00001462 "no smux peer OID PASSWORD",
1463 NO_STR
1464 "SNMP MUX protocol settings\n"
1465 "SNMP MUX peer settings\n"
1466 "SMUX peering object ID\n"
1467 "SMUX peering password\n")
paul718e3742002-12-13 20:15:29 +00001468
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001469static int
paul718e3742002-12-13 20:15:29 +00001470config_write_smux (struct vty *vty)
1471{
1472 int first = 1;
paul9035efa2004-10-10 11:56:56 +00001473 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001474
hassoc75105a2004-10-13 10:33:26 +00001475 if (smux_oid)
paul718e3742002-12-13 20:15:29 +00001476 {
1477 vty_out (vty, "smux peer ");
1478 for (i = 0; i < smux_oid_len; i++)
1479 {
1480 vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
1481 first = 0;
1482 }
1483 vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
1484 }
1485 return 0;
1486}
1487
1488/* Register subtree to smux master tree. */
1489void
paulc9eca012004-10-11 11:28:44 +00001490smux_register_mib (const char *descr, struct variable *var,
1491 size_t width, int num,
paul718e3742002-12-13 20:15:29 +00001492 oid name[], size_t namelen)
1493{
1494 struct subtree *tree;
1495
1496 tree = (struct subtree *)malloc(sizeof(struct subtree));
1497 oid_copy (tree->name, name, namelen);
1498 tree->name_len = namelen;
1499 tree->variables = var;
1500 tree->variables_num = num;
1501 tree->variables_width = width;
1502 tree->registered = 0;
1503 listnode_add_sort(treelist, tree);
1504}
1505
paul718e3742002-12-13 20:15:29 +00001506/* Compare function to keep treelist sorted */
1507static int
1508smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
1509{
1510 return oid_compare(tree1->name, tree1->name_len,
1511 tree2->name, tree2->name_len);
1512}
1513
1514/* Initialize some values then schedule first SMUX connection. */
1515void
hassoc75105a2004-10-13 10:33:26 +00001516smux_init (struct thread_master *tm)
paul718e3742002-12-13 20:15:29 +00001517{
pauldd488a72003-06-19 01:21:07 +00001518 /* copy callers thread master */
1519 master = tm;
paul718e3742002-12-13 20:15:29 +00001520
1521 /* Make MIB tree. */
1522 treelist = list_new();
1523 treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
1524
1525 /* Install commands. */
1526 install_node (&smux_node, config_write_smux);
1527
1528 install_element (CONFIG_NODE, &smux_peer_cmd);
1529 install_element (CONFIG_NODE, &smux_peer_password_cmd);
1530 install_element (CONFIG_NODE, &no_smux_peer_cmd);
hassoc75105a2004-10-13 10:33:26 +00001531 install_element (CONFIG_NODE, &no_smux_peer_oid_cmd);
1532 install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd);
paul718e3742002-12-13 20:15:29 +00001533}
1534
1535void
1536smux_start(void)
1537{
Paul Jakmaa56ef882007-10-22 15:53:17 +00001538 /* Close any existing connections. */
1539 smux_stop();
1540
paul718e3742002-12-13 20:15:29 +00001541 /* Schedule first connection. */
1542 smux_event (SMUX_SCHEDULE, 0);
1543}
1544#endif /* HAVE_SNMP */