]> git.proxmox.com Git - mirror_frr.git/blame - lib/smux.c
*: nuke ^L (page feed)
[mirror_frr.git] / lib / smux.c
CommitLineData
718e3744 1/* 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
d6be5fb9 24#if defined HAVE_SNMP && defined SNMP_SMUX
07661cb5 25#include <net-snmp/net-snmp-config.h>
fb62a3ce 26#include <net-snmp/net-snmp-includes.h>
718e3744 27
718e3744 28#include "log.h"
29#include "thread.h"
30#include "linklist.h"
31#include "command.h"
5e4fa164 32#include <lib/version.h>
718e3744 33#include "memory.h"
34#include "sockunion.h"
dd488a78 35#include "smux.h"
718e3744 36
3a4c9688
VB
37#define SMUX_PORT_DEFAULT 199
38
39#define SMUXMAXPKTSIZE 1500
40#define SMUXMAXSTRLEN 256
41
42#define SMUX_OPEN (ASN_APPLICATION | ASN_CONSTRUCTOR | 0)
43#define SMUX_CLOSE (ASN_APPLICATION | ASN_PRIMITIVE | 1)
44#define SMUX_RREQ (ASN_APPLICATION | ASN_CONSTRUCTOR | 2)
45#define SMUX_RRSP (ASN_APPLICATION | ASN_PRIMITIVE | 3)
46#define SMUX_SOUT (ASN_APPLICATION | ASN_PRIMITIVE | 4)
47
48#define SMUX_GET (ASN_CONTEXT | ASN_CONSTRUCTOR | 0)
49#define SMUX_GETNEXT (ASN_CONTEXT | ASN_CONSTRUCTOR | 1)
50#define SMUX_GETRSP (ASN_CONTEXT | ASN_CONSTRUCTOR | 2)
51#define SMUX_SET (ASN_CONTEXT | ASN_CONSTRUCTOR | 3)
52#define SMUX_TRAP (ASN_CONTEXT | ASN_CONSTRUCTOR | 4)
53
54#define SMUX_MAX_FAILURE 3
55
56/* SNMP tree. */
57struct subtree
58{
59 /* Tree's oid. */
60 oid name[MAX_OID_LEN];
61 u_char name_len;
62
63 /* List of the variables. */
64 struct variable *variables;
65
66 /* Length of the variables list. */
67 int variables_num;
68
69 /* Width of the variables list. */
70 int variables_width;
71
72 /* Registered flag. */
73 int registered;
74};
75
718e3744 76#define min(A,B) ((A) < (B) ? (A) : (B))
77
78enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
79
80void smux_event (enum smux_event, int);
6b0655a2 81
718e3744 82
83/* SMUX socket. */
84int smux_sock = -1;
85
86/* SMUX subtree list. */
87struct list *treelist;
88
89/* SMUX oid. */
c75105ab 90oid *smux_oid = NULL;
718e3744 91size_t smux_oid_len;
92
718e3744 93/* SMUX password. */
c75105ab 94char *smux_passwd = NULL;
718e3744 95
96/* SMUX read threads. */
97struct thread *smux_read_thread;
98
99/* SMUX connect thrads. */
100struct thread *smux_connect_thread;
101
102/* SMUX debug flag. */
103int debug_smux = 0;
104
105/* SMUX failure count. */
106int fail = 0;
107
108/* SMUX node. */
7fc626de 109static struct cmd_node smux_node =
718e3744 110{
111 SMUX_NODE,
112 "" /* SMUX has no interface. */
113};
dd488a78 114
115/* thread master */
116static struct thread_master *master;
6b0655a2 117
0be8dfb2 118static int
718e3744 119oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
120{
121 int i;
122
123 for (i = 0; i < min (o1_len, o2_len); i++)
124 {
125 if (o1[i] < o2[i])
126 return -1;
127 else if (o1[i] > o2[i])
128 return 1;
129 }
130 if (o1_len < o2_len)
131 return -1;
132
133 return 0;
134}
6b0655a2 135
0be8dfb2 136static void
65d3fbb4 137smux_oid_dump (const char *prefix, const oid *oid, size_t oid_len)
718e3744 138{
9035efaa 139 unsigned int i;
718e3744 140 int first = 1;
141 char buf[MAX_OID_LEN * 3];
142
143 buf[0] = '\0';
144
145 for (i = 0; i < oid_len; i++)
146 {
147 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
148 first = 0;
149 }
8ddca704 150 zlog_debug ("%s: %s", prefix, buf);
718e3744 151}
152
0be8dfb2 153static int
65d3fbb4 154smux_socket (void)
718e3744 155{
156 int ret;
157#ifdef HAVE_IPV6
158 struct addrinfo hints, *res0, *res;
159 int gai;
160#else
161 struct sockaddr_in serv;
162 struct servent *sp;
163#endif
164 int sock = 0;
165
166#ifdef HAVE_IPV6
167 memset(&hints, 0, sizeof(hints));
168 hints.ai_family = PF_UNSPEC;
169 hints.ai_socktype = SOCK_STREAM;
170 gai = getaddrinfo(NULL, "smux", &hints, &res0);
171 if (gai == EAI_SERVICE)
172 {
173 char servbuf[NI_MAXSERV];
174 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
175 servbuf[sizeof (servbuf) - 1] = '\0';
176 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
177 }
178 if (gai)
179 {
180 zlog_warn("Cannot locate loopback service smux");
181 return -1;
182 }
183 for(res=res0; res; res=res->ai_next)
184 {
185 if (res->ai_family != AF_INET
186#ifdef HAVE_IPV6
187 && res->ai_family != AF_INET6
188#endif /* HAVE_IPV6 */
189 )
190 continue;
191
192 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
193 if (sock < 0)
194 continue;
195 sockopt_reuseaddr (sock);
196 sockopt_reuseport (sock);
197 ret = connect (sock, res->ai_addr, res->ai_addrlen);
198 if (ret < 0)
199 {
200 close(sock);
201 sock = -1;
202 continue;
203 }
204 break;
205 }
206 freeaddrinfo(res0);
207 if (sock < 0)
208 zlog_warn ("Can't connect to SNMP agent with SMUX");
209#else
210 sock = socket (AF_INET, SOCK_STREAM, 0);
211 if (sock < 0)
212 {
213 zlog_warn ("Can't make socket for SNMP");
214 return -1;
215 }
216
217 memset (&serv, 0, sizeof (struct sockaddr_in));
218 serv.sin_family = AF_INET;
6f0e3f6e 219#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
718e3744 220 serv.sin_len = sizeof (struct sockaddr_in);
6f0e3f6e 221#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
718e3744 222
223 sp = getservbyname ("smux", "tcp");
224 if (sp != NULL)
225 serv.sin_port = sp->s_port;
226 else
227 serv.sin_port = htons (SMUX_PORT_DEFAULT);
228
229 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
230
231 sockopt_reuseaddr (sock);
232 sockopt_reuseport (sock);
233
234 ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
235 if (ret < 0)
236 {
237 close (sock);
238 smux_sock = -1;
239 zlog_warn ("Can't connect to SNMP agent with SMUX");
240 return -1;
241 }
242#endif
243 return sock;
244}
245
0be8dfb2 246static void
718e3744 247smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
248 long errindex, u_char val_type, void *arg, size_t arg_len)
249{
718e3744 250 u_char buf[BUFSIZ];
251 u_char *ptr, *h1, *h1e, *h2, *h2e;
70e149e0 252 size_t len, length;
718e3744 253
254 ptr = buf;
255 len = BUFSIZ;
256 length = len;
257
258 if (debug_smux)
259 {
8ddca704 260 zlog_debug ("SMUX GETRSP send");
261 zlog_debug ("SMUX GETRSP reqid: %ld", reqid);
718e3744 262 }
263
264 h1 = ptr;
265 /* Place holder h1 for complete sequence */
266 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
267 h1e = ptr;
268
269 ptr = asn_build_int (ptr, &len,
270 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
271 &reqid, sizeof (reqid));
272
273 if (debug_smux)
8ddca704 274 zlog_debug ("SMUX GETRSP errstat: %ld", errstat);
718e3744 275
276 ptr = asn_build_int (ptr, &len,
277 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
278 &errstat, sizeof (errstat));
279 if (debug_smux)
8ddca704 280 zlog_debug ("SMUX GETRSP errindex: %ld", errindex);
718e3744 281
282 ptr = asn_build_int (ptr, &len,
283 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
284 &errindex, sizeof (errindex));
285
286 h2 = ptr;
287 /* Place holder h2 for one variable */
288 ptr = asn_build_sequence (ptr, &len,
289 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
290 0);
291 h2e = ptr;
292
293 ptr = snmp_build_var_op (ptr, objid, &objid_len,
294 val_type, arg_len, arg, &len);
295
296 /* Now variable size is known, fill in size */
297 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
298
299 /* Fill in size of whole sequence */
300 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
301
302 if (debug_smux)
0be8dfb2 303 zlog_debug ("SMUX getresp send: %td", (ptr - buf));
718e3744 304
004b1238 305 send (smux_sock, buf, (ptr - buf), 0);
718e3744 306}
307
0be8dfb2
CC
308static u_char *
309smux_var (u_char *ptr, size_t len, oid objid[], size_t *objid_len,
718e3744 310 size_t *var_val_len,
311 u_char *var_val_type,
312 void **var_value)
313{
314 u_char type;
315 u_char val_type;
316 size_t val_len;
317 u_char *val;
318
319 if (debug_smux)
0be8dfb2 320 zlog_debug ("SMUX var parse: len %zd", len);
718e3744 321
322 /* Parse header. */
323 ptr = asn_parse_header (ptr, &len, &type);
324
325 if (debug_smux)
326 {
0be8dfb2 327 zlog_debug ("SMUX var parse: type %d len %zd", type, len);
8ddca704 328 zlog_debug ("SMUX var parse: type must be %d",
718e3744 329 (ASN_SEQUENCE | ASN_CONSTRUCTOR));
330 }
331
332 /* Parse var option. */
333 *objid_len = MAX_OID_LEN;
334 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
335 &val_len, &val, &len);
336
337 if (var_val_len)
338 *var_val_len = val_len;
339
340 if (var_value)
341 *var_value = (void*) val;
342
343 if (var_val_type)
344 *var_val_type = val_type;
345
346 /* Requested object id length is objid_len. */
347 if (debug_smux)
348 smux_oid_dump ("Request OID", objid, *objid_len);
349
350 if (debug_smux)
8ddca704 351 zlog_debug ("SMUX val_type: %d", val_type);
718e3744 352
353 /* Check request value type. */
354 if (debug_smux)
355 switch (val_type)
356 {
357 case ASN_NULL:
358 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
359 ASN_NULL. */
8ddca704 360 zlog_debug ("ASN_NULL");
718e3744 361 break;
362
363 case ASN_INTEGER:
8ddca704 364 zlog_debug ("ASN_INTEGER");
718e3744 365 break;
366 case ASN_COUNTER:
367 case ASN_GAUGE:
368 case ASN_TIMETICKS:
369 case ASN_UINTEGER:
8ddca704 370 zlog_debug ("ASN_COUNTER");
718e3744 371 break;
372 case ASN_COUNTER64:
8ddca704 373 zlog_debug ("ASN_COUNTER64");
718e3744 374 break;
375 case ASN_IPADDRESS:
8ddca704 376 zlog_debug ("ASN_IPADDRESS");
718e3744 377 break;
378 case ASN_OCTET_STR:
8ddca704 379 zlog_debug ("ASN_OCTET_STR");
718e3744 380 break;
381 case ASN_OPAQUE:
382 case ASN_NSAP:
383 case ASN_OBJECT_ID:
8ddca704 384 zlog_debug ("ASN_OPAQUE");
718e3744 385 break;
386 case SNMP_NOSUCHOBJECT:
8ddca704 387 zlog_debug ("SNMP_NOSUCHOBJECT");
718e3744 388 break;
389 case SNMP_NOSUCHINSTANCE:
8ddca704 390 zlog_debug ("SNMP_NOSUCHINSTANCE");
718e3744 391 break;
392 case SNMP_ENDOFMIBVIEW:
8ddca704 393 zlog_debug ("SNMP_ENDOFMIBVIEW");
718e3744 394 break;
395 case ASN_BIT_STR:
8ddca704 396 zlog_debug ("ASN_BIT_STR");
718e3744 397 break;
398 default:
8ddca704 399 zlog_debug ("Unknown type");
718e3744 400 break;
401 }
402 return ptr;
403}
404
405/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
406 ucd-snmp smux and as such suppose, that the peer receives in the message
407 only one variable. Fortunately, IBM seems to do the same in AIX. */
408
0be8dfb2 409static int
718e3744 410smux_set (oid *reqid, size_t *reqid_len,
411 u_char val_type, void *val, size_t val_len, int action)
412{
413 int j;
414 struct subtree *subtree;
415 struct variable *v;
416 int subresult;
417 oid *suffix;
70e149e0 418 size_t suffix_len;
718e3744 419 int result;
420 u_char *statP = NULL;
421 WriteMethod *write_method = NULL;
1eb8ef25 422 struct listnode *node, *nnode;
718e3744 423
424 /* Check */
1eb8ef25 425 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
718e3744 426 {
718e3744 427 subresult = oid_compare_part (reqid, *reqid_len,
428 subtree->name, subtree->name_len);
429
430 /* Subtree matched. */
431 if (subresult == 0)
432 {
433 /* Prepare suffix. */
434 suffix = reqid + subtree->name_len;
435 suffix_len = *reqid_len - subtree->name_len;
436 result = subresult;
437
438 /* Check variables. */
439 for (j = 0; j < subtree->variables_num; j++)
440 {
441 v = &subtree->variables[j];
442
443 /* Always check suffix */
444 result = oid_compare_part (suffix, suffix_len,
445 v->name, v->namelen);
446
447 /* This is exact match so result must be zero. */
448 if (result == 0)
449 {
450 if (debug_smux)
8ddca704 451 zlog_debug ("SMUX function call index is %d", v->magic);
718e3744 452
453 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
454 &val_len, &write_method);
455
456 if (write_method)
457 {
458 return (*write_method)(action, val, val_type, val_len,
3a4c9688 459 statP, suffix, suffix_len);
718e3744 460 }
461 else
462 {
463 return SNMP_ERR_READONLY;
464 }
465 }
466
467 /* If above execution is failed or oid is small (so
468 there is no further match). */
469 if (result < 0)
470 return SNMP_ERR_NOSUCHNAME;
471 }
472 }
473 }
474 return SNMP_ERR_NOSUCHNAME;
475}
476
0be8dfb2 477static int
718e3744 478smux_get (oid *reqid, size_t *reqid_len, int exact,
479 u_char *val_type,void **val, size_t *val_len)
480{
481 int j;
482 struct subtree *subtree;
483 struct variable *v;
484 int subresult;
485 oid *suffix;
70e149e0 486 size_t suffix_len;
718e3744 487 int result;
488 WriteMethod *write_method=NULL;
1eb8ef25 489 struct listnode *node, *nnode;
718e3744 490
491 /* Check */
1eb8ef25 492 for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree))
718e3744 493 {
718e3744 494 subresult = oid_compare_part (reqid, *reqid_len,
495 subtree->name, subtree->name_len);
496
497 /* Subtree matched. */
498 if (subresult == 0)
499 {
500 /* Prepare suffix. */
501 suffix = reqid + subtree->name_len;
502 suffix_len = *reqid_len - subtree->name_len;
503 result = subresult;
504
505 /* Check variables. */
506 for (j = 0; j < subtree->variables_num; j++)
507 {
508 v = &subtree->variables[j];
509
510 /* Always check suffix */
511 result = oid_compare_part (suffix, suffix_len,
512 v->name, v->namelen);
513
514 /* This is exact match so result must be zero. */
515 if (result == 0)
516 {
517 if (debug_smux)
8ddca704 518 zlog_debug ("SMUX function call index is %d", v->magic);
718e3744 519
520 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
521 val_len, &write_method);
522
523 /* There is no instance. */
524 if (*val == NULL)
525 return SNMP_NOSUCHINSTANCE;
526
527 /* Call is suceed. */
528 *val_type = v->type;
529
530 return 0;
531 }
532
533 /* If above execution is failed or oid is small (so
534 there is no further match). */
535 if (result < 0)
536 return SNMP_ERR_NOSUCHNAME;
537 }
538 }
539 }
540 return SNMP_ERR_NOSUCHNAME;
541}
542
0be8dfb2 543static int
718e3744 544smux_getnext (oid *reqid, size_t *reqid_len, int exact,
545 u_char *val_type,void **val, size_t *val_len)
546{
547 int j;
548 oid save[MAX_OID_LEN];
549 int savelen = 0;
550 struct subtree *subtree;
551 struct variable *v;
552 int subresult;
553 oid *suffix;
70e149e0 554 size_t suffix_len;
718e3744 555 int result;
556 WriteMethod *write_method=NULL;
1eb8ef25 557 struct listnode *node, *nnode;
718e3744 558
559
560 /* Save incoming request. */
561 oid_copy (save, reqid, *reqid_len);
562 savelen = *reqid_len;
563
564 /* Check */
1eb8ef25 565 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
718e3744 566 {
718e3744 567 subresult = oid_compare_part (reqid, *reqid_len,
568 subtree->name, subtree->name_len);
569
570 /* If request is in the tree. The agent has to make sure we
571 only receive requests we have registered for. */
572 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
573 behave as if it manages the whole SNMP MIB tree itself. It's the
574 duty of the master agent to collect the best answer and return it
575 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
576 :-). ucd-snmp really behaves bad here as it actually might ask
577 multiple times for the same GETNEXT request as it throws away the
578 answer when it expects it in a different subtree and might come
579 back later with the very same request. --jochen */
580
581 if (subresult <= 0)
582 {
583 /* Prepare suffix. */
584 suffix = reqid + subtree->name_len;
585 suffix_len = *reqid_len - subtree->name_len;
586 if (subresult < 0)
587 {
588 oid_copy(reqid, subtree->name, subtree->name_len);
589 *reqid_len = subtree->name_len;
590 }
591 for (j = 0; j < subtree->variables_num; j++)
592 {
593 result = subresult;
594 v = &subtree->variables[j];
595
596 /* Next then check result >= 0. */
597 if (result == 0)
598 result = oid_compare_part (suffix, suffix_len,
599 v->name, v->namelen);
600
601 if (result <= 0)
602 {
603 if (debug_smux)
8ddca704 604 zlog_debug ("SMUX function call index is %d", v->magic);
718e3744 605 if(result<0)
606 {
607 oid_copy(suffix, v->name, v->namelen);
608 suffix_len = v->namelen;
609 }
610 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
611 val_len, &write_method);
612 *reqid_len = suffix_len + subtree->name_len;
613 if (*val)
614 {
615 *val_type = v->type;
616 return 0;
617 }
618 }
619 }
620 }
621 }
622 memcpy (reqid, save, savelen * sizeof(oid));
623 *reqid_len = savelen;
624
625 return SNMP_ERR_NOSUCHNAME;
626}
627
628/* GET message header. */
0be8dfb2
CC
629static u_char *
630smux_parse_get_header (u_char *ptr, size_t *len, long *reqid)
718e3744 631{
632 u_char type;
633 long errstat;
634 long errindex;
635
636 /* Request ID. */
637 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
638
639 if (debug_smux)
8ddca704 640 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
718e3744 641
642 /* Error status. */
643 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
644
645 if (debug_smux)
0be8dfb2 646 zlog_debug ("SMUX GET errstat %ld len: %zd", errstat, *len);
718e3744 647
648 /* Error index. */
649 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
650
651 if (debug_smux)
0be8dfb2 652 zlog_debug ("SMUX GET errindex %ld len: %zd", errindex, *len);
718e3744 653
654 return ptr;
655}
656
0be8dfb2
CC
657static void
658smux_parse_set (u_char *ptr, size_t len, int action)
718e3744 659{
660 long reqid;
661 oid oid[MAX_OID_LEN];
662 size_t oid_len;
663 u_char val_type;
664 void *val;
665 size_t val_len;
666 int ret;
667
668 if (debug_smux)
0be8dfb2 669 zlog_debug ("SMUX SET(%s) message parse: len %zd",
718e3744 670 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
671 len);
672
673 /* Parse SET message header. */
674 ptr = smux_parse_get_header (ptr, &len, &reqid);
675
676 /* Parse SET message object ID. */
677 ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
678
679 ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
680 if (debug_smux)
8ddca704 681 zlog_debug ("SMUX SET ret %d", ret);
718e3744 682
683 /* Return result. */
684 if (RESERVE1 == action)
685 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
686}
687
0be8dfb2
CC
688static void
689smux_parse_get (u_char *ptr, size_t len, int exact)
718e3744 690{
691 long reqid;
692 oid oid[MAX_OID_LEN];
693 size_t oid_len;
694 u_char val_type;
695 void *val;
696 size_t val_len;
697 int ret;
698
699 if (debug_smux)
0be8dfb2 700 zlog_debug ("SMUX GET message parse: len %zd", len);
718e3744 701
702 /* Parse GET message header. */
703 ptr = smux_parse_get_header (ptr, &len, &reqid);
704
705 /* Parse GET message object ID. We needn't the value come */
706 ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
707
708 /* Traditional getstatptr. */
709 if (exact)
710 ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
711 else
712 ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
713
714 /* Return result. */
715 if (ret == 0)
716 smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
717 else
718 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
719}
720
721/* Parse SMUX_CLOSE message. */
0be8dfb2
CC
722static void
723smux_parse_close (u_char *ptr, int len)
718e3744 724{
725 long reason = 0;
726
727 while (len--)
728 {
729 reason = (reason << 8) | (long) *ptr;
730 ptr++;
731 }
732 zlog_info ("SMUX_CLOSE with reason: %ld", reason);
733}
734
735/* SMUX_RRSP message. */
0be8dfb2
CC
736static void
737smux_parse_rrsp (u_char *ptr, size_t len)
718e3744 738{
0be8dfb2 739 u_char val;
718e3744 740 long errstat;
741
742 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
743
744 if (debug_smux)
8ddca704 745 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
718e3744 746}
747
748/* Parse SMUX message. */
0be8dfb2
CC
749static int
750smux_parse (u_char *ptr, size_t len)
718e3744 751{
752 /* This buffer we'll use for SOUT message. We could allocate it with
753 malloc and save only static pointer/lenght, but IMHO static
754 buffer is a faster solusion. */
755 static u_char sout_save_buff[SMUXMAXPKTSIZE];
756 static int sout_save_len = 0;
757
758 int len_income = len; /* see note below: YYY */
759 u_char type;
760 u_char rollback;
761
762 rollback = ptr[2]; /* important only for SMUX_SOUT */
763
764process_rest: /* see note below: YYY */
765
766 /* Parse SMUX message type and subsequent length. */
767 ptr = asn_parse_header (ptr, &len, &type);
768
769 if (debug_smux)
0be8dfb2 770 zlog_debug ("SMUX message received type: %d rest len: %zd", type, len);
718e3744 771
772 switch (type)
773 {
774 case SMUX_OPEN:
775 /* Open must be not send from SNMP agent. */
776 zlog_warn ("SMUX_OPEN received: resetting connection.");
777 return -1;
778 break;
779 case SMUX_RREQ:
780 /* SMUX_RREQ message is invalid for us. */
781 zlog_warn ("SMUX_RREQ received: resetting connection.");
782 return -1;
783 break;
784 case SMUX_SOUT:
785 /* SMUX_SOUT message is now valied for us. */
786 if (debug_smux)
8ddca704 787 zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
718e3744 788
789 if (sout_save_len > 0)
790 {
791 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
792 sout_save_len = 0;
793 }
794 else
795 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
796
797 if (len_income > 3)
798 {
799 /* YYY: this strange code has to solve the "slow peer"
800 problem: When agent sends SMUX_SOUT message it doesn't
801 wait any responce and may send some next message to
802 subagent. Then the peer in 'smux_read()' will recieve
803 from socket the 'concatenated' buffer, contaning both
804 SMUX_SOUT message and the next one
805 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
806 the buffer is longer than 3 ( length of SMUX_SOUT ), we
807 must process the rest of it. This effect may be observed
808 if 'debug_smux' is set to '1' */
809 ptr++;
810 len = len_income - 3;
811 goto process_rest;
812 }
813 break;
814 case SMUX_GETRSP:
815 /* SMUX_GETRSP message is invalid for us. */
816 zlog_warn ("SMUX_GETRSP received: resetting connection.");
817 return -1;
818 break;
819 case SMUX_CLOSE:
820 /* Close SMUX connection. */
821 if (debug_smux)
8ddca704 822 zlog_debug ("SMUX_CLOSE");
718e3744 823 smux_parse_close (ptr, len);
824 return -1;
825 break;
826 case SMUX_RRSP:
827 /* This is response for register message. */
828 if (debug_smux)
8ddca704 829 zlog_debug ("SMUX_RRSP");
718e3744 830 smux_parse_rrsp (ptr, len);
831 break;
832 case SMUX_GET:
833 /* Exact request for object id. */
834 if (debug_smux)
8ddca704 835 zlog_debug ("SMUX_GET");
718e3744 836 smux_parse_get (ptr, len, 1);
837 break;
838 case SMUX_GETNEXT:
839 /* Next request for object id. */
840 if (debug_smux)
8ddca704 841 zlog_debug ("SMUX_GETNEXT");
718e3744 842 smux_parse_get (ptr, len, 0);
843 break;
844 case SMUX_SET:
845 /* SMUX_SET is supported with some limitations. */
846 if (debug_smux)
8ddca704 847 zlog_debug ("SMUX_SET");
718e3744 848
849 /* save the data for future SMUX_SOUT */
850 memcpy (sout_save_buff, ptr, len);
851 sout_save_len = len;
852 smux_parse_set (ptr, len, RESERVE1);
853 break;
854 default:
855 zlog_info ("Unknown type: %d", type);
856 break;
857 }
858 return 0;
859}
860
861/* SMUX message read function. */
0be8dfb2 862static int
718e3744 863smux_read (struct thread *t)
864{
865 int sock;
866 int len;
867 u_char buf[SMUXMAXPKTSIZE];
868 int ret;
869
870 /* Clear thread. */
871 sock = THREAD_FD (t);
872 smux_read_thread = NULL;
873
874 if (debug_smux)
8ddca704 875 zlog_debug ("SMUX read start");
718e3744 876
877 /* Read message from SMUX socket. */
878 len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
879
880 if (len < 0)
881 {
6099b3b5 882 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno));
718e3744 883 close (sock);
884 smux_sock = -1;
885 smux_event (SMUX_CONNECT, 0);
886 return -1;
887 }
888
889 if (len == 0)
890 {
891 zlog_warn ("SMUX connection closed: %d", sock);
892 close (sock);
893 smux_sock = -1;
894 smux_event (SMUX_CONNECT, 0);
895 return -1;
896 }
897
898 if (debug_smux)
8ddca704 899 zlog_debug ("SMUX read len: %d", len);
718e3744 900
901 /* Parse the message. */
902 ret = smux_parse (buf, len);
903
904 if (ret < 0)
905 {
906 close (sock);
907 smux_sock = -1;
908 smux_event (SMUX_CONNECT, 0);
909 return -1;
910 }
911
912 /* Regiser read thread. */
913 smux_event (SMUX_READ, sock);
914
915 return 0;
916}
917
0be8dfb2 918static int
718e3744 919smux_open (int sock)
920{
921 u_char buf[BUFSIZ];
922 u_char *ptr;
70e149e0 923 size_t len;
0be8dfb2 924 long version;
004b1238 925 const char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION;
718e3744 926
927 if (debug_smux)
928 {
929 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
8ddca704 930 zlog_debug ("SMUX open progname: %s", progname);
931 zlog_debug ("SMUX open password: %s", smux_passwd);
718e3744 932 }
933
934 ptr = buf;
935 len = BUFSIZ;
936
937 /* SMUX Header. As placeholder. */
938 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
939
940 /* SMUX Open. */
941 version = 0;
942 ptr = asn_build_int (ptr, &len,
943 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
965b83f9 944 &version, sizeof (version));
718e3744 945
946 /* SMUX connection oid. */
947 ptr = asn_build_objid (ptr, &len,
948 (u_char)
949 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
950 smux_oid, smux_oid_len);
951
952 /* SMUX connection description. */
953 ptr = asn_build_string (ptr, &len,
954 (u_char)
955 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
004b1238 956 (const u_char *) progname, strlen (progname));
718e3744 957
958 /* SMUX connection password. */
959 ptr = asn_build_string (ptr, &len,
960 (u_char)
961 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
0be8dfb2 962 (u_char *)smux_passwd, strlen (smux_passwd));
718e3744 963
964 /* Fill in real SMUX header. We exclude ASN header size (2). */
965 len = BUFSIZ;
966 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
967
968 return send (sock, buf, (ptr - buf), 0);
969}
970
b7c0d065
VB
971/* `ename` is ignored. Instead of using the provided enterprise OID,
972 the SMUX peer is used. This keep compatibility with the previous
973 versions of Quagga.
974
975 All other fields are used as they are intended. */
718e3744 976int
b7c0d065
VB
977smux_trap (struct variable *vp, size_t vp_len,
978 const oid *ename, size_t enamelen,
979 const oid *name, size_t namelen,
65d3fbb4
SH
980 const oid *iname, size_t inamelen,
981 const struct trap_object *trapobj, size_t trapobjlen,
4b89e45d 982 u_char sptrap)
718e3744 983{
9035efaa 984 unsigned int i;
718e3744 985 u_char buf[BUFSIZ];
986 u_char *ptr;
70e149e0 987 size_t len, length;
718e3744 988 struct in_addr addr;
989 unsigned long val;
990 u_char *h1, *h1e;
991
992 ptr = buf;
993 len = BUFSIZ;
994 length = len;
995
996 /* When SMUX connection is not established. */
997 if (smux_sock < 0)
998 return 0;
999
1000 /* SMUX header. */
1001 ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
1002
1003 /* Sub agent enterprise oid. */
1004 ptr = asn_build_objid (ptr, &len,
1005 (u_char)
1006 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1007 smux_oid, smux_oid_len);
1008
1009 /* IP address. */
1010 addr.s_addr = 0;
1011 ptr = asn_build_string (ptr, &len,
1012 (u_char)
1013 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
965b83f9 1014 (u_char *)&addr, sizeof (addr));
718e3744 1015
1016 /* Generic trap integer. */
1017 val = SNMP_TRAP_ENTERPRISESPECIFIC;
1018 ptr = asn_build_int (ptr, &len,
1019 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
0be8dfb2 1020 (long *)&val, sizeof (val));
718e3744 1021
1022 /* Specific trap integer. */
020709f9 1023 val = sptrap;
718e3744 1024 ptr = asn_build_int (ptr, &len,
1025 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
0be8dfb2 1026 (long *)&val, sizeof (val));
718e3744 1027
1028 /* Timeticks timestamp. */
1029 val = 0;
1030 ptr = asn_build_unsigned_int (ptr, &len,
1031 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS),
965b83f9 1032 &val, sizeof (val));
718e3744 1033
1034 /* Variables. */
1035 h1 = ptr;
1036 ptr = asn_build_sequence (ptr, &len,
1037 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1038 0);
1039
1040
1041 /* Iteration for each objects. */
1042 h1e = ptr;
1043 for (i = 0; i < trapobjlen; i++)
1044 {
1045 int ret;
1046 oid oid[MAX_OID_LEN];
1047 size_t oid_len;
1048 void *val;
1049 size_t val_len;
1050 u_char val_type;
1051
1052 /* Make OID. */
5e4914c3 1053 if (trapobj[i].namelen > 0)
1054 {
1055 oid_copy (oid, name, namelen);
1056 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen);
1057 oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen);
1058 oid_len = namelen + trapobj[i].namelen + inamelen;
1059 }
1060 else
1061 {
1062 oid_copy (oid, name, namelen);
1063 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen * (-1));
1064 oid_len = namelen + trapobj[i].namelen * (-1) ;
1065 }
718e3744 1066
5e4914c3 1067 if (debug_smux)
1068 {
1069 smux_oid_dump ("Trap", name, namelen);
1070 if (trapobj[i].namelen < 0)
1071 smux_oid_dump ("Trap",
1072 trapobj[i].name, (- 1) * (trapobj[i].namelen));
1073 else
1074 {
1075 smux_oid_dump ("Trap", trapobj[i].name, (trapobj[i].namelen));
1076 smux_oid_dump ("Trap", iname, inamelen);
1077 }
1078 smux_oid_dump ("Trap", oid, oid_len);
eda9ba74 1079 zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ, (u_long)oid_len);
5e4914c3 1080 }
718e3744 1081
1082 ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
1083
1084 if (debug_smux)
8ddca704 1085 zlog_debug ("smux_get result %d", ret);
718e3744 1086
1087 if (ret == 0)
1088 ptr = snmp_build_var_op (ptr, oid, &oid_len,
1089 val_type, val_len, val, &len);
1090 }
1091
1092 /* Now variable size is known, fill in size */
1093 asn_build_sequence(h1, &length,
1094 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1095 ptr - h1e);
1096
1097 /* Fill in size of whole sequence */
1098 len = BUFSIZ;
1099 asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
1100
1101 return send (smux_sock, buf, (ptr - buf), 0);
1102}
1103
0be8dfb2 1104static int
718e3744 1105smux_register (int sock)
1106{
1107 u_char buf[BUFSIZ];
1108 u_char *ptr;
70e149e0 1109 int ret;
1110 size_t len;
718e3744 1111 long priority;
1112 long operation;
1113 struct subtree *subtree;
1eb8ef25 1114 struct listnode *node, *nnode;
718e3744 1115
1116 ret = 0;
1117
1eb8ef25 1118 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
718e3744 1119 {
1120 ptr = buf;
1121 len = BUFSIZ;
1122
718e3744 1123 /* SMUX RReq Header. */
1124 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
1125
1126 /* Register MIB tree. */
1127 ptr = asn_build_objid (ptr, &len,
1128 (u_char)
1129 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1130 subtree->name, subtree->name_len);
1131
1132 /* Priority. */
1133 priority = -1;
1134 ptr = asn_build_int (ptr, &len,
1135 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
965b83f9 1136 &priority, sizeof (priority));
718e3744 1137
1138 /* Operation. */
1139 operation = 2; /* Register R/W */
1140 ptr = asn_build_int (ptr, &len,
1141 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
965b83f9 1142 &operation, sizeof (operation));
718e3744 1143
1144 if (debug_smux)
1145 {
1146 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
8ddca704 1147 zlog_debug ("SMUX register priority: %ld", priority);
1148 zlog_debug ("SMUX register operation: %ld", operation);
718e3744 1149 }
1150
1151 len = BUFSIZ;
1152 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
1153 ret = send (sock, buf, (ptr - buf), 0);
1154 if (ret < 0)
1155 return ret;
1156 }
1157 return ret;
1158}
1159
1160/* Try to connect to SNMP agent. */
0be8dfb2 1161static int
718e3744 1162smux_connect (struct thread *t)
1163{
1164 int ret;
1165
1166 if (debug_smux)
8ddca704 1167 zlog_debug ("SMUX connect try %d", fail + 1);
718e3744 1168
1169 /* Clear thread poner of myself. */
1170 smux_connect_thread = NULL;
1171
1172 /* Make socket. Try to connect. */
1173 smux_sock = smux_socket ();
1174 if (smux_sock < 0)
1175 {
1176 if (++fail < SMUX_MAX_FAILURE)
1177 smux_event (SMUX_CONNECT, 0);
1178 return 0;
1179 }
1180
1181 /* Send OPEN PDU. */
1182 ret = smux_open (smux_sock);
1183 if (ret < 0)
1184 {
6099b3b5 1185 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno));
718e3744 1186 close (smux_sock);
1187 smux_sock = -1;
1188 if (++fail < SMUX_MAX_FAILURE)
1189 smux_event (SMUX_CONNECT, 0);
1190 return -1;
1191 }
1192
1193 /* Send any outstanding register PDUs. */
1194 ret = smux_register (smux_sock);
1195 if (ret < 0)
1196 {
6099b3b5 1197 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno));
718e3744 1198 close (smux_sock);
1199 smux_sock = -1;
1200 if (++fail < SMUX_MAX_FAILURE)
1201 smux_event (SMUX_CONNECT, 0);
1202 return -1;
1203 }
1204
1205 /* Everything goes fine. */
1206 smux_event (SMUX_READ, smux_sock);
1207
1208 return 0;
1209}
1210
1211/* Clear all SMUX related resources. */
0be8dfb2 1212static void
65d3fbb4 1213smux_stop (void)
718e3744 1214{
1215 if (smux_read_thread)
a56ef883
PJ
1216 {
1217 thread_cancel (smux_read_thread);
1218 smux_read_thread = NULL;
1219 }
1220
718e3744 1221 if (smux_connect_thread)
a56ef883
PJ
1222 {
1223 thread_cancel (smux_connect_thread);
1224 smux_connect_thread = NULL;
1225 }
718e3744 1226
1227 if (smux_sock >= 0)
1228 {
1229 close (smux_sock);
1230 smux_sock = -1;
1231 }
1232}
6b0655a2 1233
dd488a78 1234
718e3744 1235
1236void
1237smux_event (enum smux_event event, int sock)
1238{
1239 switch (event)
1240 {
1241 case SMUX_SCHEDULE:
1242 smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
1243 break;
1244 case SMUX_CONNECT:
1245 smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
1246 break;
1247 case SMUX_READ:
1248 smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
1249 break;
1250 default:
1251 break;
1252 }
1253}
6b0655a2 1254
0be8dfb2 1255static int
9035efaa 1256smux_str2oid (const char *str, oid *oid, size_t *oid_len)
718e3744 1257{
1258 int len;
1259 int val;
1260
1261 len = 0;
1262 val = 0;
1263 *oid_len = 0;
1264
1265 if (*str == '.')
1266 str++;
1267 if (*str == '\0')
1268 return 0;
1269
1270 while (1)
1271 {
1272 if (! isdigit (*str))
1273 return -1;
1274
1275 while (isdigit (*str))
1276 {
1277 val *= 10;
1278 val += (*str - '0');
1279 str++;
1280 }
1281
1282 if (*str == '\0')
1283 break;
1284 if (*str != '.')
1285 return -1;
1286
1287 oid[len++] = val;
1288 val = 0;
1289 str++;
1290 }
1291
1292 oid[len++] = val;
1293 *oid_len = len;
1294
1295 return 0;
1296}
1297
0be8dfb2 1298static oid *
718e3744 1299smux_oid_dup (oid *objid, size_t objid_len)
1300{
1301 oid *new;
1302
1303 new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
1304 oid_copy (new, objid, objid_len);
1305
1306 return new;
1307}
1308
0be8dfb2 1309static int
9035efaa 1310smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str)
718e3744 1311{
1312 int ret;
1313 oid oid[MAX_OID_LEN];
1314 size_t oid_len;
1315
1316 ret = smux_str2oid (oid_str, oid, &oid_len);
1317 if (ret != 0)
1318 {
1319 vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
1320 return CMD_WARNING;
1321 }
1322
c75105ab 1323 if (smux_oid)
1324 {
1325 free (smux_oid);
1326 smux_oid = NULL;
1327 }
718e3744 1328
9035efaa 1329 /* careful, smux_passwd might point to string constant */
c75105ab 1330 if (smux_passwd)
718e3744 1331 {
1332 free (smux_passwd);
1333 smux_passwd = NULL;
1334 }
1335
1336 smux_oid = smux_oid_dup (oid, oid_len);
1337 smux_oid_len = oid_len;
1338
1339 if (passwd_str)
1340 smux_passwd = strdup (passwd_str);
c75105ab 1341 else
1342 smux_passwd = strdup ("");
718e3744 1343
c75105ab 1344 return 0;
718e3744 1345}
1346
0be8dfb2 1347static int
65d3fbb4 1348smux_peer_default (void)
718e3744 1349{
c75105ab 1350 if (smux_oid)
718e3744 1351 {
1352 free (smux_oid);
c75105ab 1353 smux_oid = NULL;
718e3744 1354 }
9035efaa 1355
1356 /* careful, smux_passwd might be pointing at string constant */
c75105ab 1357 if (smux_passwd)
718e3744 1358 {
1359 free (smux_passwd);
c75105ab 1360 smux_passwd = NULL;
718e3744 1361 }
c75105ab 1362
718e3744 1363 return CMD_SUCCESS;
1364}
1365
1366DEFUN (smux_peer,
1367 smux_peer_cmd,
1368 "smux peer OID",
1369 "SNMP MUX protocol settings\n"
1370 "SNMP MUX peer settings\n"
1371 "Object ID used in SMUX peering\n")
1372{
c75105ab 1373 if (smux_peer_oid (vty, argv[0], NULL) == 0)
1374 {
1375 smux_start();
1376 return CMD_SUCCESS;
1377 }
1378 else
1379 return CMD_WARNING;
718e3744 1380}
1381
1382DEFUN (smux_peer_password,
1383 smux_peer_password_cmd,
1384 "smux peer OID PASSWORD",
1385 "SNMP MUX protocol settings\n"
1386 "SNMP MUX peer settings\n"
1387 "SMUX peering object ID\n"
1388 "SMUX peering password\n")
1389{
c75105ab 1390 if (smux_peer_oid (vty, argv[0], argv[1]) == 0)
1391 {
1392 smux_start();
1393 return CMD_SUCCESS;
1394 }
1395 else
1396 return CMD_WARNING;
718e3744 1397}
1398
1399DEFUN (no_smux_peer,
1400 no_smux_peer_cmd,
c75105ab 1401 "no smux peer",
718e3744 1402 NO_STR
1403 "SNMP MUX protocol settings\n"
c75105ab 1404 "SNMP MUX peer settings\n")
718e3744 1405{
c75105ab 1406 smux_stop();
718e3744 1407 return smux_peer_default ();
1408}
1409
c75105ab 1410ALIAS (no_smux_peer,
1411 no_smux_peer_oid_cmd,
1412 "no smux peer OID",
1413 NO_STR
1414 "SNMP MUX protocol settings\n"
1415 "SNMP MUX peer settings\n"
1416 "SMUX peering object ID\n")
1417
1418ALIAS (no_smux_peer,
1419 no_smux_peer_oid_password_cmd,
718e3744 1420 "no smux peer OID PASSWORD",
1421 NO_STR
1422 "SNMP MUX protocol settings\n"
1423 "SNMP MUX peer settings\n"
1424 "SMUX peering object ID\n"
1425 "SMUX peering password\n")
718e3744 1426
0be8dfb2 1427static int
718e3744 1428config_write_smux (struct vty *vty)
1429{
1430 int first = 1;
9035efaa 1431 unsigned int i;
718e3744 1432
c75105ab 1433 if (smux_oid)
718e3744 1434 {
1435 vty_out (vty, "smux peer ");
1436 for (i = 0; i < smux_oid_len; i++)
1437 {
1438 vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
1439 first = 0;
1440 }
1441 vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
1442 }
1443 return 0;
1444}
1445
1446/* Register subtree to smux master tree. */
1447void
c9eca01b 1448smux_register_mib (const char *descr, struct variable *var,
1449 size_t width, int num,
718e3744 1450 oid name[], size_t namelen)
1451{
1452 struct subtree *tree;
1453
1454 tree = (struct subtree *)malloc(sizeof(struct subtree));
1455 oid_copy (tree->name, name, namelen);
1456 tree->name_len = namelen;
1457 tree->variables = var;
1458 tree->variables_num = num;
1459 tree->variables_width = width;
1460 tree->registered = 0;
1461 listnode_add_sort(treelist, tree);
1462}
1463
718e3744 1464/* Compare function to keep treelist sorted */
1465static int
1466smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
1467{
1468 return oid_compare(tree1->name, tree1->name_len,
1469 tree2->name, tree2->name_len);
1470}
1471
1472/* Initialize some values then schedule first SMUX connection. */
1473void
c75105ab 1474smux_init (struct thread_master *tm)
718e3744 1475{
dd488a78 1476 /* copy callers thread master */
1477 master = tm;
718e3744 1478
1479 /* Make MIB tree. */
1480 treelist = list_new();
1481 treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
1482
1483 /* Install commands. */
1484 install_node (&smux_node, config_write_smux);
1485
1486 install_element (CONFIG_NODE, &smux_peer_cmd);
1487 install_element (CONFIG_NODE, &smux_peer_password_cmd);
1488 install_element (CONFIG_NODE, &no_smux_peer_cmd);
c75105ab 1489 install_element (CONFIG_NODE, &no_smux_peer_oid_cmd);
1490 install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd);
718e3744 1491}
1492
1493void
1494smux_start(void)
1495{
a56ef883
PJ
1496 /* Close any existing connections. */
1497 smux_stop();
1498
718e3744 1499 /* Schedule first connection. */
1500 smux_event (SMUX_SCHEDULE, 0);
1501}
1502#endif /* HAVE_SNMP */