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
);
157 struct addrinfo hints
, *res0
, *res
;
161 memset(&hints
, 0, sizeof(hints
));
162 hints
.ai_family
= PF_UNSPEC
;
163 hints
.ai_socktype
= SOCK_STREAM
;
164 gai
= getaddrinfo(NULL
, "smux", &hints
, &res0
);
165 if (gai
== EAI_SERVICE
)
167 char servbuf
[NI_MAXSERV
];
168 sprintf(servbuf
,"%d",SMUX_PORT_DEFAULT
);
169 servbuf
[sizeof (servbuf
) - 1] = '\0';
170 gai
= getaddrinfo(NULL
, servbuf
, &hints
, &res0
);
174 zlog_warn("Cannot locate loopback service smux");
177 for(res
=res0
; res
; res
=res
->ai_next
)
179 if (res
->ai_family
!= AF_INET
180 && res
->ai_family
!= AF_INET6
184 sock
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
187 sockopt_reuseaddr (sock
);
188 sockopt_reuseport (sock
);
189 ret
= connect (sock
, res
->ai_addr
, res
->ai_addrlen
);
200 zlog_warn ("Can't connect to SNMP agent with SMUX");
205 smux_getresp_send (oid objid
[], size_t objid_len
, long reqid
, long errstat
,
206 long errindex
, u_char val_type
, void *arg
, size_t arg_len
)
209 u_char
*ptr
, *h1
, *h1e
, *h2
, *h2e
;
218 zlog_debug ("SMUX GETRSP send");
219 zlog_debug ("SMUX GETRSP reqid: %ld", reqid
);
223 /* Place holder h1 for complete sequence */
224 ptr
= asn_build_sequence (ptr
, &len
, (u_char
) SMUX_GETRSP
, 0);
227 ptr
= asn_build_int (ptr
, &len
,
228 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
229 &reqid
, sizeof (reqid
));
232 zlog_debug ("SMUX GETRSP errstat: %ld", errstat
);
234 ptr
= asn_build_int (ptr
, &len
,
235 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
236 &errstat
, sizeof (errstat
));
238 zlog_debug ("SMUX GETRSP errindex: %ld", errindex
);
240 ptr
= asn_build_int (ptr
, &len
,
241 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
242 &errindex
, sizeof (errindex
));
245 /* Place holder h2 for one variable */
246 ptr
= asn_build_sequence (ptr
, &len
,
247 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
251 ptr
= snmp_build_var_op (ptr
, objid
, &objid_len
,
252 val_type
, arg_len
, arg
, &len
);
254 /* Now variable size is known, fill in size */
255 asn_build_sequence(h2
,&length
,(u_char
)(ASN_SEQUENCE
|ASN_CONSTRUCTOR
),ptr
-h2e
);
257 /* Fill in size of whole sequence */
258 asn_build_sequence(h1
,&length
,(u_char
)SMUX_GETRSP
,ptr
-h1e
);
261 zlog_debug ("SMUX getresp send: %td", (ptr
- buf
));
263 send (smux_sock
, buf
, (ptr
- buf
), 0);
267 smux_var (u_char
*ptr
, size_t len
, oid objid
[], size_t *objid_len
,
269 u_char
*var_val_type
,
278 zlog_debug ("SMUX var parse: len %zd", len
);
281 ptr
= asn_parse_header (ptr
, &len
, &type
);
285 zlog_debug ("SMUX var parse: type %d len %zd", type
, len
);
286 zlog_debug ("SMUX var parse: type must be %d",
287 (ASN_SEQUENCE
| ASN_CONSTRUCTOR
));
290 /* Parse var option. */
291 *objid_len
= MAX_OID_LEN
;
292 ptr
= snmp_parse_var_op(ptr
, objid
, objid_len
, &val_type
,
293 &val_len
, &val
, &len
);
296 *var_val_len
= val_len
;
299 *var_value
= (void*) val
;
302 *var_val_type
= val_type
;
304 /* Requested object id length is objid_len. */
306 smux_oid_dump ("Request OID", objid
, *objid_len
);
309 zlog_debug ("SMUX val_type: %d", val_type
);
311 /* Check request value type. */
316 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
318 zlog_debug ("ASN_NULL");
322 zlog_debug ("ASN_INTEGER");
328 zlog_debug ("ASN_COUNTER");
331 zlog_debug ("ASN_COUNTER64");
334 zlog_debug ("ASN_IPADDRESS");
337 zlog_debug ("ASN_OCTET_STR");
342 zlog_debug ("ASN_OPAQUE");
344 case SNMP_NOSUCHOBJECT
:
345 zlog_debug ("SNMP_NOSUCHOBJECT");
347 case SNMP_NOSUCHINSTANCE
:
348 zlog_debug ("SNMP_NOSUCHINSTANCE");
350 case SNMP_ENDOFMIBVIEW
:
351 zlog_debug ("SNMP_ENDOFMIBVIEW");
354 zlog_debug ("ASN_BIT_STR");
357 zlog_debug ("Unknown type");
363 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
364 ucd-snmp smux and as such suppose, that the peer receives in the message
365 only one variable. Fortunately, IBM seems to do the same in AIX. */
368 smux_set (oid
*reqid
, size_t *reqid_len
,
369 u_char val_type
, void *val
, size_t val_len
, int action
)
372 struct subtree
*subtree
;
378 u_char
*statP
= NULL
;
379 WriteMethod
*write_method
= NULL
;
380 struct listnode
*node
, *nnode
;
383 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
385 subresult
= oid_compare_part (reqid
, *reqid_len
,
386 subtree
->name
, subtree
->name_len
);
388 /* Subtree matched. */
391 /* Prepare suffix. */
392 suffix
= reqid
+ subtree
->name_len
;
393 suffix_len
= *reqid_len
- subtree
->name_len
;
396 /* Check variables. */
397 for (j
= 0; j
< subtree
->variables_num
; j
++)
399 v
= &subtree
->variables
[j
];
401 /* Always check suffix */
402 result
= oid_compare_part (suffix
, suffix_len
,
403 v
->name
, v
->namelen
);
405 /* This is exact match so result must be zero. */
409 zlog_debug ("SMUX function call index is %d", v
->magic
);
411 statP
= (*v
->findVar
) (v
, suffix
, &suffix_len
, 1,
412 &val_len
, &write_method
);
416 return (*write_method
)(action
, val
, val_type
, val_len
,
417 statP
, suffix
, suffix_len
);
421 return SNMP_ERR_READONLY
;
425 /* If above execution is failed or oid is small (so
426 there is no further match). */
428 return SNMP_ERR_NOSUCHNAME
;
432 return SNMP_ERR_NOSUCHNAME
;
436 smux_get (oid
*reqid
, size_t *reqid_len
, int exact
,
437 u_char
*val_type
,void **val
, size_t *val_len
)
440 struct subtree
*subtree
;
446 WriteMethod
*write_method
=NULL
;
447 struct listnode
*node
, *nnode
;
450 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
,subtree
))
452 subresult
= oid_compare_part (reqid
, *reqid_len
,
453 subtree
->name
, subtree
->name_len
);
455 /* Subtree matched. */
458 /* Prepare suffix. */
459 suffix
= reqid
+ subtree
->name_len
;
460 suffix_len
= *reqid_len
- subtree
->name_len
;
463 /* Check variables. */
464 for (j
= 0; j
< subtree
->variables_num
; j
++)
466 v
= &subtree
->variables
[j
];
468 /* Always check suffix */
469 result
= oid_compare_part (suffix
, suffix_len
,
470 v
->name
, v
->namelen
);
472 /* This is exact match so result must be zero. */
476 zlog_debug ("SMUX function call index is %d", v
->magic
);
478 *val
= (*v
->findVar
) (v
, suffix
, &suffix_len
, exact
,
479 val_len
, &write_method
);
481 /* There is no instance. */
483 return SNMP_NOSUCHINSTANCE
;
485 /* Call is suceed. */
491 /* If above execution is failed or oid is small (so
492 there is no further match). */
494 return SNMP_ERR_NOSUCHNAME
;
498 return SNMP_ERR_NOSUCHNAME
;
502 smux_getnext (oid
*reqid
, size_t *reqid_len
, int exact
,
503 u_char
*val_type
,void **val
, size_t *val_len
)
506 oid save
[MAX_OID_LEN
];
508 struct subtree
*subtree
;
514 WriteMethod
*write_method
=NULL
;
515 struct listnode
*node
, *nnode
;
518 /* Save incoming request. */
519 oid_copy (save
, reqid
, *reqid_len
);
520 savelen
= *reqid_len
;
523 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
525 subresult
= oid_compare_part (reqid
, *reqid_len
,
526 subtree
->name
, subtree
->name_len
);
528 /* If request is in the tree. The agent has to make sure we
529 only receive requests we have registered for. */
530 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
531 behave as if it manages the whole SNMP MIB tree itself. It's the
532 duty of the master agent to collect the best answer and return it
533 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
534 :-). ucd-snmp really behaves bad here as it actually might ask
535 multiple times for the same GETNEXT request as it throws away the
536 answer when it expects it in a different subtree and might come
537 back later with the very same request. --jochen */
541 /* Prepare suffix. */
542 suffix
= reqid
+ subtree
->name_len
;
543 suffix_len
= *reqid_len
- subtree
->name_len
;
546 oid_copy(reqid
, subtree
->name
, subtree
->name_len
);
547 *reqid_len
= subtree
->name_len
;
549 for (j
= 0; j
< subtree
->variables_num
; j
++)
552 v
= &subtree
->variables
[j
];
554 /* Next then check result >= 0. */
556 result
= oid_compare_part (suffix
, suffix_len
,
557 v
->name
, v
->namelen
);
562 zlog_debug ("SMUX function call index is %d", v
->magic
);
565 oid_copy(suffix
, v
->name
, v
->namelen
);
566 suffix_len
= v
->namelen
;
568 *val
= (*v
->findVar
) (v
, suffix
, &suffix_len
, exact
,
569 val_len
, &write_method
);
570 *reqid_len
= suffix_len
+ subtree
->name_len
;
580 memcpy (reqid
, save
, savelen
* sizeof(oid
));
581 *reqid_len
= savelen
;
583 return SNMP_ERR_NOSUCHNAME
;
586 /* GET message header. */
588 smux_parse_get_header (u_char
*ptr
, size_t *len
, long *reqid
)
595 ptr
= asn_parse_int (ptr
, len
, &type
, reqid
, sizeof (*reqid
));
598 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid
, (int) *len
);
601 ptr
= asn_parse_int (ptr
, len
, &type
, &errstat
, sizeof (errstat
));
604 zlog_debug ("SMUX GET errstat %ld len: %zd", errstat
, *len
);
607 ptr
= asn_parse_int (ptr
, len
, &type
, &errindex
, sizeof (errindex
));
610 zlog_debug ("SMUX GET errindex %ld len: %zd", errindex
, *len
);
616 smux_parse_set (u_char
*ptr
, size_t len
, int action
)
619 oid oid
[MAX_OID_LEN
];
627 zlog_debug ("SMUX SET(%s) message parse: len %zd",
628 (RESERVE1
== action
) ? "RESERVE1" : ((FREE
== action
) ? "FREE" : "COMMIT"),
631 /* Parse SET message header. */
632 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
634 /* Parse SET message object ID. */
635 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, &val_len
, &val_type
, &val
);
637 ret
= smux_set (oid
, &oid_len
, val_type
, val
, val_len
, action
);
639 zlog_debug ("SMUX SET ret %d", ret
);
642 if (RESERVE1
== action
)
643 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
647 smux_parse_get (u_char
*ptr
, size_t len
, int exact
)
650 oid oid
[MAX_OID_LEN
];
658 zlog_debug ("SMUX GET message parse: len %zd", len
);
660 /* Parse GET message header. */
661 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
663 /* Parse GET message object ID. We needn't the value come */
664 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, NULL
, NULL
, NULL
);
666 /* Traditional getstatptr. */
668 ret
= smux_get (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
670 ret
= smux_getnext (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
674 smux_getresp_send (oid
, oid_len
, reqid
, 0, 0, val_type
, val
, val_len
);
676 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
679 /* Parse SMUX_CLOSE message. */
681 smux_parse_close (u_char
*ptr
, int len
)
687 reason
= (reason
<< 8) | (long) *ptr
;
690 zlog_info ("SMUX_CLOSE with reason: %ld", reason
);
693 /* SMUX_RRSP message. */
695 smux_parse_rrsp (u_char
*ptr
, size_t len
)
700 ptr
= asn_parse_int (ptr
, &len
, &val
, &errstat
, sizeof (errstat
));
703 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val
, errstat
);
706 /* Parse SMUX message. */
708 smux_parse (u_char
*ptr
, size_t len
)
710 /* This buffer we'll use for SOUT message. We could allocate it with
711 malloc and save only static pointer/lenght, but IMHO static
712 buffer is a faster solusion. */
713 static u_char sout_save_buff
[SMUXMAXPKTSIZE
];
714 static int sout_save_len
= 0;
716 int len_income
= len
; /* see note below: YYY */
720 rollback
= ptr
[2]; /* important only for SMUX_SOUT */
722 process_rest
: /* see note below: YYY */
724 /* Parse SMUX message type and subsequent length. */
725 ptr
= asn_parse_header (ptr
, &len
, &type
);
728 zlog_debug ("SMUX message received type: %d rest len: %zd", type
, len
);
733 /* Open must be not send from SNMP agent. */
734 zlog_warn ("SMUX_OPEN received: resetting connection.");
738 /* SMUX_RREQ message is invalid for us. */
739 zlog_warn ("SMUX_RREQ received: resetting connection.");
743 /* SMUX_SOUT message is now valied for us. */
745 zlog_debug ("SMUX_SOUT(%s)", rollback
? "rollback" : "commit");
747 if (sout_save_len
> 0)
749 smux_parse_set (sout_save_buff
, sout_save_len
, rollback
? FREE
: COMMIT
);
753 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len
);
757 /* YYY: this strange code has to solve the "slow peer"
758 problem: When agent sends SMUX_SOUT message it doesn't
759 wait any responce and may send some next message to
760 subagent. Then the peer in 'smux_read()' will recieve
761 from socket the 'concatenated' buffer, contaning both
762 SMUX_SOUT message and the next one
763 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
764 the buffer is longer than 3 ( length of SMUX_SOUT ), we
765 must process the rest of it. This effect may be observed
766 if 'debug_smux' is set to '1' */
768 len
= len_income
- 3;
773 /* SMUX_GETRSP message is invalid for us. */
774 zlog_warn ("SMUX_GETRSP received: resetting connection.");
778 /* Close SMUX connection. */
780 zlog_debug ("SMUX_CLOSE");
781 smux_parse_close (ptr
, len
);
785 /* This is response for register message. */
787 zlog_debug ("SMUX_RRSP");
788 smux_parse_rrsp (ptr
, len
);
791 /* Exact request for object id. */
793 zlog_debug ("SMUX_GET");
794 smux_parse_get (ptr
, len
, 1);
797 /* Next request for object id. */
799 zlog_debug ("SMUX_GETNEXT");
800 smux_parse_get (ptr
, len
, 0);
803 /* SMUX_SET is supported with some limitations. */
805 zlog_debug ("SMUX_SET");
807 /* save the data for future SMUX_SOUT */
808 memcpy (sout_save_buff
, ptr
, len
);
810 smux_parse_set (ptr
, len
, RESERVE1
);
813 zlog_info ("Unknown type: %d", type
);
819 /* SMUX message read function. */
821 smux_read (struct thread
*t
)
825 u_char buf
[SMUXMAXPKTSIZE
];
829 sock
= THREAD_FD (t
);
830 smux_read_thread
= NULL
;
833 zlog_debug ("SMUX read start");
835 /* Read message from SMUX socket. */
836 len
= recv (sock
, buf
, SMUXMAXPKTSIZE
, 0);
840 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno
));
843 smux_event (SMUX_CONNECT
, 0);
849 zlog_warn ("SMUX connection closed: %d", sock
);
852 smux_event (SMUX_CONNECT
, 0);
857 zlog_debug ("SMUX read len: %d", len
);
859 /* Parse the message. */
860 ret
= smux_parse (buf
, len
);
866 smux_event (SMUX_CONNECT
, 0);
870 /* Regiser read thread. */
871 smux_event (SMUX_READ
, sock
);
883 const char progname
[] = FRR_SMUX_NAME
"-" FRR_VERSION
;
887 smux_oid_dump ("SMUX open oid", smux_oid
, smux_oid_len
);
888 zlog_debug ("SMUX open progname: %s", progname
);
889 zlog_debug ("SMUX open password: %s", smux_passwd
);
895 /* SMUX Header. As placeholder. */
896 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_OPEN
, 0);
900 ptr
= asn_build_int (ptr
, &len
,
901 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
902 &version
, sizeof (version
));
904 /* SMUX connection oid. */
905 ptr
= asn_build_objid (ptr
, &len
,
907 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
908 smux_oid
, smux_oid_len
);
910 /* SMUX connection description. */
911 ptr
= asn_build_string (ptr
, &len
,
913 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
914 (const u_char
*) progname
, strlen (progname
));
916 /* SMUX connection password. */
917 ptr
= asn_build_string (ptr
, &len
,
919 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
920 (u_char
*)smux_passwd
, strlen (smux_passwd
));
922 /* Fill in real SMUX header. We exclude ASN header size (2). */
924 asn_build_header (buf
, &len
, (u_char
) SMUX_OPEN
, (ptr
- buf
) - 2);
926 return send (sock
, buf
, (ptr
- buf
), 0);
929 /* `ename` is ignored. Instead of using the provided enterprise OID,
930 the SMUX peer is used. This keep compatibility with the previous
933 All other fields are used as they are intended. */
935 smux_trap (struct variable
*vp
, size_t vp_len
,
936 const oid
*ename
, size_t enamelen
,
937 const oid
*name
, size_t namelen
,
938 const oid
*iname
, size_t inamelen
,
939 const struct trap_object
*trapobj
, size_t trapobjlen
,
954 /* When SMUX connection is not established. */
959 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_TRAP
, 0);
961 /* Sub agent enterprise oid. */
962 ptr
= asn_build_objid (ptr
, &len
,
964 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
965 smux_oid
, smux_oid_len
);
969 ptr
= asn_build_string (ptr
, &len
,
971 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_IPADDRESS
),
972 (u_char
*)&addr
, sizeof (addr
));
974 /* Generic trap integer. */
975 val
= SNMP_TRAP_ENTERPRISESPECIFIC
;
976 ptr
= asn_build_int (ptr
, &len
,
977 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
978 (long *)&val
, sizeof (val
));
980 /* Specific trap integer. */
982 ptr
= asn_build_int (ptr
, &len
,
983 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
984 (long *)&val
, sizeof (val
));
986 /* Timeticks timestamp. */
988 ptr
= asn_build_unsigned_int (ptr
, &len
,
989 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_TIMETICKS
),
994 ptr
= asn_build_sequence (ptr
, &len
,
995 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
999 /* Iteration for each objects. */
1001 for (i
= 0; i
< trapobjlen
; i
++)
1004 oid oid
[MAX_OID_LEN
];
1011 if (trapobj
[i
].namelen
> 0)
1013 oid_copy (oid
, name
, namelen
);
1014 oid_copy (oid
+ namelen
, trapobj
[i
].name
, trapobj
[i
].namelen
);
1015 oid_copy (oid
+ namelen
+ trapobj
[i
].namelen
, iname
, inamelen
);
1016 oid_len
= namelen
+ trapobj
[i
].namelen
+ inamelen
;
1020 oid_copy (oid
, name
, namelen
);
1021 oid_copy (oid
+ namelen
, trapobj
[i
].name
, trapobj
[i
].namelen
* (-1));
1022 oid_len
= namelen
+ trapobj
[i
].namelen
* (-1) ;
1027 smux_oid_dump ("Trap", name
, namelen
);
1028 if (trapobj
[i
].namelen
< 0)
1029 smux_oid_dump ("Trap",
1030 trapobj
[i
].name
, (- 1) * (trapobj
[i
].namelen
));
1033 smux_oid_dump ("Trap", trapobj
[i
].name
, (trapobj
[i
].namelen
));
1034 smux_oid_dump ("Trap", iname
, inamelen
);
1036 smux_oid_dump ("Trap", oid
, oid_len
);
1037 zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ
, (u_long
)oid_len
);
1040 ret
= smux_get (oid
, &oid_len
, 1, &val_type
, &val
, &val_len
);
1043 zlog_debug ("smux_get result %d", ret
);
1046 ptr
= snmp_build_var_op (ptr
, oid
, &oid_len
,
1047 val_type
, val_len
, val
, &len
);
1050 /* Now variable size is known, fill in size */
1051 asn_build_sequence(h1
, &length
,
1052 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1055 /* Fill in size of whole sequence */
1057 asn_build_header (buf
, &len
, (u_char
) SMUX_TRAP
, (ptr
- buf
) - 2);
1059 return send (smux_sock
, buf
, (ptr
- buf
), 0);
1063 smux_register (int sock
)
1071 struct subtree
*subtree
;
1072 struct listnode
*node
, *nnode
;
1076 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
1081 /* SMUX RReq Header. */
1082 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_RREQ
, 0);
1084 /* Register MIB tree. */
1085 ptr
= asn_build_objid (ptr
, &len
,
1087 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1088 subtree
->name
, subtree
->name_len
);
1092 ptr
= asn_build_int (ptr
, &len
,
1093 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1094 &priority
, sizeof (priority
));
1097 operation
= 2; /* Register R/W */
1098 ptr
= asn_build_int (ptr
, &len
,
1099 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1100 &operation
, sizeof (operation
));
1104 smux_oid_dump ("SMUX register oid", subtree
->name
, subtree
->name_len
);
1105 zlog_debug ("SMUX register priority: %ld", priority
);
1106 zlog_debug ("SMUX register operation: %ld", operation
);
1110 asn_build_header (buf
, &len
, (u_char
) SMUX_RREQ
, (ptr
- buf
) - 2);
1111 ret
= send (sock
, buf
, (ptr
- buf
), 0);
1118 /* Try to connect to SNMP agent. */
1120 smux_connect (struct thread
*t
)
1125 zlog_debug ("SMUX connect try %d", fail
+ 1);
1127 /* Clear thread poner of myself. */
1128 smux_connect_thread
= NULL
;
1130 /* Make socket. Try to connect. */
1131 smux_sock
= smux_socket ();
1134 if (++fail
< SMUX_MAX_FAILURE
)
1135 smux_event (SMUX_CONNECT
, 0);
1139 /* Send OPEN PDU. */
1140 ret
= smux_open (smux_sock
);
1143 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno
));
1146 if (++fail
< SMUX_MAX_FAILURE
)
1147 smux_event (SMUX_CONNECT
, 0);
1151 /* Send any outstanding register PDUs. */
1152 ret
= smux_register (smux_sock
);
1155 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno
));
1158 if (++fail
< SMUX_MAX_FAILURE
)
1159 smux_event (SMUX_CONNECT
, 0);
1163 /* Everything goes fine. */
1164 smux_event (SMUX_READ
, smux_sock
);
1169 /* Clear all SMUX related resources. */
1173 if (smux_read_thread
)
1175 thread_cancel (smux_read_thread
);
1176 smux_read_thread
= NULL
;
1179 if (smux_connect_thread
)
1181 thread_cancel (smux_connect_thread
);
1182 smux_connect_thread
= NULL
;
1195 smux_event (enum smux_event event
, int sock
)
1200 smux_connect_thread
= thread_add_event (smux_master
, smux_connect
, NULL
, 0);
1203 smux_connect_thread
= thread_add_timer (smux_master
, smux_connect
, NULL
, 10);
1206 smux_read_thread
= thread_add_read (smux_master
, smux_read
, NULL
, sock
);
1214 smux_str2oid (const char *str
, oid
*oid
, size_t *oid_len
)
1230 if (! isdigit (*str
))
1233 while (isdigit (*str
))
1236 val
+= (*str
- '0');
1257 smux_oid_dup (oid
*objid
, size_t objid_len
)
1261 new = XMALLOC (MTYPE_TMP
, sizeof (oid
) * objid_len
);
1262 oid_copy (new, objid
, objid_len
);
1268 smux_peer_oid (struct vty
*vty
, const char *oid_str
, const char *passwd_str
)
1271 oid oid
[MAX_OID_LEN
];
1274 ret
= smux_str2oid (oid_str
, oid
, &oid_len
);
1277 vty_out (vty
, "object ID malformed%s", VTY_NEWLINE
);
1287 /* careful, smux_passwd might point to string constant */
1294 smux_oid
= smux_oid_dup (oid
, oid_len
);
1295 smux_oid_len
= oid_len
;
1298 smux_passwd
= strdup (passwd_str
);
1300 smux_passwd
= strdup ("");
1306 smux_peer_default (void)
1314 /* careful, smux_passwd might be pointing at string constant */
1327 "SNMP MUX protocol settings\n"
1328 "SNMP MUX peer settings\n"
1329 "Object ID used in SMUX peering\n")
1332 if (smux_peer_oid (vty
, argv
[idx_oid
]->arg
, NULL
) == 0)
1341 DEFUN (smux_peer_password
,
1342 smux_peer_password_cmd
,
1343 "smux peer OID PASSWORD",
1344 "SNMP MUX protocol settings\n"
1345 "SNMP MUX peer settings\n"
1346 "SMUX peering object ID\n"
1347 "SMUX peering password\n")
1350 if (smux_peer_oid (vty
, argv
[idx_oid
]->arg
, argv
[3]->rg
) == 0)
1359 DEFUN (no_smux_peer
,
1361 "no smux peer [OID [PASSWORD]]",
1363 "SNMP MUX protocol settings\n"
1364 "SNMP MUX peer settings\n"
1365 "SMUX peering object ID\n"
1366 "SMUX peering password\n")
1369 return smux_peer_default ();
1373 config_write_smux (struct vty
*vty
)
1380 vty_out (vty
, "smux peer ");
1381 for (i
= 0; i
< smux_oid_len
; i
++)
1383 vty_out (vty
, "%s%d", first
? "" : ".", (int) smux_oid
[i
]);
1386 vty_out (vty
, " %s%s", smux_passwd
, VTY_NEWLINE
);
1391 /* Register subtree to smux master tree. */
1393 smux_register_mib (const char *descr
, struct variable
*var
,
1394 size_t width
, int num
,
1395 oid name
[], size_t namelen
)
1397 struct subtree
*tree
;
1399 tree
= (struct subtree
*)malloc(sizeof(struct subtree
));
1400 oid_copy (tree
->name
, name
, namelen
);
1401 tree
->name_len
= namelen
;
1402 tree
->variables
= var
;
1403 tree
->variables_num
= num
;
1404 tree
->variables_width
= width
;
1405 tree
->registered
= 0;
1406 listnode_add_sort(treelist
, tree
);
1409 /* Compare function to keep treelist sorted */
1411 smux_tree_cmp(struct subtree
*tree1
, struct subtree
*tree2
)
1413 return oid_compare(tree1
->name
, tree1
->name_len
,
1414 tree2
->name
, tree2
->name_len
);
1417 /* Initialize some values then schedule first SMUX connection. */
1419 smux_init (struct thread_master
*tm
)
1422 /* copy callers thread master */
1425 /* Make MIB tree. */
1426 treelist
= list_new();
1427 treelist
->cmp
= (int (*)(void *, void *))smux_tree_cmp
;
1429 /* Install commands. */
1430 install_node (&smux_node
, config_write_smux
);
1432 install_element (CONFIG_NODE
, &smux_peer_cmd
);
1433 install_element (CONFIG_NODE
, &smux_peer_password_cmd
);
1434 install_element (CONFIG_NODE
, &no_smux_peer_cmd
);
1435 install_element (CONFIG_NODE
, &no_smux_peer_oid_cmd
);
1436 install_element (CONFIG_NODE
, &no_smux_peer_oid_password_cmd
);
1442 /* Close any existing connections. */
1445 /* Schedule first connection. */
1446 smux_event (SMUX_SCHEDULE
, 0);
1448 #endif /* HAVE_SNMP */