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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include <net-snmp/net-snmp-config.h>
25 #include <net-snmp/net-snmp-includes.h>
31 #include <lib/version.h>
33 #include "sockunion.h"
36 #define SMUX_PORT_DEFAULT 199
38 #define SMUXMAXPKTSIZE 1500
39 #define SMUXMAXSTRLEN 256
41 #define SMUX_OPEN (ASN_APPLICATION | ASN_CONSTRUCTOR | 0)
42 #define SMUX_CLOSE (ASN_APPLICATION | ASN_PRIMITIVE | 1)
43 #define SMUX_RREQ (ASN_APPLICATION | ASN_CONSTRUCTOR | 2)
44 #define SMUX_RRSP (ASN_APPLICATION | ASN_PRIMITIVE | 3)
45 #define SMUX_SOUT (ASN_APPLICATION | ASN_PRIMITIVE | 4)
47 #define SMUX_GET (ASN_CONTEXT | ASN_CONSTRUCTOR | 0)
48 #define SMUX_GETNEXT (ASN_CONTEXT | ASN_CONSTRUCTOR | 1)
49 #define SMUX_GETRSP (ASN_CONTEXT | ASN_CONSTRUCTOR | 2)
50 #define SMUX_SET (ASN_CONTEXT | ASN_CONSTRUCTOR | 3)
51 #define SMUX_TRAP (ASN_CONTEXT | ASN_CONSTRUCTOR | 4)
53 #define SMUX_MAX_FAILURE 3
58 oid name
[MAX_OID_LEN
];
61 /* List of the variables. */
62 struct variable
*variables
;
64 /* Length of the variables list. */
67 /* Width of the variables list. */
70 /* Registered flag. */
74 #define min(A,B) ((A) < (B) ? (A) : (B))
76 enum smux_event
{ SMUX_SCHEDULE
, SMUX_CONNECT
, SMUX_READ
};
78 void smux_event(enum smux_event
, int);
84 /* SMUX subtree list. */
85 struct list
*treelist
;
92 char *smux_passwd
= NULL
;
94 /* SMUX read threads. */
95 struct thread
*smux_read_thread
;
97 /* SMUX connect thrads. */
98 struct thread
*smux_connect_thread
;
100 /* SMUX debug flag. */
103 /* SMUX failure count. */
107 static struct cmd_node smux_node
= {
108 SMUX_NODE
, "" /* SMUX has no interface. */
112 static struct thread_master
*smux_master
;
114 static int oid_compare_part(oid
*o1
, int o1_len
, oid
*o2
, int o2_len
)
118 for (i
= 0; i
< min(o1_len
, o2_len
); i
++) {
121 else if (o1
[i
] > o2
[i
])
130 static void smux_oid_dump(const char *prefix
, const oid
*oid
, size_t oid_len
)
134 char buf
[MAX_OID_LEN
* 3];
138 for (i
= 0; i
< oid_len
; i
++) {
139 sprintf(buf
+ strlen(buf
), "%s%d", first
? "" : ".",
143 zlog_debug("%s: %s", prefix
, buf
);
146 static int smux_socket(void)
149 struct addrinfo hints
, *res0
, *res
;
153 memset(&hints
, 0, sizeof(hints
));
154 hints
.ai_family
= PF_UNSPEC
;
155 hints
.ai_socktype
= SOCK_STREAM
;
156 gai
= getaddrinfo(NULL
, "smux", &hints
, &res0
);
157 if (gai
== EAI_SERVICE
) {
158 char servbuf
[NI_MAXSERV
];
159 sprintf(servbuf
, "%d", SMUX_PORT_DEFAULT
);
160 servbuf
[sizeof(servbuf
) - 1] = '\0';
161 gai
= getaddrinfo(NULL
, servbuf
, &hints
, &res0
);
164 zlog_warn("Cannot locate loopback service smux");
167 for (res
= res0
; res
; res
= res
->ai_next
) {
168 if (res
->ai_family
!= AF_INET
&& res
->ai_family
!= AF_INET6
)
171 sock
= socket(res
->ai_family
, res
->ai_socktype
,
175 sockopt_reuseaddr(sock
);
176 sockopt_reuseport(sock
);
177 ret
= connect(sock
, res
->ai_addr
, res
->ai_addrlen
);
187 zlog_warn("Can't connect to SNMP agent with SMUX");
191 static void smux_getresp_send(oid objid
[], size_t objid_len
, long reqid
,
192 long errstat
, long errindex
, u_char val_type
,
193 void *arg
, size_t arg_len
)
196 u_char
*ptr
, *h1
, *h1e
, *h2
, *h2e
;
204 zlog_debug("SMUX GETRSP send");
205 zlog_debug("SMUX GETRSP reqid: %ld", reqid
);
209 /* Place holder h1 for complete sequence */
210 ptr
= asn_build_sequence(ptr
, &len
, (u_char
)SMUX_GETRSP
, 0);
213 ptr
= asn_build_int(ptr
, &len
, (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
215 &reqid
, sizeof(reqid
));
218 zlog_debug("SMUX GETRSP errstat: %ld", errstat
);
220 ptr
= asn_build_int(ptr
, &len
, (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
222 &errstat
, sizeof(errstat
));
224 zlog_debug("SMUX GETRSP errindex: %ld", errindex
);
226 ptr
= asn_build_int(ptr
, &len
, (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
228 &errindex
, sizeof(errindex
));
231 /* Place holder h2 for one variable */
232 ptr
= asn_build_sequence(ptr
, &len
,
233 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
), 0);
236 ptr
= snmp_build_var_op(ptr
, objid
, &objid_len
, val_type
, arg_len
, arg
,
239 /* Now variable size is known, fill in size */
240 asn_build_sequence(h2
, &length
,
241 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
), ptr
- h2e
);
243 /* Fill in size of whole sequence */
244 asn_build_sequence(h1
, &length
, (u_char
)SMUX_GETRSP
, ptr
- h1e
);
247 zlog_debug("SMUX getresp send: %td", (ptr
- buf
));
249 send(smux_sock
, buf
, (ptr
- buf
), 0);
252 static u_char
*smux_var(u_char
*ptr
, size_t len
, oid objid
[], size_t *objid_len
,
253 size_t *var_val_len
, u_char
*var_val_type
,
262 zlog_debug("SMUX var parse: len %zd", len
);
265 ptr
= asn_parse_header(ptr
, &len
, &type
);
268 zlog_debug("SMUX var parse: type %d len %zd", type
, len
);
269 zlog_debug("SMUX var parse: type must be %d",
270 (ASN_SEQUENCE
| ASN_CONSTRUCTOR
));
273 /* Parse var option. */
274 *objid_len
= MAX_OID_LEN
;
275 ptr
= snmp_parse_var_op(ptr
, objid
, objid_len
, &val_type
, &val_len
,
279 *var_val_len
= val_len
;
282 *var_value
= (void *)val
;
285 *var_val_type
= val_type
;
287 /* Requested object id length is objid_len. */
289 smux_oid_dump("Request OID", objid
, *objid_len
);
292 zlog_debug("SMUX val_type: %d", val_type
);
294 /* Check request value type. */
298 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set
301 zlog_debug("ASN_NULL");
305 zlog_debug("ASN_INTEGER");
311 zlog_debug("ASN_COUNTER");
314 zlog_debug("ASN_COUNTER64");
317 zlog_debug("ASN_IPADDRESS");
320 zlog_debug("ASN_OCTET_STR");
325 zlog_debug("ASN_OPAQUE");
327 case SNMP_NOSUCHOBJECT
:
328 zlog_debug("SNMP_NOSUCHOBJECT");
330 case SNMP_NOSUCHINSTANCE
:
331 zlog_debug("SNMP_NOSUCHINSTANCE");
333 case SNMP_ENDOFMIBVIEW
:
334 zlog_debug("SNMP_ENDOFMIBVIEW");
337 zlog_debug("ASN_BIT_STR");
340 zlog_debug("Unknown type");
346 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
347 ucd-snmp smux and as such suppose, that the peer receives in the message
348 only one variable. Fortunately, IBM seems to do the same in AIX. */
350 static int smux_set(oid
*reqid
, size_t *reqid_len
, u_char val_type
, void *val
,
351 size_t val_len
, int action
)
354 struct subtree
*subtree
;
360 u_char
*statP
= NULL
;
361 WriteMethod
*write_method
= NULL
;
362 struct listnode
*node
, *nnode
;
365 for (ALL_LIST_ELEMENTS(treelist
, node
, nnode
, subtree
)) {
366 subresult
= oid_compare_part(reqid
, *reqid_len
, subtree
->name
,
369 /* Subtree matched. */
370 if (subresult
== 0) {
371 /* Prepare suffix. */
372 suffix
= reqid
+ subtree
->name_len
;
373 suffix_len
= *reqid_len
- subtree
->name_len
;
376 /* Check variables. */
377 for (j
= 0; j
< subtree
->variables_num
; j
++) {
378 v
= &subtree
->variables
[j
];
380 /* Always check suffix */
381 result
= oid_compare_part(suffix
, suffix_len
,
382 v
->name
, v
->namelen
);
384 /* This is exact match so result must be zero.
389 "SMUX function call index is %d",
392 statP
= (*v
->findVar
)(
393 v
, suffix
, &suffix_len
, 1,
394 &val_len
, &write_method
);
397 return (*write_method
)(
398 action
, val
, val_type
,
399 val_len
, statP
, suffix
,
402 return SNMP_ERR_READONLY
;
406 /* If above execution is failed or oid is small
408 there is no further match). */
410 return SNMP_ERR_NOSUCHNAME
;
414 return SNMP_ERR_NOSUCHNAME
;
417 static int smux_get(oid
*reqid
, size_t *reqid_len
, int exact
, u_char
*val_type
,
418 void **val
, size_t *val_len
)
421 struct subtree
*subtree
;
427 WriteMethod
*write_method
= NULL
;
428 struct listnode
*node
, *nnode
;
431 for (ALL_LIST_ELEMENTS(treelist
, node
, nnode
, subtree
)) {
432 subresult
= oid_compare_part(reqid
, *reqid_len
, subtree
->name
,
435 /* Subtree matched. */
436 if (subresult
== 0) {
437 /* Prepare suffix. */
438 suffix
= reqid
+ subtree
->name_len
;
439 suffix_len
= *reqid_len
- subtree
->name_len
;
442 /* Check variables. */
443 for (j
= 0; j
< subtree
->variables_num
; j
++) {
444 v
= &subtree
->variables
[j
];
446 /* Always check suffix */
447 result
= oid_compare_part(suffix
, suffix_len
,
448 v
->name
, v
->namelen
);
450 /* This is exact match so result must be zero.
455 "SMUX function call index is %d",
458 *val
= (*v
->findVar
)(
459 v
, suffix
, &suffix_len
, exact
,
460 val_len
, &write_method
);
462 /* There is no instance. */
464 return SNMP_NOSUCHINSTANCE
;
466 /* Call is suceed. */
472 /* If above execution is failed or oid is small
474 there is no further match). */
476 return SNMP_ERR_NOSUCHNAME
;
480 return SNMP_ERR_NOSUCHNAME
;
483 static int smux_getnext(oid
*reqid
, size_t *reqid_len
, int exact
,
484 u_char
*val_type
, void **val
, size_t *val_len
)
487 oid save
[MAX_OID_LEN
];
489 struct subtree
*subtree
;
495 WriteMethod
*write_method
= NULL
;
496 struct listnode
*node
, *nnode
;
499 /* Save incoming request. */
500 oid_copy(save
, reqid
, *reqid_len
);
501 savelen
= *reqid_len
;
504 for (ALL_LIST_ELEMENTS(treelist
, node
, nnode
, subtree
)) {
505 subresult
= oid_compare_part(reqid
, *reqid_len
, subtree
->name
,
508 /* If request is in the tree. The agent has to make sure we
509 only receive requests we have registered for. */
510 /* Unfortunately, that's not true. In fact, a SMUX subagent has
512 behave as if it manages the whole SNMP MIB tree itself. It's
514 duty of the master agent to collect the best answer and
516 to the manager. See RFC 1227 chapter 3.1.6 for the glory
518 :-). ucd-snmp really behaves bad here as it actually might
520 multiple times for the same GETNEXT request as it throws away
522 answer when it expects it in a different subtree and might
524 back later with the very same request. --jochen */
526 if (subresult
<= 0) {
527 /* Prepare suffix. */
528 suffix
= reqid
+ subtree
->name_len
;
529 suffix_len
= *reqid_len
- subtree
->name_len
;
531 oid_copy(reqid
, subtree
->name
,
533 *reqid_len
= subtree
->name_len
;
535 for (j
= 0; j
< subtree
->variables_num
; j
++) {
537 v
= &subtree
->variables
[j
];
539 /* Next then check result >= 0. */
541 result
= oid_compare_part(
542 suffix
, suffix_len
, v
->name
,
548 "SMUX function call index is %d",
551 oid_copy(suffix
, v
->name
,
553 suffix_len
= v
->namelen
;
555 *val
= (*v
->findVar
)(
556 v
, suffix
, &suffix_len
, exact
,
557 val_len
, &write_method
);
559 suffix_len
+ subtree
->name_len
;
568 memcpy(reqid
, save
, savelen
* sizeof(oid
));
569 *reqid_len
= savelen
;
571 return SNMP_ERR_NOSUCHNAME
;
574 /* GET message header. */
575 static u_char
*smux_parse_get_header(u_char
*ptr
, size_t *len
, long *reqid
)
582 ptr
= asn_parse_int(ptr
, len
, &type
, reqid
, sizeof(*reqid
));
585 zlog_debug("SMUX GET reqid: %d len: %d", (int)*reqid
,
589 ptr
= asn_parse_int(ptr
, len
, &type
, &errstat
, sizeof(errstat
));
592 zlog_debug("SMUX GET errstat %ld len: %zd", errstat
, *len
);
595 ptr
= asn_parse_int(ptr
, len
, &type
, &errindex
, sizeof(errindex
));
598 zlog_debug("SMUX GET errindex %ld len: %zd", errindex
, *len
);
603 static void smux_parse_set(u_char
*ptr
, size_t len
, int action
)
606 oid oid
[MAX_OID_LEN
];
614 zlog_debug("SMUX SET(%s) message parse: len %zd",
617 : ((FREE
== action
) ? "FREE" : "COMMIT"),
620 /* Parse SET message header. */
621 ptr
= smux_parse_get_header(ptr
, &len
, &reqid
);
623 /* Parse SET message object ID. */
624 ptr
= smux_var(ptr
, len
, oid
, &oid_len
, &val_len
, &val_type
, &val
);
626 ret
= smux_set(oid
, &oid_len
, val_type
, val
, val_len
, action
);
628 zlog_debug("SMUX SET ret %d", ret
);
631 if (RESERVE1
== action
)
632 smux_getresp_send(oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
,
636 static void smux_parse_get(u_char
*ptr
, size_t len
, int exact
)
639 oid oid
[MAX_OID_LEN
];
647 zlog_debug("SMUX GET message parse: len %zd", len
);
649 /* Parse GET message header. */
650 ptr
= smux_parse_get_header(ptr
, &len
, &reqid
);
652 /* Parse GET message object ID. We needn't the value come */
653 ptr
= smux_var(ptr
, len
, oid
, &oid_len
, NULL
, NULL
, NULL
);
655 /* Traditional getstatptr. */
657 ret
= smux_get(oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
659 ret
= smux_getnext(oid
, &oid_len
, exact
, &val_type
, &val
,
664 smux_getresp_send(oid
, oid_len
, reqid
, 0, 0, val_type
, val
,
667 smux_getresp_send(oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
,
671 /* Parse SMUX_CLOSE message. */
672 static void smux_parse_close(u_char
*ptr
, int len
)
677 reason
= (reason
<< 8) | (long)*ptr
;
680 zlog_info("SMUX_CLOSE with reason: %ld", reason
);
683 /* SMUX_RRSP message. */
684 static void smux_parse_rrsp(u_char
*ptr
, size_t len
)
689 ptr
= asn_parse_int(ptr
, &len
, &val
, &errstat
, sizeof(errstat
));
692 zlog_debug("SMUX_RRSP value: %d errstat: %ld", val
, errstat
);
695 /* Parse SMUX message. */
696 static int smux_parse(u_char
*ptr
, size_t len
)
698 /* This buffer we'll use for SOUT message. We could allocate it with
699 malloc and save only static pointer/lenght, but IMHO static
700 buffer is a faster solusion. */
701 static u_char sout_save_buff
[SMUXMAXPKTSIZE
];
702 static int sout_save_len
= 0;
704 int len_income
= len
; /* see note below: YYY */
708 rollback
= ptr
[2]; /* important only for SMUX_SOUT */
710 process_rest
: /* see note below: YYY */
712 /* Parse SMUX message type and subsequent length. */
713 ptr
= asn_parse_header(ptr
, &len
, &type
);
716 zlog_debug("SMUX message received type: %d rest len: %zd", type
,
721 /* Open must be not send from SNMP agent. */
722 zlog_warn("SMUX_OPEN received: resetting connection.");
726 /* SMUX_RREQ message is invalid for us. */
727 zlog_warn("SMUX_RREQ received: resetting connection.");
731 /* SMUX_SOUT message is now valied for us. */
733 zlog_debug("SMUX_SOUT(%s)",
734 rollback
? "rollback" : "commit");
736 if (sout_save_len
> 0) {
737 smux_parse_set(sout_save_buff
, sout_save_len
,
738 rollback
? FREE
: COMMIT
);
741 zlog_warn("SMUX_SOUT sout_save_len=%d - invalid",
744 if (len_income
> 3) {
745 /* YYY: this strange code has to solve the "slow peer"
746 problem: When agent sends SMUX_SOUT message it
748 wait any responce and may send some next message to
749 subagent. Then the peer in 'smux_read()' will recieve
750 from socket the 'concatenated' buffer, contaning both
751 SMUX_SOUT message and the next one
752 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check:
754 the buffer is longer than 3 ( length of SMUX_SOUT ),
756 must process the rest of it. This effect may be
758 if 'debug_smux' is set to '1' */
760 len
= len_income
- 3;
765 /* SMUX_GETRSP message is invalid for us. */
766 zlog_warn("SMUX_GETRSP received: resetting connection.");
770 /* Close SMUX connection. */
772 zlog_debug("SMUX_CLOSE");
773 smux_parse_close(ptr
, len
);
777 /* This is response for register message. */
779 zlog_debug("SMUX_RRSP");
780 smux_parse_rrsp(ptr
, len
);
783 /* Exact request for object id. */
785 zlog_debug("SMUX_GET");
786 smux_parse_get(ptr
, len
, 1);
789 /* Next request for object id. */
791 zlog_debug("SMUX_GETNEXT");
792 smux_parse_get(ptr
, len
, 0);
795 /* SMUX_SET is supported with some limitations. */
797 zlog_debug("SMUX_SET");
799 /* save the data for future SMUX_SOUT */
800 memcpy(sout_save_buff
, ptr
, len
);
802 smux_parse_set(ptr
, len
, RESERVE1
);
805 zlog_info("Unknown type: %d", type
);
811 /* SMUX message read function. */
812 static int smux_read(struct thread
*t
)
816 u_char buf
[SMUXMAXPKTSIZE
];
821 smux_read_thread
= NULL
;
824 zlog_debug("SMUX read start");
826 /* Read message from SMUX socket. */
827 len
= recv(sock
, buf
, SMUXMAXPKTSIZE
, 0);
830 zlog_warn("Can't read all SMUX packet: %s",
831 safe_strerror(errno
));
834 smux_event(SMUX_CONNECT
, 0);
839 zlog_warn("SMUX connection closed: %d", sock
);
842 smux_event(SMUX_CONNECT
, 0);
847 zlog_debug("SMUX read len: %d", len
);
849 /* Parse the message. */
850 ret
= smux_parse(buf
, len
);
855 smux_event(SMUX_CONNECT
, 0);
859 /* Regiser read thread. */
860 smux_event(SMUX_READ
, sock
);
865 static int smux_open(int sock
)
871 const char progname
[] = FRR_SMUX_NAME
"-" FRR_VERSION
;
874 smux_oid_dump("SMUX open oid", smux_oid
, smux_oid_len
);
875 zlog_debug("SMUX open progname: %s", progname
);
876 zlog_debug("SMUX open password: %s", smux_passwd
);
882 /* SMUX Header. As placeholder. */
883 ptr
= asn_build_header(ptr
, &len
, (u_char
)SMUX_OPEN
, 0);
887 ptr
= asn_build_int(ptr
, &len
, (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
889 &version
, sizeof(version
));
891 /* SMUX connection oid. */
892 ptr
= asn_build_objid(ptr
, &len
, (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
894 smux_oid
, smux_oid_len
);
896 /* SMUX connection description. */
897 ptr
= asn_build_string(ptr
, &len
, (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
899 (const u_char
*)progname
, strlen(progname
));
901 /* SMUX connection password. */
902 ptr
= asn_build_string(ptr
, &len
, (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
904 (u_char
*)smux_passwd
, strlen(smux_passwd
));
906 /* Fill in real SMUX header. We exclude ASN header size (2). */
908 asn_build_header(buf
, &len
, (u_char
)SMUX_OPEN
, (ptr
- buf
) - 2);
910 return send(sock
, buf
, (ptr
- buf
), 0);
913 /* `ename` is ignored. Instead of using the provided enterprise OID,
914 the SMUX peer is used. This keep compatibility with the previous
917 All other fields are used as they are intended. */
918 int smux_trap(struct variable
*vp
, size_t vp_len
, const oid
*ename
,
919 size_t enamelen
, const oid
*name
, size_t namelen
,
920 const oid
*iname
, size_t inamelen
,
921 const struct trap_object
*trapobj
, size_t trapobjlen
,
936 /* When SMUX connection is not established. */
941 ptr
= asn_build_header(ptr
, &len
, (u_char
)SMUX_TRAP
, 0);
943 /* Sub agent enterprise oid. */
944 ptr
= asn_build_objid(ptr
, &len
, (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
946 smux_oid
, smux_oid_len
);
950 ptr
= asn_build_string(ptr
, &len
, (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
952 (u_char
*)&addr
, sizeof(addr
));
954 /* Generic trap integer. */
955 val
= SNMP_TRAP_ENTERPRISESPECIFIC
;
956 ptr
= asn_build_int(ptr
, &len
, (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
958 (long *)&val
, sizeof(val
));
960 /* Specific trap integer. */
962 ptr
= asn_build_int(ptr
, &len
, (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
964 (long *)&val
, sizeof(val
));
966 /* Timeticks timestamp. */
968 ptr
= asn_build_unsigned_int(
970 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_TIMETICKS
), &val
,
975 ptr
= asn_build_sequence(ptr
, &len
,
976 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
), 0);
979 /* Iteration for each objects. */
981 for (i
= 0; i
< trapobjlen
; i
++) {
983 oid oid
[MAX_OID_LEN
];
990 if (trapobj
[i
].namelen
> 0) {
991 oid_copy(oid
, name
, namelen
);
992 oid_copy(oid
+ namelen
, trapobj
[i
].name
,
994 oid_copy(oid
+ namelen
+ trapobj
[i
].namelen
, iname
,
996 oid_len
= namelen
+ trapobj
[i
].namelen
+ inamelen
;
998 oid_copy(oid
, name
, namelen
);
999 oid_copy(oid
+ namelen
, trapobj
[i
].name
,
1000 trapobj
[i
].namelen
* (-1));
1001 oid_len
= namelen
+ trapobj
[i
].namelen
* (-1);
1005 smux_oid_dump("Trap", name
, namelen
);
1006 if (trapobj
[i
].namelen
< 0)
1007 smux_oid_dump("Trap", trapobj
[i
].name
,
1008 (-1) * (trapobj
[i
].namelen
));
1010 smux_oid_dump("Trap", trapobj
[i
].name
,
1011 (trapobj
[i
].namelen
));
1012 smux_oid_dump("Trap", iname
, inamelen
);
1014 smux_oid_dump("Trap", oid
, oid_len
);
1015 zlog_info("BUFSIZ: %d // oid_len: %lu", BUFSIZ
,
1019 ret
= smux_get(oid
, &oid_len
, 1, &val_type
, &val
, &val_len
);
1022 zlog_debug("smux_get result %d", ret
);
1025 ptr
= snmp_build_var_op(ptr
, oid
, &oid_len
, val_type
,
1026 val_len
, val
, &len
);
1029 /* Now variable size is known, fill in size */
1030 asn_build_sequence(h1
, &length
,
1031 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
), ptr
- h1e
);
1033 /* Fill in size of whole sequence */
1035 asn_build_header(buf
, &len
, (u_char
)SMUX_TRAP
, (ptr
- buf
) - 2);
1037 return send(smux_sock
, buf
, (ptr
- buf
), 0);
1040 static int smux_register(int sock
)
1048 struct subtree
*subtree
;
1049 struct listnode
*node
, *nnode
;
1053 for (ALL_LIST_ELEMENTS(treelist
, node
, nnode
, subtree
)) {
1057 /* SMUX RReq Header. */
1058 ptr
= asn_build_header(ptr
, &len
, (u_char
)SMUX_RREQ
, 0);
1060 /* Register MIB tree. */
1061 ptr
= asn_build_objid(
1063 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1064 subtree
->name
, subtree
->name_len
);
1068 ptr
= asn_build_int(
1070 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1071 &priority
, sizeof(priority
));
1074 operation
= 2; /* Register R/W */
1075 ptr
= asn_build_int(
1077 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1078 &operation
, sizeof(operation
));
1081 smux_oid_dump("SMUX register oid", subtree
->name
,
1083 zlog_debug("SMUX register priority: %ld", priority
);
1084 zlog_debug("SMUX register operation: %ld", operation
);
1088 asn_build_header(buf
, &len
, (u_char
)SMUX_RREQ
, (ptr
- buf
) - 2);
1089 ret
= send(sock
, buf
, (ptr
- buf
), 0);
1096 /* Try to connect to SNMP agent. */
1097 static int smux_connect(struct thread
*t
)
1102 zlog_debug("SMUX connect try %d", fail
+ 1);
1104 /* Clear thread poner of myself. */
1105 smux_connect_thread
= NULL
;
1107 /* Make socket. Try to connect. */
1108 smux_sock
= smux_socket();
1109 if (smux_sock
< 0) {
1110 if (++fail
< SMUX_MAX_FAILURE
)
1111 smux_event(SMUX_CONNECT
, 0);
1115 /* Send OPEN PDU. */
1116 ret
= smux_open(smux_sock
);
1118 zlog_warn("SMUX open message send failed: %s",
1119 safe_strerror(errno
));
1122 if (++fail
< SMUX_MAX_FAILURE
)
1123 smux_event(SMUX_CONNECT
, 0);
1127 /* Send any outstanding register PDUs. */
1128 ret
= smux_register(smux_sock
);
1130 zlog_warn("SMUX register message send failed: %s",
1131 safe_strerror(errno
));
1134 if (++fail
< SMUX_MAX_FAILURE
)
1135 smux_event(SMUX_CONNECT
, 0);
1139 /* Everything goes fine. */
1140 smux_event(SMUX_READ
, smux_sock
);
1145 /* Clear all SMUX related resources. */
1146 static void smux_stop(void)
1148 if (smux_read_thread
) {
1149 thread_cancel(smux_read_thread
);
1150 smux_read_thread
= NULL
;
1153 if (smux_connect_thread
) {
1154 thread_cancel(smux_connect_thread
);
1155 smux_connect_thread
= NULL
;
1158 if (smux_sock
>= 0) {
1165 void smux_event(enum smux_event event
, int sock
)
1169 smux_connect_thread
= NULL
;
1170 thread_add_event(smux_master
, smux_connect
, NULL
, 0,
1171 &smux_connect_thread
);
1174 smux_connect_thread
= NULL
;
1175 thread_add_timer(smux_master
, smux_connect
, NULL
, 10,
1176 &smux_connect_thread
);
1179 smux_read_thread
= NULL
;
1180 thread_add_read(smux_master
, smux_read
, NULL
, sock
,
1188 static int smux_str2oid(const char *str
, oid
*oid
, size_t *oid_len
)
1206 while (isdigit(*str
)) {
1208 val
+= (*str
- '0');
1228 static oid
*smux_oid_dup(oid
*objid
, size_t objid_len
)
1232 new = XMALLOC(MTYPE_TMP
, sizeof(oid
) * objid_len
);
1233 oid_copy(new, objid
, objid_len
);
1238 static int smux_peer_oid(struct vty
*vty
, const char *oid_str
,
1239 const char *passwd_str
)
1242 oid oid
[MAX_OID_LEN
];
1245 ret
= smux_str2oid(oid_str
, oid
, &oid_len
);
1247 vty_out(vty
, "object ID malformed\n");
1248 return CMD_WARNING_CONFIG_FAILED
;
1256 /* careful, smux_passwd might point to string constant */
1262 smux_oid
= smux_oid_dup(oid
, oid_len
);
1263 smux_oid_len
= oid_len
;
1266 smux_passwd
= strdup(passwd_str
);
1268 smux_passwd
= strdup("");
1273 static int smux_peer_default(void)
1280 /* careful, smux_passwd might be pointing at string constant */
1292 "SNMP MUX protocol settings\n"
1293 "SNMP MUX peer settings\n"
1294 "Object ID used in SMUX peering\n")
1297 if (smux_peer_oid(vty
, argv
[idx_oid
]->arg
, NULL
) == 0) {
1301 return CMD_WARNING_CONFIG_FAILED
;
1304 DEFUN (smux_peer_password
,
1305 smux_peer_password_cmd
,
1306 "smux peer OID PASSWORD",
1307 "SNMP MUX protocol settings\n"
1308 "SNMP MUX peer settings\n"
1309 "SMUX peering object ID\n"
1310 "SMUX peering password\n")
1313 if (smux_peer_oid(vty
, argv
[idx_oid
]->arg
, argv
[3]->rg
) == 0) {
1317 return CMD_WARNING_CONFIG_FAILED
;
1320 DEFUN (no_smux_peer
,
1322 "no smux peer [OID [PASSWORD]]",
1324 "SNMP MUX protocol settings\n"
1325 "SNMP MUX peer settings\n"
1326 "SMUX peering object ID\n"
1327 "SMUX peering password\n")
1330 return smux_peer_default();
1333 static int config_write_smux(struct vty
*vty
)
1339 vty_out(vty
, "smux peer ");
1340 for (i
= 0; i
< smux_oid_len
; i
++) {
1341 vty_out(vty
, "%s%d", first
? "" : ".",
1345 vty_out(vty
, " %s\n", smux_passwd
);
1350 /* Register subtree to smux master tree. */
1351 void smux_register_mib(const char *descr
, struct variable
*var
, size_t width
,
1352 int num
, oid name
[], size_t namelen
)
1354 struct subtree
*tree
;
1356 tree
= (struct subtree
*)malloc(sizeof(struct subtree
));
1357 oid_copy(tree
->name
, name
, namelen
);
1358 tree
->name_len
= namelen
;
1359 tree
->variables
= var
;
1360 tree
->variables_num
= num
;
1361 tree
->variables_width
= width
;
1362 tree
->registered
= 0;
1363 listnode_add_sort(treelist
, tree
);
1366 /* Compare function to keep treelist sorted */
1367 static int smux_tree_cmp(struct subtree
*tree1
, struct subtree
*tree2
)
1369 return oid_compare(tree1
->name
, tree1
->name_len
, tree2
->name
,
1373 /* Initialize some values then schedule first SMUX connection. */
1374 void smux_init(struct thread_master
*tm
)
1377 /* copy callers thread master */
1380 /* Make MIB tree. */
1381 treelist
= list_new();
1382 treelist
->cmp
= (int (*)(void *, void *))smux_tree_cmp
;
1384 /* Install commands. */
1385 install_node(&smux_node
, config_write_smux
);
1387 install_element(CONFIG_NODE
, &smux_peer_cmd
);
1388 install_element(CONFIG_NODE
, &smux_peer_password_cmd
);
1389 install_element(CONFIG_NODE
, &no_smux_peer_cmd
);
1390 install_element(CONFIG_NODE
, &no_smux_peer_oid_cmd
);
1391 install_element(CONFIG_NODE
, &no_smux_peer_oid_password_cmd
);
1394 void smux_start(void)
1396 /* Close any existing connections. */
1399 /* Schedule first connection. */
1400 smux_event(SMUX_SCHEDULE
, 0);
1402 #endif /* SNMP_SMUX */