2 * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
4 * This file is part of GNU Zebra.
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
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.
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
24 #if defined HAVE_SNMP && defined SNMP_SMUX
25 #include <net-snmp/net-snmp-config.h>
26 #include <net-snmp/net-snmp-includes.h>
32 #include <lib/version.h>
34 #include "sockunion.h"
37 #define SMUX_PORT_DEFAULT 199
39 #define SMUXMAXPKTSIZE 1500
40 #define SMUXMAXSTRLEN 256
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)
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)
54 #define SMUX_MAX_FAILURE 3
60 oid name[MAX_OID_LEN];
63 /* List of the variables. */
64 struct variable *variables;
66 /* Length of the variables list. */
69 /* Width of the variables list. */
72 /* Registered flag. */
76 #define min(A,B) ((A) < (B) ? (A) : (B))
78 enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
80 void smux_event (enum smux_event, int);
86 /* SMUX subtree list. */
87 struct list *treelist;
94 char *smux_passwd = NULL;
96 /* SMUX read threads. */
97 struct thread *smux_read_thread;
99 /* SMUX connect thrads. */
100 struct thread *smux_connect_thread;
102 /* SMUX debug flag. */
105 /* SMUX failure count. */
109 static struct cmd_node smux_node =
112 "" /* SMUX has no interface. */
116 static struct thread_master *smux_master;
119 oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
123 for (i = 0; i < min (o1_len, o2_len); i++)
127 else if (o1[i] > o2[i])
137 smux_oid_dump (const char *prefix, const oid *oid, size_t oid_len)
141 char buf[MAX_OID_LEN * 3];
145 for (i = 0; i < oid_len; i++)
147 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
150 zlog_debug ("%s: %s", prefix, buf);
158 struct addrinfo hints, *res0, *res;
161 struct sockaddr_in serv;
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)
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);
180 zlog_warn("Cannot locate loopback service smux");
183 for(res=res0; res; res=res->ai_next)
185 if (res->ai_family != AF_INET
187 && res->ai_family != AF_INET6
188 #endif /* HAVE_IPV6 */
192 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
195 sockopt_reuseaddr (sock);
196 sockopt_reuseport (sock);
197 ret = connect (sock, res->ai_addr, res->ai_addrlen);
208 zlog_warn ("Can't connect to SNMP agent with SMUX");
210 sock = socket (AF_INET, SOCK_STREAM, 0);
213 zlog_warn ("Can't make socket for SNMP");
217 memset (&serv, 0, sizeof (struct sockaddr_in));
218 serv.sin_family = AF_INET;
219 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
220 serv.sin_len = sizeof (struct sockaddr_in);
221 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
223 sp = getservbyname ("smux", "tcp");
225 serv.sin_port = sp->s_port;
227 serv.sin_port = htons (SMUX_PORT_DEFAULT);
229 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
231 sockopt_reuseaddr (sock);
232 sockopt_reuseport (sock);
234 ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
239 zlog_warn ("Can't connect to SNMP agent with SMUX");
247 smux_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)
251 u_char *ptr, *h1, *h1e, *h2, *h2e;
260 zlog_debug ("SMUX GETRSP send");
261 zlog_debug ("SMUX GETRSP reqid: %ld", reqid);
265 /* Place holder h1 for complete sequence */
266 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
269 ptr = asn_build_int (ptr, &len,
270 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
271 &reqid, sizeof (reqid));
274 zlog_debug ("SMUX GETRSP errstat: %ld", errstat);
276 ptr = asn_build_int (ptr, &len,
277 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
278 &errstat, sizeof (errstat));
280 zlog_debug ("SMUX GETRSP errindex: %ld", errindex);
282 ptr = asn_build_int (ptr, &len,
283 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
284 &errindex, sizeof (errindex));
287 /* Place holder h2 for one variable */
288 ptr = asn_build_sequence (ptr, &len,
289 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
293 ptr = snmp_build_var_op (ptr, objid, &objid_len,
294 val_type, arg_len, arg, &len);
296 /* Now variable size is known, fill in size */
297 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
299 /* Fill in size of whole sequence */
300 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
303 zlog_debug ("SMUX getresp send: %td", (ptr - buf));
305 send (smux_sock, buf, (ptr - buf), 0);
309 smux_var (u_char *ptr, size_t len, oid objid[], size_t *objid_len,
311 u_char *var_val_type,
320 zlog_debug ("SMUX var parse: len %zd", len);
323 ptr = asn_parse_header (ptr, &len, &type);
327 zlog_debug ("SMUX var parse: type %d len %zd", type, len);
328 zlog_debug ("SMUX var parse: type must be %d",
329 (ASN_SEQUENCE | ASN_CONSTRUCTOR));
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);
338 *var_val_len = val_len;
341 *var_value = (void*) val;
344 *var_val_type = val_type;
346 /* Requested object id length is objid_len. */
348 smux_oid_dump ("Request OID", objid, *objid_len);
351 zlog_debug ("SMUX val_type: %d", val_type);
353 /* Check request value type. */
358 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
360 zlog_debug ("ASN_NULL");
364 zlog_debug ("ASN_INTEGER");
370 zlog_debug ("ASN_COUNTER");
373 zlog_debug ("ASN_COUNTER64");
376 zlog_debug ("ASN_IPADDRESS");
379 zlog_debug ("ASN_OCTET_STR");
384 zlog_debug ("ASN_OPAQUE");
386 case SNMP_NOSUCHOBJECT:
387 zlog_debug ("SNMP_NOSUCHOBJECT");
389 case SNMP_NOSUCHINSTANCE:
390 zlog_debug ("SNMP_NOSUCHINSTANCE");
392 case SNMP_ENDOFMIBVIEW:
393 zlog_debug ("SNMP_ENDOFMIBVIEW");
396 zlog_debug ("ASN_BIT_STR");
399 zlog_debug ("Unknown type");
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. */
410 smux_set (oid *reqid, size_t *reqid_len,
411 u_char val_type, void *val, size_t val_len, int action)
414 struct subtree *subtree;
420 u_char *statP = NULL;
421 WriteMethod *write_method = NULL;
422 struct listnode *node, *nnode;
425 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
427 subresult = oid_compare_part (reqid, *reqid_len,
428 subtree->name, subtree->name_len);
430 /* Subtree matched. */
433 /* Prepare suffix. */
434 suffix = reqid + subtree->name_len;
435 suffix_len = *reqid_len - subtree->name_len;
438 /* Check variables. */
439 for (j = 0; j < subtree->variables_num; j++)
441 v = &subtree->variables[j];
443 /* Always check suffix */
444 result = oid_compare_part (suffix, suffix_len,
445 v->name, v->namelen);
447 /* This is exact match so result must be zero. */
451 zlog_debug ("SMUX function call index is %d", v->magic);
453 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
454 &val_len, &write_method);
458 return (*write_method)(action, val, val_type, val_len,
459 statP, suffix, suffix_len);
463 return SNMP_ERR_READONLY;
467 /* If above execution is failed or oid is small (so
468 there is no further match). */
470 return SNMP_ERR_NOSUCHNAME;
474 return SNMP_ERR_NOSUCHNAME;
478 smux_get (oid *reqid, size_t *reqid_len, int exact,
479 u_char *val_type,void **val, size_t *val_len)
482 struct subtree *subtree;
488 WriteMethod *write_method=NULL;
489 struct listnode *node, *nnode;
492 for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree))
494 subresult = oid_compare_part (reqid, *reqid_len,
495 subtree->name, subtree->name_len);
497 /* Subtree matched. */
500 /* Prepare suffix. */
501 suffix = reqid + subtree->name_len;
502 suffix_len = *reqid_len - subtree->name_len;
505 /* Check variables. */
506 for (j = 0; j < subtree->variables_num; j++)
508 v = &subtree->variables[j];
510 /* Always check suffix */
511 result = oid_compare_part (suffix, suffix_len,
512 v->name, v->namelen);
514 /* This is exact match so result must be zero. */
518 zlog_debug ("SMUX function call index is %d", v->magic);
520 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
521 val_len, &write_method);
523 /* There is no instance. */
525 return SNMP_NOSUCHINSTANCE;
527 /* Call is suceed. */
533 /* If above execution is failed or oid is small (so
534 there is no further match). */
536 return SNMP_ERR_NOSUCHNAME;
540 return SNMP_ERR_NOSUCHNAME;
544 smux_getnext (oid *reqid, size_t *reqid_len, int exact,
545 u_char *val_type,void **val, size_t *val_len)
548 oid save[MAX_OID_LEN];
550 struct subtree *subtree;
556 WriteMethod *write_method=NULL;
557 struct listnode *node, *nnode;
560 /* Save incoming request. */
561 oid_copy (save, reqid, *reqid_len);
562 savelen = *reqid_len;
565 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
567 subresult = oid_compare_part (reqid, *reqid_len,
568 subtree->name, subtree->name_len);
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 */
583 /* Prepare suffix. */
584 suffix = reqid + subtree->name_len;
585 suffix_len = *reqid_len - subtree->name_len;
588 oid_copy(reqid, subtree->name, subtree->name_len);
589 *reqid_len = subtree->name_len;
591 for (j = 0; j < subtree->variables_num; j++)
594 v = &subtree->variables[j];
596 /* Next then check result >= 0. */
598 result = oid_compare_part (suffix, suffix_len,
599 v->name, v->namelen);
604 zlog_debug ("SMUX function call index is %d", v->magic);
607 oid_copy(suffix, v->name, v->namelen);
608 suffix_len = v->namelen;
610 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
611 val_len, &write_method);
612 *reqid_len = suffix_len + subtree->name_len;
622 memcpy (reqid, save, savelen * sizeof(oid));
623 *reqid_len = savelen;
625 return SNMP_ERR_NOSUCHNAME;
628 /* GET message header. */
630 smux_parse_get_header (u_char *ptr, size_t *len, long *reqid)
637 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
640 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
643 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
646 zlog_debug ("SMUX GET errstat %ld len: %zd", errstat, *len);
649 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
652 zlog_debug ("SMUX GET errindex %ld len: %zd", errindex, *len);
658 smux_parse_set (u_char *ptr, size_t len, int action)
661 oid oid[MAX_OID_LEN];
669 zlog_debug ("SMUX SET(%s) message parse: len %zd",
670 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
673 /* Parse SET message header. */
674 ptr = smux_parse_get_header (ptr, &len, &reqid);
676 /* Parse SET message object ID. */
677 ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
679 ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
681 zlog_debug ("SMUX SET ret %d", ret);
684 if (RESERVE1 == action)
685 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
689 smux_parse_get (u_char *ptr, size_t len, int exact)
692 oid oid[MAX_OID_LEN];
700 zlog_debug ("SMUX GET message parse: len %zd", len);
702 /* Parse GET message header. */
703 ptr = smux_parse_get_header (ptr, &len, &reqid);
705 /* Parse GET message object ID. We needn't the value come */
706 ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
708 /* Traditional getstatptr. */
710 ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
712 ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
716 smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
718 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
721 /* Parse SMUX_CLOSE message. */
723 smux_parse_close (u_char *ptr, int len)
729 reason = (reason << 8) | (long) *ptr;
732 zlog_info ("SMUX_CLOSE with reason: %ld", reason);
735 /* SMUX_RRSP message. */
737 smux_parse_rrsp (u_char *ptr, size_t len)
742 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
745 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
748 /* Parse SMUX message. */
750 smux_parse (u_char *ptr, size_t len)
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;
758 int len_income = len; /* see note below: YYY */
762 rollback = ptr[2]; /* important only for SMUX_SOUT */
764 process_rest: /* see note below: YYY */
766 /* Parse SMUX message type and subsequent length. */
767 ptr = asn_parse_header (ptr, &len, &type);
770 zlog_debug ("SMUX message received type: %d rest len: %zd", type, len);
775 /* Open must be not send from SNMP agent. */
776 zlog_warn ("SMUX_OPEN received: resetting connection.");
780 /* SMUX_RREQ message is invalid for us. */
781 zlog_warn ("SMUX_RREQ received: resetting connection.");
785 /* SMUX_SOUT message is now valied for us. */
787 zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
789 if (sout_save_len > 0)
791 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
795 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
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' */
810 len = len_income - 3;
815 /* SMUX_GETRSP message is invalid for us. */
816 zlog_warn ("SMUX_GETRSP received: resetting connection.");
820 /* Close SMUX connection. */
822 zlog_debug ("SMUX_CLOSE");
823 smux_parse_close (ptr, len);
827 /* This is response for register message. */
829 zlog_debug ("SMUX_RRSP");
830 smux_parse_rrsp (ptr, len);
833 /* Exact request for object id. */
835 zlog_debug ("SMUX_GET");
836 smux_parse_get (ptr, len, 1);
839 /* Next request for object id. */
841 zlog_debug ("SMUX_GETNEXT");
842 smux_parse_get (ptr, len, 0);
845 /* SMUX_SET is supported with some limitations. */
847 zlog_debug ("SMUX_SET");
849 /* save the data for future SMUX_SOUT */
850 memcpy (sout_save_buff, ptr, len);
852 smux_parse_set (ptr, len, RESERVE1);
855 zlog_info ("Unknown type: %d", type);
861 /* SMUX message read function. */
863 smux_read (struct thread *t)
867 u_char buf[SMUXMAXPKTSIZE];
871 sock = THREAD_FD (t);
872 smux_read_thread = NULL;
875 zlog_debug ("SMUX read start");
877 /* Read message from SMUX socket. */
878 len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
882 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno));
885 smux_event (SMUX_CONNECT, 0);
891 zlog_warn ("SMUX connection closed: %d", sock);
894 smux_event (SMUX_CONNECT, 0);
899 zlog_debug ("SMUX read len: %d", len);
901 /* Parse the message. */
902 ret = smux_parse (buf, len);
908 smux_event (SMUX_CONNECT, 0);
912 /* Regiser read thread. */
913 smux_event (SMUX_READ, sock);
925 const char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION;
929 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
930 zlog_debug ("SMUX open progname: %s", progname);
931 zlog_debug ("SMUX open password: %s", smux_passwd);
937 /* SMUX Header. As placeholder. */
938 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
942 ptr = asn_build_int (ptr, &len,
943 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
944 &version, sizeof (version));
946 /* SMUX connection oid. */
947 ptr = asn_build_objid (ptr, &len,
949 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
950 smux_oid, smux_oid_len);
952 /* SMUX connection description. */
953 ptr = asn_build_string (ptr, &len,
955 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
956 (const u_char *) progname, strlen (progname));
958 /* SMUX connection password. */
959 ptr = asn_build_string (ptr, &len,
961 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
962 (u_char *)smux_passwd, strlen (smux_passwd));
964 /* Fill in real SMUX header. We exclude ASN header size (2). */
966 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
968 return send (sock, buf, (ptr - buf), 0);
971 /* `ename` is ignored. Instead of using the provided enterprise OID,
972 the SMUX peer is used. This keep compatibility with the previous
975 All other fields are used as they are intended. */
977 smux_trap (struct variable *vp, size_t vp_len,
978 const oid *ename, size_t enamelen,
979 const oid *name, size_t namelen,
980 const oid *iname, size_t inamelen,
981 const struct trap_object *trapobj, size_t trapobjlen,
996 /* When SMUX connection is not established. */
1001 ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
1003 /* Sub agent enterprise oid. */
1004 ptr = asn_build_objid (ptr, &len,
1006 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1007 smux_oid, smux_oid_len);
1011 ptr = asn_build_string (ptr, &len,
1013 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
1014 (u_char *)&addr, sizeof (addr));
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),
1020 (long *)&val, sizeof (val));
1022 /* Specific trap integer. */
1024 ptr = asn_build_int (ptr, &len,
1025 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1026 (long *)&val, sizeof (val));
1028 /* Timeticks timestamp. */
1030 ptr = asn_build_unsigned_int (ptr, &len,
1031 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS),
1032 &val, sizeof (val));
1036 ptr = asn_build_sequence (ptr, &len,
1037 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1041 /* Iteration for each objects. */
1043 for (i = 0; i < trapobjlen; i++)
1046 oid oid[MAX_OID_LEN];
1053 if (trapobj[i].namelen > 0)
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;
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) ;
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));
1075 smux_oid_dump ("Trap", trapobj[i].name, (trapobj[i].namelen));
1076 smux_oid_dump ("Trap", iname, inamelen);
1078 smux_oid_dump ("Trap", oid, oid_len);
1079 zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ, (u_long)oid_len);
1082 ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
1085 zlog_debug ("smux_get result %d", ret);
1088 ptr = snmp_build_var_op (ptr, oid, &oid_len,
1089 val_type, val_len, val, &len);
1092 /* Now variable size is known, fill in size */
1093 asn_build_sequence(h1, &length,
1094 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1097 /* Fill in size of whole sequence */
1099 asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
1101 return send (smux_sock, buf, (ptr - buf), 0);
1105 smux_register (int sock)
1113 struct subtree *subtree;
1114 struct listnode *node, *nnode;
1118 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
1123 /* SMUX RReq Header. */
1124 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
1126 /* Register MIB tree. */
1127 ptr = asn_build_objid (ptr, &len,
1129 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1130 subtree->name, subtree->name_len);
1134 ptr = asn_build_int (ptr, &len,
1135 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1136 &priority, sizeof (priority));
1139 operation = 2; /* Register R/W */
1140 ptr = asn_build_int (ptr, &len,
1141 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1142 &operation, sizeof (operation));
1146 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
1147 zlog_debug ("SMUX register priority: %ld", priority);
1148 zlog_debug ("SMUX register operation: %ld", operation);
1152 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
1153 ret = send (sock, buf, (ptr - buf), 0);
1160 /* Try to connect to SNMP agent. */
1162 smux_connect (struct thread *t)
1167 zlog_debug ("SMUX connect try %d", fail + 1);
1169 /* Clear thread poner of myself. */
1170 smux_connect_thread = NULL;
1172 /* Make socket. Try to connect. */
1173 smux_sock = smux_socket ();
1176 if (++fail < SMUX_MAX_FAILURE)
1177 smux_event (SMUX_CONNECT, 0);
1181 /* Send OPEN PDU. */
1182 ret = smux_open (smux_sock);
1185 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno));
1188 if (++fail < SMUX_MAX_FAILURE)
1189 smux_event (SMUX_CONNECT, 0);
1193 /* Send any outstanding register PDUs. */
1194 ret = smux_register (smux_sock);
1197 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno));
1200 if (++fail < SMUX_MAX_FAILURE)
1201 smux_event (SMUX_CONNECT, 0);
1205 /* Everything goes fine. */
1206 smux_event (SMUX_READ, smux_sock);
1211 /* Clear all SMUX related resources. */
1215 if (smux_read_thread)
1217 thread_cancel (smux_read_thread);
1218 smux_read_thread = NULL;
1221 if (smux_connect_thread)
1223 thread_cancel (smux_connect_thread);
1224 smux_connect_thread = NULL;
1237 smux_event (enum smux_event event, int sock)
1242 smux_connect_thread = thread_add_event (smux_master, smux_connect, NULL, 0);
1245 smux_connect_thread = thread_add_timer (smux_master, smux_connect, NULL, 10);
1248 smux_read_thread = thread_add_read (smux_master, smux_read, NULL, sock);
1256 smux_str2oid (const char *str, oid *oid, size_t *oid_len)
1272 if (! isdigit (*str))
1275 while (isdigit (*str))
1278 val += (*str - '0');
1299 smux_oid_dup (oid *objid, size_t objid_len)
1303 new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
1304 oid_copy (new, objid, objid_len);
1310 smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str)
1313 oid oid[MAX_OID_LEN];
1316 ret = smux_str2oid (oid_str, oid, &oid_len);
1319 vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
1329 /* careful, smux_passwd might point to string constant */
1336 smux_oid = smux_oid_dup (oid, oid_len);
1337 smux_oid_len = oid_len;
1340 smux_passwd = strdup (passwd_str);
1342 smux_passwd = strdup ("");
1348 smux_peer_default (void)
1356 /* careful, smux_passwd might be pointing at string constant */
1369 "SNMP MUX protocol settings\n"
1370 "SNMP MUX peer settings\n"
1371 "Object ID used in SMUX peering\n")
1373 if (smux_peer_oid (vty, argv[0], NULL) == 0)
1382 DEFUN (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")
1390 if (smux_peer_oid (vty, argv[0], argv[1]) == 0)
1399 DEFUN (no_smux_peer,
1403 "SNMP MUX protocol settings\n"
1404 "SNMP MUX peer settings\n")
1407 return smux_peer_default ();
1410 ALIAS (no_smux_peer,
1411 no_smux_peer_oid_cmd,
1414 "SNMP MUX protocol settings\n"
1415 "SNMP MUX peer settings\n"
1416 "SMUX peering object ID\n")
1418 ALIAS (no_smux_peer,
1419 no_smux_peer_oid_password_cmd,
1420 "no smux peer OID PASSWORD",
1422 "SNMP MUX protocol settings\n"
1423 "SNMP MUX peer settings\n"
1424 "SMUX peering object ID\n"
1425 "SMUX peering password\n")
1428 config_write_smux (struct vty *vty)
1435 vty_out (vty, "smux peer ");
1436 for (i = 0; i < smux_oid_len; i++)
1438 vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
1441 vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
1446 /* Register subtree to smux master tree. */
1448 smux_register_mib (const char *descr, struct variable *var,
1449 size_t width, int num,
1450 oid name[], size_t namelen)
1452 struct subtree *tree;
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);
1464 /* Compare function to keep treelist sorted */
1466 smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
1468 return oid_compare(tree1->name, tree1->name_len,
1469 tree2->name, tree2->name_len);
1472 /* Initialize some values then schedule first SMUX connection. */
1474 smux_init (struct thread_master *tm)
1476 /* copy callers thread master */
1479 /* Make MIB tree. */
1480 treelist = list_new();
1481 treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
1483 /* Install commands. */
1484 install_node (&smux_node, config_write_smux);
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);
1489 install_element (CONFIG_NODE, &no_smux_peer_oid_cmd);
1490 install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd);
1496 /* Close any existing connections. */
1499 /* Schedule first connection. */
1500 smux_event (SMUX_SCHEDULE, 0);
1502 #endif /* HAVE_SNMP */