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
59 oid name
[MAX_OID_LEN
];
62 /* List of the variables. */
63 struct variable
*variables
;
65 /* Length of the variables list. */
68 /* Width of the variables list. */
71 /* Registered flag. */
75 #define min(A,B) ((A) < (B) ? (A) : (B))
77 enum smux_event
{SMUX_SCHEDULE
, SMUX_CONNECT
, SMUX_READ
};
79 void smux_event (enum smux_event
, int);
85 /* SMUX subtree list. */
86 struct list
*treelist
;
93 char *smux_passwd
= NULL
;
95 /* SMUX read threads. */
96 struct thread
*smux_read_thread
;
98 /* SMUX connect thrads. */
99 struct thread
*smux_connect_thread
;
101 /* SMUX debug flag. */
104 /* SMUX failure count. */
108 static struct cmd_node smux_node
=
111 "" /* SMUX has no interface. */
115 static struct thread_master
*smux_master
;
118 oid_compare_part (oid
*o1
, int o1_len
, oid
*o2
, int o2_len
)
122 for (i
= 0; i
< min (o1_len
, o2_len
); i
++)
126 else if (o1
[i
] > o2
[i
])
136 smux_oid_dump (const char *prefix
, const oid
*oid
, size_t oid_len
)
140 char buf
[MAX_OID_LEN
* 3];
144 for (i
= 0; i
< oid_len
; i
++)
146 sprintf (buf
+ strlen (buf
), "%s%d", first
? "" : ".", (int) oid
[i
]);
149 zlog_debug ("%s: %s", prefix
, buf
);
156 struct addrinfo hints
, *res0
, *res
;
160 memset(&hints
, 0, sizeof(hints
));
161 hints
.ai_family
= PF_UNSPEC
;
162 hints
.ai_socktype
= SOCK_STREAM
;
163 gai
= getaddrinfo(NULL
, "smux", &hints
, &res0
);
164 if (gai
== EAI_SERVICE
)
166 char servbuf
[NI_MAXSERV
];
167 sprintf(servbuf
,"%d",SMUX_PORT_DEFAULT
);
168 servbuf
[sizeof (servbuf
) - 1] = '\0';
169 gai
= getaddrinfo(NULL
, servbuf
, &hints
, &res0
);
173 zlog_warn("Cannot locate loopback service smux");
176 for(res
=res0
; res
; res
=res
->ai_next
)
178 if (res
->ai_family
!= AF_INET
179 && res
->ai_family
!= AF_INET6
183 sock
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
186 sockopt_reuseaddr (sock
);
187 sockopt_reuseport (sock
);
188 ret
= connect (sock
, res
->ai_addr
, res
->ai_addrlen
);
199 zlog_warn ("Can't connect to SNMP agent with SMUX");
204 smux_getresp_send (oid objid
[], size_t objid_len
, long reqid
, long errstat
,
205 long errindex
, u_char val_type
, void *arg
, size_t arg_len
)
208 u_char
*ptr
, *h1
, *h1e
, *h2
, *h2e
;
217 zlog_debug ("SMUX GETRSP send");
218 zlog_debug ("SMUX GETRSP reqid: %ld", reqid
);
222 /* Place holder h1 for complete sequence */
223 ptr
= asn_build_sequence (ptr
, &len
, (u_char
) SMUX_GETRSP
, 0);
226 ptr
= asn_build_int (ptr
, &len
,
227 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
228 &reqid
, sizeof (reqid
));
231 zlog_debug ("SMUX GETRSP errstat: %ld", errstat
);
233 ptr
= asn_build_int (ptr
, &len
,
234 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
235 &errstat
, sizeof (errstat
));
237 zlog_debug ("SMUX GETRSP errindex: %ld", errindex
);
239 ptr
= asn_build_int (ptr
, &len
,
240 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
241 &errindex
, sizeof (errindex
));
244 /* Place holder h2 for one variable */
245 ptr
= asn_build_sequence (ptr
, &len
,
246 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
250 ptr
= snmp_build_var_op (ptr
, objid
, &objid_len
,
251 val_type
, arg_len
, arg
, &len
);
253 /* Now variable size is known, fill in size */
254 asn_build_sequence(h2
,&length
,(u_char
)(ASN_SEQUENCE
|ASN_CONSTRUCTOR
),ptr
-h2e
);
256 /* Fill in size of whole sequence */
257 asn_build_sequence(h1
,&length
,(u_char
)SMUX_GETRSP
,ptr
-h1e
);
260 zlog_debug ("SMUX getresp send: %td", (ptr
- buf
));
262 send (smux_sock
, buf
, (ptr
- buf
), 0);
266 smux_var (u_char
*ptr
, size_t len
, oid objid
[], size_t *objid_len
,
268 u_char
*var_val_type
,
277 zlog_debug ("SMUX var parse: len %zd", len
);
280 ptr
= asn_parse_header (ptr
, &len
, &type
);
284 zlog_debug ("SMUX var parse: type %d len %zd", type
, len
);
285 zlog_debug ("SMUX var parse: type must be %d",
286 (ASN_SEQUENCE
| ASN_CONSTRUCTOR
));
289 /* Parse var option. */
290 *objid_len
= MAX_OID_LEN
;
291 ptr
= snmp_parse_var_op(ptr
, objid
, objid_len
, &val_type
,
292 &val_len
, &val
, &len
);
295 *var_val_len
= val_len
;
298 *var_value
= (void*) val
;
301 *var_val_type
= val_type
;
303 /* Requested object id length is objid_len. */
305 smux_oid_dump ("Request OID", objid
, *objid_len
);
308 zlog_debug ("SMUX val_type: %d", val_type
);
310 /* Check request value type. */
315 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
317 zlog_debug ("ASN_NULL");
321 zlog_debug ("ASN_INTEGER");
327 zlog_debug ("ASN_COUNTER");
330 zlog_debug ("ASN_COUNTER64");
333 zlog_debug ("ASN_IPADDRESS");
336 zlog_debug ("ASN_OCTET_STR");
341 zlog_debug ("ASN_OPAQUE");
343 case SNMP_NOSUCHOBJECT
:
344 zlog_debug ("SNMP_NOSUCHOBJECT");
346 case SNMP_NOSUCHINSTANCE
:
347 zlog_debug ("SNMP_NOSUCHINSTANCE");
349 case SNMP_ENDOFMIBVIEW
:
350 zlog_debug ("SNMP_ENDOFMIBVIEW");
353 zlog_debug ("ASN_BIT_STR");
356 zlog_debug ("Unknown type");
362 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
363 ucd-snmp smux and as such suppose, that the peer receives in the message
364 only one variable. Fortunately, IBM seems to do the same in AIX. */
367 smux_set (oid
*reqid
, size_t *reqid_len
,
368 u_char val_type
, void *val
, size_t val_len
, int action
)
371 struct subtree
*subtree
;
377 u_char
*statP
= NULL
;
378 WriteMethod
*write_method
= NULL
;
379 struct listnode
*node
, *nnode
;
382 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
384 subresult
= oid_compare_part (reqid
, *reqid_len
,
385 subtree
->name
, subtree
->name_len
);
387 /* Subtree matched. */
390 /* Prepare suffix. */
391 suffix
= reqid
+ subtree
->name_len
;
392 suffix_len
= *reqid_len
- subtree
->name_len
;
395 /* Check variables. */
396 for (j
= 0; j
< subtree
->variables_num
; j
++)
398 v
= &subtree
->variables
[j
];
400 /* Always check suffix */
401 result
= oid_compare_part (suffix
, suffix_len
,
402 v
->name
, v
->namelen
);
404 /* This is exact match so result must be zero. */
408 zlog_debug ("SMUX function call index is %d", v
->magic
);
410 statP
= (*v
->findVar
) (v
, suffix
, &suffix_len
, 1,
411 &val_len
, &write_method
);
415 return (*write_method
)(action
, val
, val_type
, val_len
,
416 statP
, suffix
, suffix_len
);
420 return SNMP_ERR_READONLY
;
424 /* If above execution is failed or oid is small (so
425 there is no further match). */
427 return SNMP_ERR_NOSUCHNAME
;
431 return SNMP_ERR_NOSUCHNAME
;
435 smux_get (oid
*reqid
, size_t *reqid_len
, int exact
,
436 u_char
*val_type
,void **val
, size_t *val_len
)
439 struct subtree
*subtree
;
445 WriteMethod
*write_method
=NULL
;
446 struct listnode
*node
, *nnode
;
449 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
,subtree
))
451 subresult
= oid_compare_part (reqid
, *reqid_len
,
452 subtree
->name
, subtree
->name_len
);
454 /* Subtree matched. */
457 /* Prepare suffix. */
458 suffix
= reqid
+ subtree
->name_len
;
459 suffix_len
= *reqid_len
- subtree
->name_len
;
462 /* Check variables. */
463 for (j
= 0; j
< subtree
->variables_num
; j
++)
465 v
= &subtree
->variables
[j
];
467 /* Always check suffix */
468 result
= oid_compare_part (suffix
, suffix_len
,
469 v
->name
, v
->namelen
);
471 /* This is exact match so result must be zero. */
475 zlog_debug ("SMUX function call index is %d", v
->magic
);
477 *val
= (*v
->findVar
) (v
, suffix
, &suffix_len
, exact
,
478 val_len
, &write_method
);
480 /* There is no instance. */
482 return SNMP_NOSUCHINSTANCE
;
484 /* Call is suceed. */
490 /* If above execution is failed or oid is small (so
491 there is no further match). */
493 return SNMP_ERR_NOSUCHNAME
;
497 return SNMP_ERR_NOSUCHNAME
;
501 smux_getnext (oid
*reqid
, size_t *reqid_len
, int exact
,
502 u_char
*val_type
,void **val
, size_t *val_len
)
505 oid save
[MAX_OID_LEN
];
507 struct subtree
*subtree
;
513 WriteMethod
*write_method
=NULL
;
514 struct listnode
*node
, *nnode
;
517 /* Save incoming request. */
518 oid_copy (save
, reqid
, *reqid_len
);
519 savelen
= *reqid_len
;
522 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
524 subresult
= oid_compare_part (reqid
, *reqid_len
,
525 subtree
->name
, subtree
->name_len
);
527 /* If request is in the tree. The agent has to make sure we
528 only receive requests we have registered for. */
529 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
530 behave as if it manages the whole SNMP MIB tree itself. It's the
531 duty of the master agent to collect the best answer and return it
532 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
533 :-). ucd-snmp really behaves bad here as it actually might ask
534 multiple times for the same GETNEXT request as it throws away the
535 answer when it expects it in a different subtree and might come
536 back later with the very same request. --jochen */
540 /* Prepare suffix. */
541 suffix
= reqid
+ subtree
->name_len
;
542 suffix_len
= *reqid_len
- subtree
->name_len
;
545 oid_copy(reqid
, subtree
->name
, subtree
->name_len
);
546 *reqid_len
= subtree
->name_len
;
548 for (j
= 0; j
< subtree
->variables_num
; j
++)
551 v
= &subtree
->variables
[j
];
553 /* Next then check result >= 0. */
555 result
= oid_compare_part (suffix
, suffix_len
,
556 v
->name
, v
->namelen
);
561 zlog_debug ("SMUX function call index is %d", v
->magic
);
564 oid_copy(suffix
, v
->name
, v
->namelen
);
565 suffix_len
= v
->namelen
;
567 *val
= (*v
->findVar
) (v
, suffix
, &suffix_len
, exact
,
568 val_len
, &write_method
);
569 *reqid_len
= suffix_len
+ subtree
->name_len
;
579 memcpy (reqid
, save
, savelen
* sizeof(oid
));
580 *reqid_len
= savelen
;
582 return SNMP_ERR_NOSUCHNAME
;
585 /* GET message header. */
587 smux_parse_get_header (u_char
*ptr
, size_t *len
, long *reqid
)
594 ptr
= asn_parse_int (ptr
, len
, &type
, reqid
, sizeof (*reqid
));
597 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid
, (int) *len
);
600 ptr
= asn_parse_int (ptr
, len
, &type
, &errstat
, sizeof (errstat
));
603 zlog_debug ("SMUX GET errstat %ld len: %zd", errstat
, *len
);
606 ptr
= asn_parse_int (ptr
, len
, &type
, &errindex
, sizeof (errindex
));
609 zlog_debug ("SMUX GET errindex %ld len: %zd", errindex
, *len
);
615 smux_parse_set (u_char
*ptr
, size_t len
, int action
)
618 oid oid
[MAX_OID_LEN
];
626 zlog_debug ("SMUX SET(%s) message parse: len %zd",
627 (RESERVE1
== action
) ? "RESERVE1" : ((FREE
== action
) ? "FREE" : "COMMIT"),
630 /* Parse SET message header. */
631 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
633 /* Parse SET message object ID. */
634 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, &val_len
, &val_type
, &val
);
636 ret
= smux_set (oid
, &oid_len
, val_type
, val
, val_len
, action
);
638 zlog_debug ("SMUX SET ret %d", ret
);
641 if (RESERVE1
== action
)
642 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
646 smux_parse_get (u_char
*ptr
, size_t len
, int exact
)
649 oid oid
[MAX_OID_LEN
];
657 zlog_debug ("SMUX GET message parse: len %zd", len
);
659 /* Parse GET message header. */
660 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
662 /* Parse GET message object ID. We needn't the value come */
663 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, NULL
, NULL
, NULL
);
665 /* Traditional getstatptr. */
667 ret
= smux_get (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
669 ret
= smux_getnext (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
673 smux_getresp_send (oid
, oid_len
, reqid
, 0, 0, val_type
, val
, val_len
);
675 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
678 /* Parse SMUX_CLOSE message. */
680 smux_parse_close (u_char
*ptr
, int len
)
686 reason
= (reason
<< 8) | (long) *ptr
;
689 zlog_info ("SMUX_CLOSE with reason: %ld", reason
);
692 /* SMUX_RRSP message. */
694 smux_parse_rrsp (u_char
*ptr
, size_t len
)
699 ptr
= asn_parse_int (ptr
, &len
, &val
, &errstat
, sizeof (errstat
));
702 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val
, errstat
);
705 /* Parse SMUX message. */
707 smux_parse (u_char
*ptr
, size_t len
)
709 /* This buffer we'll use for SOUT message. We could allocate it with
710 malloc and save only static pointer/lenght, but IMHO static
711 buffer is a faster solusion. */
712 static u_char sout_save_buff
[SMUXMAXPKTSIZE
];
713 static int sout_save_len
= 0;
715 int len_income
= len
; /* see note below: YYY */
719 rollback
= ptr
[2]; /* important only for SMUX_SOUT */
721 process_rest
: /* see note below: YYY */
723 /* Parse SMUX message type and subsequent length. */
724 ptr
= asn_parse_header (ptr
, &len
, &type
);
727 zlog_debug ("SMUX message received type: %d rest len: %zd", type
, len
);
732 /* Open must be not send from SNMP agent. */
733 zlog_warn ("SMUX_OPEN received: resetting connection.");
737 /* SMUX_RREQ message is invalid for us. */
738 zlog_warn ("SMUX_RREQ received: resetting connection.");
742 /* SMUX_SOUT message is now valied for us. */
744 zlog_debug ("SMUX_SOUT(%s)", rollback
? "rollback" : "commit");
746 if (sout_save_len
> 0)
748 smux_parse_set (sout_save_buff
, sout_save_len
, rollback
? FREE
: COMMIT
);
752 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len
);
756 /* YYY: this strange code has to solve the "slow peer"
757 problem: When agent sends SMUX_SOUT message it doesn't
758 wait any responce and may send some next message to
759 subagent. Then the peer in 'smux_read()' will recieve
760 from socket the 'concatenated' buffer, contaning both
761 SMUX_SOUT message and the next one
762 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
763 the buffer is longer than 3 ( length of SMUX_SOUT ), we
764 must process the rest of it. This effect may be observed
765 if 'debug_smux' is set to '1' */
767 len
= len_income
- 3;
772 /* SMUX_GETRSP message is invalid for us. */
773 zlog_warn ("SMUX_GETRSP received: resetting connection.");
777 /* Close SMUX connection. */
779 zlog_debug ("SMUX_CLOSE");
780 smux_parse_close (ptr
, len
);
784 /* This is response for register message. */
786 zlog_debug ("SMUX_RRSP");
787 smux_parse_rrsp (ptr
, len
);
790 /* Exact request for object id. */
792 zlog_debug ("SMUX_GET");
793 smux_parse_get (ptr
, len
, 1);
796 /* Next request for object id. */
798 zlog_debug ("SMUX_GETNEXT");
799 smux_parse_get (ptr
, len
, 0);
802 /* SMUX_SET is supported with some limitations. */
804 zlog_debug ("SMUX_SET");
806 /* save the data for future SMUX_SOUT */
807 memcpy (sout_save_buff
, ptr
, len
);
809 smux_parse_set (ptr
, len
, RESERVE1
);
812 zlog_info ("Unknown type: %d", type
);
818 /* SMUX message read function. */
820 smux_read (struct thread
*t
)
824 u_char buf
[SMUXMAXPKTSIZE
];
828 sock
= THREAD_FD (t
);
829 smux_read_thread
= NULL
;
832 zlog_debug ("SMUX read start");
834 /* Read message from SMUX socket. */
835 len
= recv (sock
, buf
, SMUXMAXPKTSIZE
, 0);
839 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno
));
842 smux_event (SMUX_CONNECT
, 0);
848 zlog_warn ("SMUX connection closed: %d", sock
);
851 smux_event (SMUX_CONNECT
, 0);
856 zlog_debug ("SMUX read len: %d", len
);
858 /* Parse the message. */
859 ret
= smux_parse (buf
, len
);
865 smux_event (SMUX_CONNECT
, 0);
869 /* Regiser read thread. */
870 smux_event (SMUX_READ
, sock
);
882 const char progname
[] = FRR_SMUX_NAME
"-" FRR_VERSION
;
886 smux_oid_dump ("SMUX open oid", smux_oid
, smux_oid_len
);
887 zlog_debug ("SMUX open progname: %s", progname
);
888 zlog_debug ("SMUX open password: %s", smux_passwd
);
894 /* SMUX Header. As placeholder. */
895 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_OPEN
, 0);
899 ptr
= asn_build_int (ptr
, &len
,
900 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
901 &version
, sizeof (version
));
903 /* SMUX connection oid. */
904 ptr
= asn_build_objid (ptr
, &len
,
906 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
907 smux_oid
, smux_oid_len
);
909 /* SMUX connection description. */
910 ptr
= asn_build_string (ptr
, &len
,
912 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
913 (const u_char
*) progname
, strlen (progname
));
915 /* SMUX connection password. */
916 ptr
= asn_build_string (ptr
, &len
,
918 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
919 (u_char
*)smux_passwd
, strlen (smux_passwd
));
921 /* Fill in real SMUX header. We exclude ASN header size (2). */
923 asn_build_header (buf
, &len
, (u_char
) SMUX_OPEN
, (ptr
- buf
) - 2);
925 return send (sock
, buf
, (ptr
- buf
), 0);
928 /* `ename` is ignored. Instead of using the provided enterprise OID,
929 the SMUX peer is used. This keep compatibility with the previous
932 All other fields are used as they are intended. */
934 smux_trap (struct variable
*vp
, size_t vp_len
,
935 const oid
*ename
, size_t enamelen
,
936 const oid
*name
, size_t namelen
,
937 const oid
*iname
, size_t inamelen
,
938 const struct trap_object
*trapobj
, size_t trapobjlen
,
953 /* When SMUX connection is not established. */
958 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_TRAP
, 0);
960 /* Sub agent enterprise oid. */
961 ptr
= asn_build_objid (ptr
, &len
,
963 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
964 smux_oid
, smux_oid_len
);
968 ptr
= asn_build_string (ptr
, &len
,
970 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_IPADDRESS
),
971 (u_char
*)&addr
, sizeof (addr
));
973 /* Generic trap integer. */
974 val
= SNMP_TRAP_ENTERPRISESPECIFIC
;
975 ptr
= asn_build_int (ptr
, &len
,
976 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
977 (long *)&val
, sizeof (val
));
979 /* Specific trap integer. */
981 ptr
= asn_build_int (ptr
, &len
,
982 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
983 (long *)&val
, sizeof (val
));
985 /* Timeticks timestamp. */
987 ptr
= asn_build_unsigned_int (ptr
, &len
,
988 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_TIMETICKS
),
993 ptr
= asn_build_sequence (ptr
, &len
,
994 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
998 /* Iteration for each objects. */
1000 for (i
= 0; i
< trapobjlen
; i
++)
1003 oid oid
[MAX_OID_LEN
];
1010 if (trapobj
[i
].namelen
> 0)
1012 oid_copy (oid
, name
, namelen
);
1013 oid_copy (oid
+ namelen
, trapobj
[i
].name
, trapobj
[i
].namelen
);
1014 oid_copy (oid
+ namelen
+ trapobj
[i
].namelen
, iname
, inamelen
);
1015 oid_len
= namelen
+ trapobj
[i
].namelen
+ inamelen
;
1019 oid_copy (oid
, name
, namelen
);
1020 oid_copy (oid
+ namelen
, trapobj
[i
].name
, trapobj
[i
].namelen
* (-1));
1021 oid_len
= namelen
+ trapobj
[i
].namelen
* (-1) ;
1026 smux_oid_dump ("Trap", name
, namelen
);
1027 if (trapobj
[i
].namelen
< 0)
1028 smux_oid_dump ("Trap",
1029 trapobj
[i
].name
, (- 1) * (trapobj
[i
].namelen
));
1032 smux_oid_dump ("Trap", trapobj
[i
].name
, (trapobj
[i
].namelen
));
1033 smux_oid_dump ("Trap", iname
, inamelen
);
1035 smux_oid_dump ("Trap", oid
, oid_len
);
1036 zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ
, (u_long
)oid_len
);
1039 ret
= smux_get (oid
, &oid_len
, 1, &val_type
, &val
, &val_len
);
1042 zlog_debug ("smux_get result %d", ret
);
1045 ptr
= snmp_build_var_op (ptr
, oid
, &oid_len
,
1046 val_type
, val_len
, val
, &len
);
1049 /* Now variable size is known, fill in size */
1050 asn_build_sequence(h1
, &length
,
1051 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1054 /* Fill in size of whole sequence */
1056 asn_build_header (buf
, &len
, (u_char
) SMUX_TRAP
, (ptr
- buf
) - 2);
1058 return send (smux_sock
, buf
, (ptr
- buf
), 0);
1062 smux_register (int sock
)
1070 struct subtree
*subtree
;
1071 struct listnode
*node
, *nnode
;
1075 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
1080 /* SMUX RReq Header. */
1081 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_RREQ
, 0);
1083 /* Register MIB tree. */
1084 ptr
= asn_build_objid (ptr
, &len
,
1086 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1087 subtree
->name
, subtree
->name_len
);
1091 ptr
= asn_build_int (ptr
, &len
,
1092 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1093 &priority
, sizeof (priority
));
1096 operation
= 2; /* Register R/W */
1097 ptr
= asn_build_int (ptr
, &len
,
1098 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1099 &operation
, sizeof (operation
));
1103 smux_oid_dump ("SMUX register oid", subtree
->name
, subtree
->name_len
);
1104 zlog_debug ("SMUX register priority: %ld", priority
);
1105 zlog_debug ("SMUX register operation: %ld", operation
);
1109 asn_build_header (buf
, &len
, (u_char
) SMUX_RREQ
, (ptr
- buf
) - 2);
1110 ret
= send (sock
, buf
, (ptr
- buf
), 0);
1117 /* Try to connect to SNMP agent. */
1119 smux_connect (struct thread
*t
)
1124 zlog_debug ("SMUX connect try %d", fail
+ 1);
1126 /* Clear thread poner of myself. */
1127 smux_connect_thread
= NULL
;
1129 /* Make socket. Try to connect. */
1130 smux_sock
= smux_socket ();
1133 if (++fail
< SMUX_MAX_FAILURE
)
1134 smux_event (SMUX_CONNECT
, 0);
1138 /* Send OPEN PDU. */
1139 ret
= smux_open (smux_sock
);
1142 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno
));
1145 if (++fail
< SMUX_MAX_FAILURE
)
1146 smux_event (SMUX_CONNECT
, 0);
1150 /* Send any outstanding register PDUs. */
1151 ret
= smux_register (smux_sock
);
1154 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno
));
1157 if (++fail
< SMUX_MAX_FAILURE
)
1158 smux_event (SMUX_CONNECT
, 0);
1162 /* Everything goes fine. */
1163 smux_event (SMUX_READ
, smux_sock
);
1168 /* Clear all SMUX related resources. */
1172 if (smux_read_thread
)
1174 thread_cancel (smux_read_thread
);
1175 smux_read_thread
= NULL
;
1178 if (smux_connect_thread
)
1180 thread_cancel (smux_connect_thread
);
1181 smux_connect_thread
= NULL
;
1194 smux_event (enum smux_event event
, int sock
)
1199 smux_connect_thread
= NULL
;
1200 thread_add_event(smux_master
, smux_connect
, NULL
, 0,
1201 &smux_connect_thread
);
1204 smux_connect_thread
= NULL
;
1205 thread_add_timer(smux_master
, smux_connect
, NULL
, 10,
1206 &smux_connect_thread
);
1209 smux_read_thread
= NULL
;
1210 thread_add_read(smux_master
, smux_read
, NULL
, sock
, &smux_read_thread
);
1218 smux_str2oid (const char *str
, oid
*oid
, size_t *oid_len
)
1234 if (! isdigit (*str
))
1237 while (isdigit (*str
))
1240 val
+= (*str
- '0');
1261 smux_oid_dup (oid
*objid
, size_t objid_len
)
1265 new = XMALLOC (MTYPE_TMP
, sizeof (oid
) * objid_len
);
1266 oid_copy (new, objid
, objid_len
);
1272 smux_peer_oid (struct vty
*vty
, const char *oid_str
, const char *passwd_str
)
1275 oid oid
[MAX_OID_LEN
];
1278 ret
= smux_str2oid (oid_str
, oid
, &oid_len
);
1281 vty_out (vty
, "object ID malformed%s", VTY_NEWLINE
);
1291 /* careful, smux_passwd might point to string constant */
1298 smux_oid
= smux_oid_dup (oid
, oid_len
);
1299 smux_oid_len
= oid_len
;
1302 smux_passwd
= strdup (passwd_str
);
1304 smux_passwd
= strdup ("");
1310 smux_peer_default (void)
1318 /* careful, smux_passwd might be pointing at string constant */
1331 "SNMP MUX protocol settings\n"
1332 "SNMP MUX peer settings\n"
1333 "Object ID used in SMUX peering\n")
1336 if (smux_peer_oid (vty
, argv
[idx_oid
]->arg
, NULL
) == 0)
1345 DEFUN (smux_peer_password
,
1346 smux_peer_password_cmd
,
1347 "smux peer OID PASSWORD",
1348 "SNMP MUX protocol settings\n"
1349 "SNMP MUX peer settings\n"
1350 "SMUX peering object ID\n"
1351 "SMUX peering password\n")
1354 if (smux_peer_oid (vty
, argv
[idx_oid
]->arg
, argv
[3]->rg
) == 0)
1363 DEFUN (no_smux_peer
,
1365 "no smux peer [OID [PASSWORD]]",
1367 "SNMP MUX protocol settings\n"
1368 "SNMP MUX peer settings\n"
1369 "SMUX peering object ID\n"
1370 "SMUX peering password\n")
1373 return smux_peer_default ();
1377 config_write_smux (struct vty
*vty
)
1384 vty_out (vty
, "smux peer ");
1385 for (i
= 0; i
< smux_oid_len
; i
++)
1387 vty_out (vty
, "%s%d", first
? "" : ".", (int) smux_oid
[i
]);
1390 vty_out (vty
, " %s%s", smux_passwd
, VTY_NEWLINE
);
1395 /* Register subtree to smux master tree. */
1397 smux_register_mib (const char *descr
, struct variable
*var
,
1398 size_t width
, int num
,
1399 oid name
[], size_t namelen
)
1401 struct subtree
*tree
;
1403 tree
= (struct subtree
*)malloc(sizeof(struct subtree
));
1404 oid_copy (tree
->name
, name
, namelen
);
1405 tree
->name_len
= namelen
;
1406 tree
->variables
= var
;
1407 tree
->variables_num
= num
;
1408 tree
->variables_width
= width
;
1409 tree
->registered
= 0;
1410 listnode_add_sort(treelist
, tree
);
1413 /* Compare function to keep treelist sorted */
1415 smux_tree_cmp(struct subtree
*tree1
, struct subtree
*tree2
)
1417 return oid_compare(tree1
->name
, tree1
->name_len
,
1418 tree2
->name
, tree2
->name_len
);
1421 /* Initialize some values then schedule first SMUX connection. */
1423 smux_init (struct thread_master
*tm
)
1426 /* copy callers thread master */
1429 /* Make MIB tree. */
1430 treelist
= list_new();
1431 treelist
->cmp
= (int (*)(void *, void *))smux_tree_cmp
;
1433 /* Install commands. */
1434 install_node (&smux_node
, config_write_smux
);
1436 install_element (CONFIG_NODE
, &smux_peer_cmd
);
1437 install_element (CONFIG_NODE
, &smux_peer_password_cmd
);
1438 install_element (CONFIG_NODE
, &no_smux_peer_cmd
);
1439 install_element (CONFIG_NODE
, &no_smux_peer_oid_cmd
);
1440 install_element (CONFIG_NODE
, &no_smux_peer_oid_password_cmd
);
1446 /* Close any existing connections. */
1449 /* Schedule first connection. */
1450 smux_event (SMUX_SCHEDULE
, 0);
1452 #endif /* SNMP_SMUX */