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
, uint8_t val_type
,
193 void *arg
, size_t arg_len
)
196 uint8_t *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
, (uint8_t)SMUX_GETRSP
, 0);
215 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
), &reqid
,
219 zlog_debug("SMUX GETRSP errstat: %ld", errstat
);
223 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
224 &errstat
, sizeof(errstat
));
226 zlog_debug("SMUX GETRSP errindex: %ld", errindex
);
230 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
231 &errindex
, sizeof(errindex
));
234 /* Place holder h2 for one variable */
235 ptr
= asn_build_sequence(ptr
, &len
,
236 (uint8_t)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
), 0);
239 ptr
= snmp_build_var_op(ptr
, objid
, &objid_len
, val_type
, arg_len
, arg
,
242 /* Now variable size is known, fill in size */
243 asn_build_sequence(h2
, &length
,
244 (uint8_t)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
247 /* Fill in size of whole sequence */
248 asn_build_sequence(h1
, &length
, (uint8_t)SMUX_GETRSP
, ptr
- h1e
);
251 zlog_debug("SMUX getresp send: %td", (ptr
- buf
));
253 send(smux_sock
, buf
, (ptr
- buf
), 0);
256 static uint8_t *smux_var(uint8_t *ptr
, size_t len
, oid objid
[],
257 size_t *objid_len
, size_t *var_val_len
,
258 uint8_t *var_val_type
, void **var_value
)
266 zlog_debug("SMUX var parse: len %zd", len
);
269 ptr
= asn_parse_header(ptr
, &len
, &type
);
272 zlog_debug("SMUX var parse: type %d len %zd", type
, len
);
273 zlog_debug("SMUX var parse: type must be %d",
274 (ASN_SEQUENCE
| ASN_CONSTRUCTOR
));
277 /* Parse var option. */
278 *objid_len
= MAX_OID_LEN
;
279 ptr
= snmp_parse_var_op(ptr
, objid
, objid_len
, &val_type
, &val_len
,
283 *var_val_len
= val_len
;
286 *var_value
= (void *)val
;
289 *var_val_type
= val_type
;
291 /* Requested object id length is objid_len. */
293 smux_oid_dump("Request OID", objid
, *objid_len
);
296 zlog_debug("SMUX val_type: %d", val_type
);
298 /* Check request value type. */
302 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set
305 zlog_debug("ASN_NULL");
309 zlog_debug("ASN_INTEGER");
315 zlog_debug("ASN_COUNTER");
318 zlog_debug("ASN_COUNTER64");
321 zlog_debug("ASN_IPADDRESS");
324 zlog_debug("ASN_OCTET_STR");
329 zlog_debug("ASN_OPAQUE");
331 case SNMP_NOSUCHOBJECT
:
332 zlog_debug("SNMP_NOSUCHOBJECT");
334 case SNMP_NOSUCHINSTANCE
:
335 zlog_debug("SNMP_NOSUCHINSTANCE");
337 case SNMP_ENDOFMIBVIEW
:
338 zlog_debug("SNMP_ENDOFMIBVIEW");
341 zlog_debug("ASN_BIT_STR");
344 zlog_debug("Unknown type");
350 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
351 ucd-snmp smux and as such suppose, that the peer receives in the message
352 only one variable. Fortunately, IBM seems to do the same in AIX. */
354 static int smux_set(oid
*reqid
, size_t *reqid_len
, uint8_t val_type
, void *val
,
355 size_t val_len
, int action
)
358 struct subtree
*subtree
;
364 uint8_t *statP
= NULL
;
365 WriteMethod
*write_method
= NULL
;
366 struct listnode
*node
, *nnode
;
369 for (ALL_LIST_ELEMENTS(treelist
, node
, nnode
, subtree
)) {
370 subresult
= oid_compare_part(reqid
, *reqid_len
, subtree
->name
,
373 /* Subtree matched. */
374 if (subresult
== 0) {
375 /* Prepare suffix. */
376 suffix
= reqid
+ subtree
->name_len
;
377 suffix_len
= *reqid_len
- subtree
->name_len
;
380 /* Check variables. */
381 for (j
= 0; j
< subtree
->variables_num
; j
++) {
382 v
= &subtree
->variables
[j
];
384 /* Always check suffix */
385 result
= oid_compare_part(suffix
, suffix_len
,
386 v
->name
, v
->namelen
);
388 /* This is exact match so result must be zero.
393 "SMUX function call index is %d",
396 statP
= (*v
->findVar
)(
397 v
, suffix
, &suffix_len
, 1,
398 &val_len
, &write_method
);
401 return (*write_method
)(
402 action
, val
, val_type
,
403 val_len
, statP
, suffix
,
406 return SNMP_ERR_READONLY
;
410 /* If above execution is failed or oid is small
412 there is no further match). */
414 return SNMP_ERR_NOSUCHNAME
;
418 return SNMP_ERR_NOSUCHNAME
;
421 static int smux_get(oid
*reqid
, size_t *reqid_len
, int exact
, uint8_t *val_type
,
422 void **val
, size_t *val_len
)
425 struct subtree
*subtree
;
431 WriteMethod
*write_method
= NULL
;
432 struct listnode
*node
, *nnode
;
435 for (ALL_LIST_ELEMENTS(treelist
, node
, nnode
, subtree
)) {
436 subresult
= oid_compare_part(reqid
, *reqid_len
, subtree
->name
,
439 /* Subtree matched. */
440 if (subresult
== 0) {
441 /* Prepare suffix. */
442 suffix
= reqid
+ subtree
->name_len
;
443 suffix_len
= *reqid_len
- subtree
->name_len
;
446 /* Check variables. */
447 for (j
= 0; j
< subtree
->variables_num
; j
++) {
448 v
= &subtree
->variables
[j
];
450 /* Always check suffix */
451 result
= oid_compare_part(suffix
, suffix_len
,
452 v
->name
, v
->namelen
);
454 /* This is exact match so result must be zero.
459 "SMUX function call index is %d",
462 *val
= (*v
->findVar
)(
463 v
, suffix
, &suffix_len
, exact
,
464 val_len
, &write_method
);
466 /* There is no instance. */
468 return SNMP_NOSUCHINSTANCE
;
470 /* Call is suceed. */
476 /* If above execution is failed or oid is small
478 there is no further match). */
480 return SNMP_ERR_NOSUCHNAME
;
484 return SNMP_ERR_NOSUCHNAME
;
487 static int smux_getnext(oid
*reqid
, size_t *reqid_len
, int exact
,
488 uint8_t *val_type
, void **val
, size_t *val_len
)
491 oid save
[MAX_OID_LEN
];
493 struct subtree
*subtree
;
499 WriteMethod
*write_method
= NULL
;
500 struct listnode
*node
, *nnode
;
503 /* Save incoming request. */
504 oid_copy(save
, reqid
, *reqid_len
);
505 savelen
= *reqid_len
;
508 for (ALL_LIST_ELEMENTS(treelist
, node
, nnode
, subtree
)) {
509 subresult
= oid_compare_part(reqid
, *reqid_len
, subtree
->name
,
512 /* If request is in the tree. The agent has to make sure we
513 only receive requests we have registered for. */
514 /* Unfortunately, that's not true. In fact, a SMUX subagent has
516 behave as if it manages the whole SNMP MIB tree itself. It's
518 duty of the master agent to collect the best answer and
520 to the manager. See RFC 1227 chapter 3.1.6 for the glory
522 :-). ucd-snmp really behaves bad here as it actually might
524 multiple times for the same GETNEXT request as it throws away
526 answer when it expects it in a different subtree and might
528 back later with the very same request. --jochen */
530 if (subresult
<= 0) {
531 /* Prepare suffix. */
532 suffix
= reqid
+ subtree
->name_len
;
533 suffix_len
= *reqid_len
- subtree
->name_len
;
535 oid_copy(reqid
, subtree
->name
,
537 *reqid_len
= subtree
->name_len
;
539 for (j
= 0; j
< subtree
->variables_num
; j
++) {
541 v
= &subtree
->variables
[j
];
543 /* Next then check result >= 0. */
545 result
= oid_compare_part(
546 suffix
, suffix_len
, v
->name
,
552 "SMUX function call index is %d",
555 oid_copy(suffix
, v
->name
,
557 suffix_len
= v
->namelen
;
559 *val
= (*v
->findVar
)(
560 v
, suffix
, &suffix_len
, exact
,
561 val_len
, &write_method
);
563 suffix_len
+ subtree
->name_len
;
572 memcpy(reqid
, save
, savelen
* sizeof(oid
));
573 *reqid_len
= savelen
;
575 return SNMP_ERR_NOSUCHNAME
;
578 /* GET message header. */
579 static uint8_t *smux_parse_get_header(uint8_t *ptr
, size_t *len
, long *reqid
)
586 ptr
= asn_parse_int(ptr
, len
, &type
, reqid
, sizeof(*reqid
));
589 zlog_debug("SMUX GET reqid: %d len: %d", (int)*reqid
,
593 ptr
= asn_parse_int(ptr
, len
, &type
, &errstat
, sizeof(errstat
));
596 zlog_debug("SMUX GET errstat %ld len: %zd", errstat
, *len
);
599 ptr
= asn_parse_int(ptr
, len
, &type
, &errindex
, sizeof(errindex
));
602 zlog_debug("SMUX GET errindex %ld len: %zd", errindex
, *len
);
607 static void smux_parse_set(uint8_t *ptr
, size_t len
, int action
)
610 oid oid
[MAX_OID_LEN
];
618 zlog_debug("SMUX SET(%s) message parse: len %zd",
621 : ((FREE
== action
) ? "FREE" : "COMMIT"),
624 /* Parse SET message header. */
625 ptr
= smux_parse_get_header(ptr
, &len
, &reqid
);
627 /* Parse SET message object ID. */
628 ptr
= smux_var(ptr
, len
, oid
, &oid_len
, &val_len
, &val_type
, &val
);
630 ret
= smux_set(oid
, &oid_len
, val_type
, val
, val_len
, action
);
632 zlog_debug("SMUX SET ret %d", ret
);
635 if (RESERVE1
== action
)
636 smux_getresp_send(oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
,
640 static void smux_parse_get(uint8_t *ptr
, size_t len
, int exact
)
643 oid oid
[MAX_OID_LEN
];
651 zlog_debug("SMUX GET message parse: len %zd", len
);
653 /* Parse GET message header. */
654 ptr
= smux_parse_get_header(ptr
, &len
, &reqid
);
656 /* Parse GET message object ID. We needn't the value come */
657 ptr
= smux_var(ptr
, len
, oid
, &oid_len
, NULL
, NULL
, NULL
);
659 /* Traditional getstatptr. */
661 ret
= smux_get(oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
663 ret
= smux_getnext(oid
, &oid_len
, exact
, &val_type
, &val
,
668 smux_getresp_send(oid
, oid_len
, reqid
, 0, 0, val_type
, val
,
671 smux_getresp_send(oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
,
675 /* Parse SMUX_CLOSE message. */
676 static void smux_parse_close(uint8_t *ptr
, int len
)
681 reason
= (reason
<< 8) | (long)*ptr
;
684 zlog_info("SMUX_CLOSE with reason: %ld", reason
);
687 /* SMUX_RRSP message. */
688 static void smux_parse_rrsp(uint8_t *ptr
, size_t len
)
693 ptr
= asn_parse_int(ptr
, &len
, &val
, &errstat
, sizeof(errstat
));
696 zlog_debug("SMUX_RRSP value: %d errstat: %ld", val
, errstat
);
699 /* Parse SMUX message. */
700 static int smux_parse(uint8_t *ptr
, size_t len
)
702 /* This buffer we'll use for SOUT message. We could allocate it with
703 malloc and save only static pointer/lenght, but IMHO static
704 buffer is a faster solusion. */
705 static uint8_t sout_save_buff
[SMUXMAXPKTSIZE
];
706 static int sout_save_len
= 0;
708 int len_income
= len
; /* see note below: YYY */
712 rollback
= ptr
[2]; /* important only for SMUX_SOUT */
714 process_rest
: /* see note below: YYY */
716 /* Parse SMUX message type and subsequent length. */
717 ptr
= asn_parse_header(ptr
, &len
, &type
);
720 zlog_debug("SMUX message received type: %d rest len: %zd", type
,
725 /* Open must be not send from SNMP agent. */
726 zlog_warn("SMUX_OPEN received: resetting connection.");
730 /* SMUX_RREQ message is invalid for us. */
731 zlog_warn("SMUX_RREQ received: resetting connection.");
735 /* SMUX_SOUT message is now valied for us. */
737 zlog_debug("SMUX_SOUT(%s)",
738 rollback
? "rollback" : "commit");
740 if (sout_save_len
> 0) {
741 smux_parse_set(sout_save_buff
, sout_save_len
,
742 rollback
? FREE
: COMMIT
);
745 zlog_warn("SMUX_SOUT sout_save_len=%d - invalid",
748 if (len_income
> 3) {
749 /* YYY: this strange code has to solve the "slow peer"
750 problem: When agent sends SMUX_SOUT message it
752 wait any responce and may send some next message to
753 subagent. Then the peer in 'smux_read()' will recieve
754 from socket the 'concatenated' buffer, contaning both
755 SMUX_SOUT message and the next one
756 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check:
758 the buffer is longer than 3 ( length of SMUX_SOUT ),
760 must process the rest of it. This effect may be
762 if 'debug_smux' is set to '1' */
764 len
= len_income
- 3;
769 /* SMUX_GETRSP message is invalid for us. */
770 zlog_warn("SMUX_GETRSP received: resetting connection.");
774 /* Close SMUX connection. */
776 zlog_debug("SMUX_CLOSE");
777 smux_parse_close(ptr
, len
);
781 /* This is response for register message. */
783 zlog_debug("SMUX_RRSP");
784 smux_parse_rrsp(ptr
, len
);
787 /* Exact request for object id. */
789 zlog_debug("SMUX_GET");
790 smux_parse_get(ptr
, len
, 1);
793 /* Next request for object id. */
795 zlog_debug("SMUX_GETNEXT");
796 smux_parse_get(ptr
, len
, 0);
799 /* SMUX_SET is supported with some limitations. */
801 zlog_debug("SMUX_SET");
803 /* save the data for future SMUX_SOUT */
804 memcpy(sout_save_buff
, ptr
, len
);
806 smux_parse_set(ptr
, len
, RESERVE1
);
809 zlog_info("Unknown type: %d", type
);
815 /* SMUX message read function. */
816 static int smux_read(struct thread
*t
)
820 uint8_t buf
[SMUXMAXPKTSIZE
];
825 smux_read_thread
= NULL
;
828 zlog_debug("SMUX read start");
830 /* Read message from SMUX socket. */
831 len
= recv(sock
, buf
, SMUXMAXPKTSIZE
, 0);
834 zlog_warn("Can't read all SMUX packet: %s",
835 safe_strerror(errno
));
838 smux_event(SMUX_CONNECT
, 0);
843 zlog_warn("SMUX connection closed: %d", sock
);
846 smux_event(SMUX_CONNECT
, 0);
851 zlog_debug("SMUX read len: %d", len
);
853 /* Parse the message. */
854 ret
= smux_parse(buf
, len
);
859 smux_event(SMUX_CONNECT
, 0);
863 /* Regiser read thread. */
864 smux_event(SMUX_READ
, sock
);
869 static int smux_open(int sock
)
875 const char progname
[] = FRR_SMUX_NAME
"-" FRR_VERSION
;
878 smux_oid_dump("SMUX open oid", smux_oid
, smux_oid_len
);
879 zlog_debug("SMUX open progname: %s", progname
);
880 zlog_debug("SMUX open password: %s", smux_passwd
);
886 /* SMUX Header. As placeholder. */
887 ptr
= asn_build_header(ptr
, &len
, (uint8_t)SMUX_OPEN
, 0);
893 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
894 &version
, sizeof(version
));
896 /* SMUX connection oid. */
897 ptr
= asn_build_objid(
899 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
900 smux_oid
, smux_oid_len
);
902 /* SMUX connection description. */
903 ptr
= asn_build_string(
905 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
906 (const uint8_t *)progname
, strlen(progname
));
908 /* SMUX connection password. */
909 ptr
= asn_build_string(
911 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
912 (uint8_t *)smux_passwd
, strlen(smux_passwd
));
914 /* Fill in real SMUX header. We exclude ASN header size (2). */
916 asn_build_header(buf
, &len
, (uint8_t)SMUX_OPEN
, (ptr
- buf
) - 2);
918 return send(sock
, buf
, (ptr
- buf
), 0);
921 /* `ename` is ignored. Instead of using the provided enterprise OID,
922 the SMUX peer is used. This keep compatibility with the previous
925 All other fields are used as they are intended. */
926 int smux_trap(struct variable
*vp
, size_t vp_len
, const oid
*ename
,
927 size_t enamelen
, const oid
*name
, size_t namelen
,
928 const oid
*iname
, size_t inamelen
,
929 const struct trap_object
*trapobj
, size_t trapobjlen
,
944 /* When SMUX connection is not established. */
949 ptr
= asn_build_header(ptr
, &len
, (uint8_t)SMUX_TRAP
, 0);
951 /* Sub agent enterprise oid. */
952 ptr
= asn_build_objid(
954 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
955 smux_oid
, smux_oid_len
);
959 ptr
= asn_build_string(
961 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_IPADDRESS
),
962 (uint8_t *)&addr
, sizeof(addr
));
964 /* Generic trap integer. */
965 val
= SNMP_TRAP_ENTERPRISESPECIFIC
;
968 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
969 (long *)&val
, sizeof(val
));
971 /* Specific trap integer. */
975 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
976 (long *)&val
, sizeof(val
));
978 /* Timeticks timestamp. */
980 ptr
= asn_build_unsigned_int(
982 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_TIMETICKS
), &val
,
987 ptr
= asn_build_sequence(ptr
, &len
,
988 (uint8_t)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
), 0);
991 /* Iteration for each objects. */
993 for (i
= 0; i
< trapobjlen
; i
++) {
995 oid oid
[MAX_OID_LEN
];
1002 if (trapobj
[i
].namelen
> 0) {
1003 oid_copy(oid
, name
, namelen
);
1004 oid_copy(oid
+ namelen
, trapobj
[i
].name
,
1005 trapobj
[i
].namelen
);
1006 oid_copy(oid
+ namelen
+ trapobj
[i
].namelen
, iname
,
1008 oid_len
= namelen
+ trapobj
[i
].namelen
+ inamelen
;
1010 oid_copy(oid
, name
, namelen
);
1011 oid_copy(oid
+ namelen
, trapobj
[i
].name
,
1012 trapobj
[i
].namelen
* (-1));
1013 oid_len
= namelen
+ trapobj
[i
].namelen
* (-1);
1017 smux_oid_dump("Trap", name
, namelen
);
1018 if (trapobj
[i
].namelen
< 0)
1019 smux_oid_dump("Trap", trapobj
[i
].name
,
1020 (-1) * (trapobj
[i
].namelen
));
1022 smux_oid_dump("Trap", trapobj
[i
].name
,
1023 (trapobj
[i
].namelen
));
1024 smux_oid_dump("Trap", iname
, inamelen
);
1026 smux_oid_dump("Trap", oid
, oid_len
);
1027 zlog_info("BUFSIZ: %d // oid_len: %lu", BUFSIZ
,
1028 (unsigned long)oid_len
);
1031 ret
= smux_get(oid
, &oid_len
, 1, &val_type
, &val
, &val_len
);
1034 zlog_debug("smux_get result %d", ret
);
1037 ptr
= snmp_build_var_op(ptr
, oid
, &oid_len
, val_type
,
1038 val_len
, val
, &len
);
1041 /* Now variable size is known, fill in size */
1042 asn_build_sequence(h1
, &length
,
1043 (uint8_t)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1046 /* Fill in size of whole sequence */
1048 asn_build_header(buf
, &len
, (uint8_t)SMUX_TRAP
, (ptr
- buf
) - 2);
1050 return send(smux_sock
, buf
, (ptr
- buf
), 0);
1053 static int smux_register(int sock
)
1055 uint8_t buf
[BUFSIZ
];
1061 struct subtree
*subtree
;
1062 struct listnode
*node
, *nnode
;
1066 for (ALL_LIST_ELEMENTS(treelist
, node
, nnode
, subtree
)) {
1070 /* SMUX RReq Header. */
1071 ptr
= asn_build_header(ptr
, &len
, (uint8_t)SMUX_RREQ
, 0);
1073 /* Register MIB tree. */
1074 ptr
= asn_build_objid(ptr
, &len
,
1075 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
1077 subtree
->name
, subtree
->name_len
);
1081 ptr
= asn_build_int(
1083 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1084 &priority
, sizeof(priority
));
1087 operation
= 2; /* Register R/W */
1088 ptr
= asn_build_int(
1090 (uint8_t)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1091 &operation
, sizeof(operation
));
1094 smux_oid_dump("SMUX register oid", subtree
->name
,
1096 zlog_debug("SMUX register priority: %ld", priority
);
1097 zlog_debug("SMUX register operation: %ld", operation
);
1101 asn_build_header(buf
, &len
, (uint8_t)SMUX_RREQ
,
1103 ret
= send(sock
, buf
, (ptr
- buf
), 0);
1110 /* Try to connect to SNMP agent. */
1111 static int smux_connect(struct thread
*t
)
1116 zlog_debug("SMUX connect try %d", fail
+ 1);
1118 /* Clear thread poner of myself. */
1119 smux_connect_thread
= NULL
;
1121 /* Make socket. Try to connect. */
1122 smux_sock
= smux_socket();
1123 if (smux_sock
< 0) {
1124 if (++fail
< SMUX_MAX_FAILURE
)
1125 smux_event(SMUX_CONNECT
, 0);
1129 /* Send OPEN PDU. */
1130 ret
= smux_open(smux_sock
);
1132 zlog_warn("SMUX open message send failed: %s",
1133 safe_strerror(errno
));
1136 if (++fail
< SMUX_MAX_FAILURE
)
1137 smux_event(SMUX_CONNECT
, 0);
1141 /* Send any outstanding register PDUs. */
1142 ret
= smux_register(smux_sock
);
1144 zlog_warn("SMUX register message send failed: %s",
1145 safe_strerror(errno
));
1148 if (++fail
< SMUX_MAX_FAILURE
)
1149 smux_event(SMUX_CONNECT
, 0);
1153 /* Everything goes fine. */
1154 smux_event(SMUX_READ
, smux_sock
);
1159 /* Clear all SMUX related resources. */
1160 static void smux_stop(void)
1162 if (smux_read_thread
) {
1163 thread_cancel(smux_read_thread
);
1164 smux_read_thread
= NULL
;
1167 if (smux_connect_thread
) {
1168 thread_cancel(smux_connect_thread
);
1169 smux_connect_thread
= NULL
;
1172 if (smux_sock
>= 0) {
1179 void smux_event(enum smux_event event
, int sock
)
1183 smux_connect_thread
= NULL
;
1184 thread_add_event(smux_master
, smux_connect
, NULL
, 0,
1185 &smux_connect_thread
);
1188 smux_connect_thread
= NULL
;
1189 thread_add_timer(smux_master
, smux_connect
, NULL
, 10,
1190 &smux_connect_thread
);
1193 smux_read_thread
= NULL
;
1194 thread_add_read(smux_master
, smux_read
, NULL
, sock
,
1202 static int smux_str2oid(const char *str
, oid
*oid
, size_t *oid_len
)
1220 while (isdigit(*str
)) {
1222 val
+= (*str
- '0');
1242 static oid
*smux_oid_dup(oid
*objid
, size_t objid_len
)
1246 new = XMALLOC(MTYPE_TMP
, sizeof(oid
) * objid_len
);
1247 oid_copy(new, objid
, objid_len
);
1252 static int smux_peer_oid(struct vty
*vty
, const char *oid_str
,
1253 const char *passwd_str
)
1256 oid oid
[MAX_OID_LEN
];
1259 ret
= smux_str2oid(oid_str
, oid
, &oid_len
);
1261 vty_out(vty
, "object ID malformed\n");
1262 return CMD_WARNING_CONFIG_FAILED
;
1270 /* careful, smux_passwd might point to string constant */
1276 smux_oid
= smux_oid_dup(oid
, oid_len
);
1277 smux_oid_len
= oid_len
;
1280 smux_passwd
= strdup(passwd_str
);
1282 smux_passwd
= strdup("");
1287 static int smux_peer_default(void)
1294 /* careful, smux_passwd might be pointing at string constant */
1306 "SNMP MUX protocol settings\n"
1307 "SNMP MUX peer settings\n"
1308 "Object ID used in SMUX peering\n")
1311 if (smux_peer_oid(vty
, argv
[idx_oid
]->arg
, NULL
) == 0) {
1315 return CMD_WARNING_CONFIG_FAILED
;
1318 DEFUN (smux_peer_password
,
1319 smux_peer_password_cmd
,
1320 "smux peer OID PASSWORD",
1321 "SNMP MUX protocol settings\n"
1322 "SNMP MUX peer settings\n"
1323 "SMUX peering object ID\n"
1324 "SMUX peering password\n")
1327 if (smux_peer_oid(vty
, argv
[idx_oid
]->arg
, argv
[3]->rg
) == 0) {
1331 return CMD_WARNING_CONFIG_FAILED
;
1334 DEFUN (no_smux_peer
,
1336 "no smux peer [OID [PASSWORD]]",
1338 "SNMP MUX protocol settings\n"
1339 "SNMP MUX peer settings\n"
1340 "SMUX peering object ID\n"
1341 "SMUX peering password\n")
1344 return smux_peer_default();
1347 static int config_write_smux(struct vty
*vty
)
1353 vty_out(vty
, "smux peer ");
1354 for (i
= 0; i
< smux_oid_len
; i
++) {
1355 vty_out(vty
, "%s%d", first
? "" : ".",
1359 vty_out(vty
, " %s\n", smux_passwd
);
1364 /* Register subtree to smux master tree. */
1365 void smux_register_mib(const char *descr
, struct variable
*var
, size_t width
,
1366 int num
, oid name
[], size_t namelen
)
1368 struct subtree
*tree
;
1370 tree
= (struct subtree
*)malloc(sizeof(struct subtree
));
1371 oid_copy(tree
->name
, name
, namelen
);
1372 tree
->name_len
= namelen
;
1373 tree
->variables
= var
;
1374 tree
->variables_num
= num
;
1375 tree
->variables_width
= width
;
1376 tree
->registered
= 0;
1377 listnode_add_sort(treelist
, tree
);
1380 /* Compare function to keep treelist sorted */
1381 static int smux_tree_cmp(struct subtree
*tree1
, struct subtree
*tree2
)
1383 return oid_compare(tree1
->name
, tree1
->name_len
, tree2
->name
,
1387 /* Initialize some values then schedule first SMUX connection. */
1388 void smux_init(struct thread_master
*tm
)
1391 /* copy callers thread master */
1394 /* Make MIB tree. */
1395 treelist
= list_new();
1396 treelist
->cmp
= (int (*)(void *, void *))smux_tree_cmp
;
1398 /* Install commands. */
1399 install_node(&smux_node
, config_write_smux
);
1401 install_element(CONFIG_NODE
, &smux_peer_cmd
);
1402 install_element(CONFIG_NODE
, &smux_peer_password_cmd
);
1403 install_element(CONFIG_NODE
, &no_smux_peer_cmd
);
1404 install_element(CONFIG_NODE
, &no_smux_peer_oid_cmd
);
1405 install_element(CONFIG_NODE
, &no_smux_peer_oid_password_cmd
);
1408 void smux_start(void)
1410 /* Close any existing connections. */
1413 /* Schedule first connection. */
1414 smux_event(SMUX_SCHEDULE
, 0);
1416 #endif /* SNMP_SMUX */