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
26 #include <net-snmp/net-snmp-config.h>
30 #include <snmp_impl.h>
36 #include <lib/version.h>
38 #include "sockunion.h"
41 #define min(A,B) ((A) < (B) ? (A) : (B))
43 enum smux_event
{SMUX_SCHEDULE
, SMUX_CONNECT
, SMUX_READ
};
45 void smux_event (enum smux_event
, int);
51 /* SMUX subtree list. */
52 struct list
*treelist
;
59 char *smux_passwd
= NULL
;
61 /* SMUX read threads. */
62 struct thread
*smux_read_thread
;
64 /* SMUX connect thrads. */
65 struct thread
*smux_connect_thread
;
67 /* SMUX debug flag. */
70 /* SMUX failure count. */
74 struct cmd_node smux_node
=
77 "" /* SMUX has no interface. */
81 static struct thread_master
*master
;
84 oid_copy (void *dest
, void *src
, size_t size
)
86 return memcpy (dest
, src
, size
* sizeof (oid
));
90 oid2in_addr (oid oid
[], int len
, struct in_addr
*addr
)
98 pnt
= (u_char
*) addr
;
100 for (i
= 0; i
< len
; i
++)
105 oid_copy_addr (oid oid
[], struct in_addr
*addr
, int len
)
113 pnt
= (u_char
*) addr
;
115 for (i
= 0; i
< len
; i
++)
120 oid_compare (oid
*o1
, int o1_len
, oid
*o2
, int o2_len
)
124 for (i
= 0; i
< min (o1_len
, o2_len
); i
++)
128 else if (o1
[i
] > o2
[i
])
140 oid_compare_part (oid
*o1
, int o1_len
, oid
*o2
, int o2_len
)
144 for (i
= 0; i
< min (o1_len
, o2_len
); i
++)
148 else if (o1
[i
] > o2
[i
])
158 smux_oid_dump (const char *prefix
, oid
*oid
, size_t oid_len
)
162 char buf
[MAX_OID_LEN
* 3];
166 for (i
= 0; i
< oid_len
; i
++)
168 sprintf (buf
+ strlen (buf
), "%s%d", first
? "" : ".", (int) oid
[i
]);
171 zlog_debug ("%s: %s", prefix
, buf
);
179 struct addrinfo hints
, *res0
, *res
;
182 struct sockaddr_in serv
;
188 memset(&hints
, 0, sizeof(hints
));
189 hints
.ai_family
= PF_UNSPEC
;
190 hints
.ai_socktype
= SOCK_STREAM
;
191 gai
= getaddrinfo(NULL
, "smux", &hints
, &res0
);
192 if (gai
== EAI_SERVICE
)
194 char servbuf
[NI_MAXSERV
];
195 sprintf(servbuf
,"%d",SMUX_PORT_DEFAULT
);
196 servbuf
[sizeof (servbuf
) - 1] = '\0';
197 gai
= getaddrinfo(NULL
, servbuf
, &hints
, &res0
);
201 zlog_warn("Cannot locate loopback service smux");
204 for(res
=res0
; res
; res
=res
->ai_next
)
206 if (res
->ai_family
!= AF_INET
208 && res
->ai_family
!= AF_INET6
209 #endif /* HAVE_IPV6 */
213 sock
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
216 sockopt_reuseaddr (sock
);
217 sockopt_reuseport (sock
);
218 ret
= connect (sock
, res
->ai_addr
, res
->ai_addrlen
);
229 zlog_warn ("Can't connect to SNMP agent with SMUX");
231 sock
= socket (AF_INET
, SOCK_STREAM
, 0);
234 zlog_warn ("Can't make socket for SNMP");
238 memset (&serv
, 0, sizeof (struct sockaddr_in
));
239 serv
.sin_family
= AF_INET
;
241 serv
.sin_len
= sizeof (struct sockaddr_in
);
242 #endif /* HAVE_SIN_LEN */
244 sp
= getservbyname ("smux", "tcp");
246 serv
.sin_port
= sp
->s_port
;
248 serv
.sin_port
= htons (SMUX_PORT_DEFAULT
);
250 serv
.sin_addr
.s_addr
= htonl (INADDR_LOOPBACK
);
252 sockopt_reuseaddr (sock
);
253 sockopt_reuseport (sock
);
255 ret
= connect (sock
, (struct sockaddr
*) &serv
, sizeof (struct sockaddr_in
));
260 zlog_warn ("Can't connect to SNMP agent with SMUX");
268 smux_getresp_send (oid objid
[], size_t objid_len
, long reqid
, long errstat
,
269 long errindex
, u_char val_type
, void *arg
, size_t arg_len
)
273 u_char
*ptr
, *h1
, *h1e
, *h2
, *h2e
;
282 zlog_debug ("SMUX GETRSP send");
283 zlog_debug ("SMUX GETRSP reqid: %ld", reqid
);
287 /* Place holder h1 for complete sequence */
288 ptr
= asn_build_sequence (ptr
, &len
, (u_char
) SMUX_GETRSP
, 0);
291 ptr
= asn_build_int (ptr
, &len
,
292 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
293 &reqid
, sizeof (reqid
));
296 zlog_debug ("SMUX GETRSP errstat: %ld", errstat
);
298 ptr
= asn_build_int (ptr
, &len
,
299 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
300 &errstat
, sizeof (errstat
));
302 zlog_debug ("SMUX GETRSP errindex: %ld", errindex
);
304 ptr
= asn_build_int (ptr
, &len
,
305 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
306 &errindex
, sizeof (errindex
));
309 /* Place holder h2 for one variable */
310 ptr
= asn_build_sequence (ptr
, &len
,
311 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
315 ptr
= snmp_build_var_op (ptr
, objid
, &objid_len
,
316 val_type
, arg_len
, arg
, &len
);
318 /* Now variable size is known, fill in size */
319 asn_build_sequence(h2
,&length
,(u_char
)(ASN_SEQUENCE
|ASN_CONSTRUCTOR
),ptr
-h2e
);
321 /* Fill in size of whole sequence */
322 asn_build_sequence(h1
,&length
,(u_char
)SMUX_GETRSP
,ptr
-h1e
);
325 zlog_debug ("SMUX getresp send: %ld", (ptr
- buf
));
327 ret
= send (smux_sock
, buf
, (ptr
- buf
), 0);
331 smux_var (char *ptr
, size_t len
, oid objid
[], size_t *objid_len
,
333 u_char
*var_val_type
,
342 zlog_debug ("SMUX var parse: len %ld", len
);
345 ptr
= asn_parse_header (ptr
, &len
, &type
);
349 zlog_debug ("SMUX var parse: type %d len %ld", type
, len
);
350 zlog_debug ("SMUX var parse: type must be %d",
351 (ASN_SEQUENCE
| ASN_CONSTRUCTOR
));
354 /* Parse var option. */
355 *objid_len
= MAX_OID_LEN
;
356 ptr
= snmp_parse_var_op(ptr
, objid
, objid_len
, &val_type
,
357 &val_len
, &val
, &len
);
360 *var_val_len
= val_len
;
363 *var_value
= (void*) val
;
366 *var_val_type
= val_type
;
368 /* Requested object id length is objid_len. */
370 smux_oid_dump ("Request OID", objid
, *objid_len
);
373 zlog_debug ("SMUX val_type: %d", val_type
);
375 /* Check request value type. */
380 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
382 zlog_debug ("ASN_NULL");
386 zlog_debug ("ASN_INTEGER");
392 zlog_debug ("ASN_COUNTER");
395 zlog_debug ("ASN_COUNTER64");
398 zlog_debug ("ASN_IPADDRESS");
401 zlog_debug ("ASN_OCTET_STR");
406 zlog_debug ("ASN_OPAQUE");
408 case SNMP_NOSUCHOBJECT
:
409 zlog_debug ("SNMP_NOSUCHOBJECT");
411 case SNMP_NOSUCHINSTANCE
:
412 zlog_debug ("SNMP_NOSUCHINSTANCE");
414 case SNMP_ENDOFMIBVIEW
:
415 zlog_debug ("SNMP_ENDOFMIBVIEW");
418 zlog_debug ("ASN_BIT_STR");
421 zlog_debug ("Unknown type");
427 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
428 ucd-snmp smux and as such suppose, that the peer receives in the message
429 only one variable. Fortunately, IBM seems to do the same in AIX. */
432 smux_set (oid
*reqid
, size_t *reqid_len
,
433 u_char val_type
, void *val
, size_t val_len
, int action
)
436 struct subtree
*subtree
;
442 u_char
*statP
= NULL
;
443 WriteMethod
*write_method
= NULL
;
444 struct listnode
*node
, *nnode
;
447 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
449 subresult
= oid_compare_part (reqid
, *reqid_len
,
450 subtree
->name
, subtree
->name_len
);
452 /* Subtree matched. */
455 /* Prepare suffix. */
456 suffix
= reqid
+ subtree
->name_len
;
457 suffix_len
= *reqid_len
- subtree
->name_len
;
460 /* Check variables. */
461 for (j
= 0; j
< subtree
->variables_num
; j
++)
463 v
= &subtree
->variables
[j
];
465 /* Always check suffix */
466 result
= oid_compare_part (suffix
, suffix_len
,
467 v
->name
, v
->namelen
);
469 /* This is exact match so result must be zero. */
473 zlog_debug ("SMUX function call index is %d", v
->magic
);
475 statP
= (*v
->findVar
) (v
, suffix
, &suffix_len
, 1,
476 &val_len
, &write_method
);
480 return (*write_method
)(action
, val
, val_type
, val_len
,
481 statP
, suffix
, suffix_len
, v
);
485 return SNMP_ERR_READONLY
;
489 /* If above execution is failed or oid is small (so
490 there is no further match). */
492 return SNMP_ERR_NOSUCHNAME
;
496 return SNMP_ERR_NOSUCHNAME
;
500 smux_get (oid
*reqid
, size_t *reqid_len
, int exact
,
501 u_char
*val_type
,void **val
, size_t *val_len
)
504 struct subtree
*subtree
;
510 WriteMethod
*write_method
=NULL
;
511 struct listnode
*node
, *nnode
;
514 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
,subtree
))
516 subresult
= oid_compare_part (reqid
, *reqid_len
,
517 subtree
->name
, subtree
->name_len
);
519 /* Subtree matched. */
522 /* Prepare suffix. */
523 suffix
= reqid
+ subtree
->name_len
;
524 suffix_len
= *reqid_len
- subtree
->name_len
;
527 /* Check variables. */
528 for (j
= 0; j
< subtree
->variables_num
; j
++)
530 v
= &subtree
->variables
[j
];
532 /* Always check suffix */
533 result
= oid_compare_part (suffix
, suffix_len
,
534 v
->name
, v
->namelen
);
536 /* This is exact match so result must be zero. */
540 zlog_debug ("SMUX function call index is %d", v
->magic
);
542 *val
= (*v
->findVar
) (v
, suffix
, &suffix_len
, exact
,
543 val_len
, &write_method
);
545 /* There is no instance. */
547 return SNMP_NOSUCHINSTANCE
;
549 /* Call is suceed. */
555 /* If above execution is failed or oid is small (so
556 there is no further match). */
558 return SNMP_ERR_NOSUCHNAME
;
562 return SNMP_ERR_NOSUCHNAME
;
566 smux_getnext (oid
*reqid
, size_t *reqid_len
, int exact
,
567 u_char
*val_type
,void **val
, size_t *val_len
)
570 oid save
[MAX_OID_LEN
];
572 struct subtree
*subtree
;
578 WriteMethod
*write_method
=NULL
;
579 struct listnode
*node
, *nnode
;
582 /* Save incoming request. */
583 oid_copy (save
, reqid
, *reqid_len
);
584 savelen
= *reqid_len
;
587 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
589 subresult
= oid_compare_part (reqid
, *reqid_len
,
590 subtree
->name
, subtree
->name_len
);
592 /* If request is in the tree. The agent has to make sure we
593 only receive requests we have registered for. */
594 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
595 behave as if it manages the whole SNMP MIB tree itself. It's the
596 duty of the master agent to collect the best answer and return it
597 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
598 :-). ucd-snmp really behaves bad here as it actually might ask
599 multiple times for the same GETNEXT request as it throws away the
600 answer when it expects it in a different subtree and might come
601 back later with the very same request. --jochen */
605 /* Prepare suffix. */
606 suffix
= reqid
+ subtree
->name_len
;
607 suffix_len
= *reqid_len
- subtree
->name_len
;
610 oid_copy(reqid
, subtree
->name
, subtree
->name_len
);
611 *reqid_len
= subtree
->name_len
;
613 for (j
= 0; j
< subtree
->variables_num
; j
++)
616 v
= &subtree
->variables
[j
];
618 /* Next then check result >= 0. */
620 result
= oid_compare_part (suffix
, suffix_len
,
621 v
->name
, v
->namelen
);
626 zlog_debug ("SMUX function call index is %d", v
->magic
);
629 oid_copy(suffix
, v
->name
, v
->namelen
);
630 suffix_len
= v
->namelen
;
632 *val
= (*v
->findVar
) (v
, suffix
, &suffix_len
, exact
,
633 val_len
, &write_method
);
634 *reqid_len
= suffix_len
+ subtree
->name_len
;
644 memcpy (reqid
, save
, savelen
* sizeof(oid
));
645 *reqid_len
= savelen
;
647 return SNMP_ERR_NOSUCHNAME
;
650 /* GET message header. */
652 smux_parse_get_header (char *ptr
, size_t *len
, long *reqid
)
659 ptr
= asn_parse_int (ptr
, len
, &type
, reqid
, sizeof (*reqid
));
662 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid
, (int) *len
);
665 ptr
= asn_parse_int (ptr
, len
, &type
, &errstat
, sizeof (errstat
));
668 zlog_debug ("SMUX GET errstat %ld len: %ld", errstat
, *len
);
671 ptr
= asn_parse_int (ptr
, len
, &type
, &errindex
, sizeof (errindex
));
674 zlog_debug ("SMUX GET errindex %ld len: %ld", errindex
, *len
);
680 smux_parse_set (char *ptr
, size_t len
, int action
)
683 oid oid
[MAX_OID_LEN
];
691 zlog_debug ("SMUX SET(%s) message parse: len %ld",
692 (RESERVE1
== action
) ? "RESERVE1" : ((FREE
== action
) ? "FREE" : "COMMIT"),
695 /* Parse SET message header. */
696 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
698 /* Parse SET message object ID. */
699 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, &val_len
, &val_type
, &val
);
701 ret
= smux_set (oid
, &oid_len
, val_type
, val
, val_len
, action
);
703 zlog_debug ("SMUX SET ret %d", ret
);
706 if (RESERVE1
== action
)
707 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
711 smux_parse_get (char *ptr
, size_t len
, int exact
)
714 oid oid
[MAX_OID_LEN
];
722 zlog_debug ("SMUX GET message parse: len %ld", len
);
724 /* Parse GET message header. */
725 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
727 /* Parse GET message object ID. We needn't the value come */
728 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, NULL
, NULL
, NULL
);
730 /* Traditional getstatptr. */
732 ret
= smux_get (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
734 ret
= smux_getnext (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
738 smux_getresp_send (oid
, oid_len
, reqid
, 0, 0, val_type
, val
, val_len
);
740 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
743 /* Parse SMUX_CLOSE message. */
745 smux_parse_close (char *ptr
, int len
)
751 reason
= (reason
<< 8) | (long) *ptr
;
754 zlog_info ("SMUX_CLOSE with reason: %ld", reason
);
757 /* SMUX_RRSP message. */
759 smux_parse_rrsp (char *ptr
, size_t len
)
764 ptr
= asn_parse_int (ptr
, &len
, &val
, &errstat
, sizeof (errstat
));
767 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val
, errstat
);
770 /* Parse SMUX message. */
772 smux_parse (char *ptr
, size_t len
)
774 /* This buffer we'll use for SOUT message. We could allocate it with
775 malloc and save only static pointer/lenght, but IMHO static
776 buffer is a faster solusion. */
777 static u_char sout_save_buff
[SMUXMAXPKTSIZE
];
778 static int sout_save_len
= 0;
780 int len_income
= len
; /* see note below: YYY */
784 rollback
= ptr
[2]; /* important only for SMUX_SOUT */
786 process_rest
: /* see note below: YYY */
788 /* Parse SMUX message type and subsequent length. */
789 ptr
= asn_parse_header (ptr
, &len
, &type
);
792 zlog_debug ("SMUX message received type: %d rest len: %ld", type
, len
);
797 /* Open must be not send from SNMP agent. */
798 zlog_warn ("SMUX_OPEN received: resetting connection.");
802 /* SMUX_RREQ message is invalid for us. */
803 zlog_warn ("SMUX_RREQ received: resetting connection.");
807 /* SMUX_SOUT message is now valied for us. */
809 zlog_debug ("SMUX_SOUT(%s)", rollback
? "rollback" : "commit");
811 if (sout_save_len
> 0)
813 smux_parse_set (sout_save_buff
, sout_save_len
, rollback
? FREE
: COMMIT
);
817 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len
);
821 /* YYY: this strange code has to solve the "slow peer"
822 problem: When agent sends SMUX_SOUT message it doesn't
823 wait any responce and may send some next message to
824 subagent. Then the peer in 'smux_read()' will recieve
825 from socket the 'concatenated' buffer, contaning both
826 SMUX_SOUT message and the next one
827 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
828 the buffer is longer than 3 ( length of SMUX_SOUT ), we
829 must process the rest of it. This effect may be observed
830 if 'debug_smux' is set to '1' */
832 len
= len_income
- 3;
837 /* SMUX_GETRSP message is invalid for us. */
838 zlog_warn ("SMUX_GETRSP received: resetting connection.");
842 /* Close SMUX connection. */
844 zlog_debug ("SMUX_CLOSE");
845 smux_parse_close (ptr
, len
);
849 /* This is response for register message. */
851 zlog_debug ("SMUX_RRSP");
852 smux_parse_rrsp (ptr
, len
);
855 /* Exact request for object id. */
857 zlog_debug ("SMUX_GET");
858 smux_parse_get (ptr
, len
, 1);
861 /* Next request for object id. */
863 zlog_debug ("SMUX_GETNEXT");
864 smux_parse_get (ptr
, len
, 0);
867 /* SMUX_SET is supported with some limitations. */
869 zlog_debug ("SMUX_SET");
871 /* save the data for future SMUX_SOUT */
872 memcpy (sout_save_buff
, ptr
, len
);
874 smux_parse_set (ptr
, len
, RESERVE1
);
877 zlog_info ("Unknown type: %d", type
);
883 /* SMUX message read function. */
885 smux_read (struct thread
*t
)
889 u_char buf
[SMUXMAXPKTSIZE
];
893 sock
= THREAD_FD (t
);
894 smux_read_thread
= NULL
;
897 zlog_debug ("SMUX read start");
899 /* Read message from SMUX socket. */
900 len
= recv (sock
, buf
, SMUXMAXPKTSIZE
, 0);
904 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno
));
907 smux_event (SMUX_CONNECT
, 0);
913 zlog_warn ("SMUX connection closed: %d", sock
);
916 smux_event (SMUX_CONNECT
, 0);
921 zlog_debug ("SMUX read len: %d", len
);
923 /* Parse the message. */
924 ret
= smux_parse (buf
, len
);
930 smux_event (SMUX_CONNECT
, 0);
934 /* Regiser read thread. */
935 smux_event (SMUX_READ
, sock
);
947 u_char progname
[] = QUAGGA_PROGNAME
"-" QUAGGA_VERSION
;
951 smux_oid_dump ("SMUX open oid", smux_oid
, smux_oid_len
);
952 zlog_debug ("SMUX open progname: %s", progname
);
953 zlog_debug ("SMUX open password: %s", smux_passwd
);
959 /* SMUX Header. As placeholder. */
960 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_OPEN
, 0);
964 ptr
= asn_build_int (ptr
, &len
,
965 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
966 &version
, sizeof (u_long
));
968 /* SMUX connection oid. */
969 ptr
= asn_build_objid (ptr
, &len
,
971 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
972 smux_oid
, smux_oid_len
);
974 /* SMUX connection description. */
975 ptr
= asn_build_string (ptr
, &len
,
977 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
978 progname
, strlen (progname
));
980 /* SMUX connection password. */
981 ptr
= asn_build_string (ptr
, &len
,
983 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
984 smux_passwd
, strlen (smux_passwd
));
986 /* Fill in real SMUX header. We exclude ASN header size (2). */
988 asn_build_header (buf
, &len
, (u_char
) SMUX_OPEN
, (ptr
- buf
) - 2);
990 return send (sock
, buf
, (ptr
- buf
), 0);
994 smux_trap (oid
*name
, size_t namelen
,
995 oid
*iname
, size_t inamelen
,
996 struct trap_object
*trapobj
, size_t trapobjlen
,
997 unsigned int tick
, u_char sptrap
)
1003 struct in_addr addr
;
1011 /* When SMUX connection is not established. */
1016 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_TRAP
, 0);
1018 /* Sub agent enterprise oid. */
1019 ptr
= asn_build_objid (ptr
, &len
,
1021 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1022 smux_oid
, smux_oid_len
);
1026 ptr
= asn_build_string (ptr
, &len
,
1028 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_IPADDRESS
),
1029 (u_char
*)&addr
, sizeof (struct in_addr
));
1031 /* Generic trap integer. */
1032 val
= SNMP_TRAP_ENTERPRISESPECIFIC
;
1033 ptr
= asn_build_int (ptr
, &len
,
1034 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1035 &val
, sizeof (int));
1037 /* Specific trap integer. */
1039 ptr
= asn_build_int (ptr
, &len
,
1040 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1041 &val
, sizeof (int));
1043 /* Timeticks timestamp. */
1045 ptr
= asn_build_unsigned_int (ptr
, &len
,
1046 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_TIMETICKS
),
1047 &val
, sizeof (int));
1051 ptr
= asn_build_sequence (ptr
, &len
,
1052 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1056 /* Iteration for each objects. */
1058 for (i
= 0; i
< trapobjlen
; i
++)
1061 oid oid
[MAX_OID_LEN
];
1068 oid_copy (oid
, name
, namelen
);
1069 oid_copy (oid
+ namelen
, trapobj
[i
].name
, trapobj
[i
].namelen
);
1070 oid_copy (oid
+ namelen
+ trapobj
[i
].namelen
, iname
, inamelen
);
1071 oid_len
= namelen
+ trapobj
[i
].namelen
+ inamelen
;
1074 smux_oid_dump ("Trap", oid
, oid_len
);
1076 ret
= smux_get (oid
, &oid_len
, 1, &val_type
, &val
, &val_len
);
1079 zlog_debug ("smux_get result %d", ret
);
1082 ptr
= snmp_build_var_op (ptr
, oid
, &oid_len
,
1083 val_type
, val_len
, val
, &len
);
1086 /* Now variable size is known, fill in size */
1087 asn_build_sequence(h1
, &length
,
1088 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1091 /* Fill in size of whole sequence */
1093 asn_build_header (buf
, &len
, (u_char
) SMUX_TRAP
, (ptr
- buf
) - 2);
1095 return send (smux_sock
, buf
, (ptr
- buf
), 0);
1099 smux_register (int sock
)
1107 struct subtree
*subtree
;
1108 struct listnode
*node
, *nnode
;
1112 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
1117 /* SMUX RReq Header. */
1118 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_RREQ
, 0);
1120 /* Register MIB tree. */
1121 ptr
= asn_build_objid (ptr
, &len
,
1123 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1124 subtree
->name
, subtree
->name_len
);
1128 ptr
= asn_build_int (ptr
, &len
,
1129 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1130 &priority
, sizeof (u_long
));
1133 operation
= 2; /* Register R/W */
1134 ptr
= asn_build_int (ptr
, &len
,
1135 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1136 &operation
, sizeof (u_long
));
1140 smux_oid_dump ("SMUX register oid", subtree
->name
, subtree
->name_len
);
1141 zlog_debug ("SMUX register priority: %ld", priority
);
1142 zlog_debug ("SMUX register operation: %ld", operation
);
1146 asn_build_header (buf
, &len
, (u_char
) SMUX_RREQ
, (ptr
- buf
) - 2);
1147 ret
= send (sock
, buf
, (ptr
- buf
), 0);
1154 /* Try to connect to SNMP agent. */
1156 smux_connect (struct thread
*t
)
1161 zlog_debug ("SMUX connect try %d", fail
+ 1);
1163 /* Clear thread poner of myself. */
1164 smux_connect_thread
= NULL
;
1166 /* Make socket. Try to connect. */
1167 smux_sock
= smux_socket ();
1170 if (++fail
< SMUX_MAX_FAILURE
)
1171 smux_event (SMUX_CONNECT
, 0);
1175 /* Send OPEN PDU. */
1176 ret
= smux_open (smux_sock
);
1179 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno
));
1182 if (++fail
< SMUX_MAX_FAILURE
)
1183 smux_event (SMUX_CONNECT
, 0);
1187 /* Send any outstanding register PDUs. */
1188 ret
= smux_register (smux_sock
);
1191 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno
));
1194 if (++fail
< SMUX_MAX_FAILURE
)
1195 smux_event (SMUX_CONNECT
, 0);
1199 /* Everything goes fine. */
1200 smux_event (SMUX_READ
, smux_sock
);
1205 /* Clear all SMUX related resources. */
1209 if (smux_read_thread
)
1210 thread_cancel (smux_read_thread
);
1211 if (smux_connect_thread
)
1212 thread_cancel (smux_connect_thread
);
1224 smux_event (enum smux_event event
, int sock
)
1229 smux_connect_thread
= thread_add_event (master
, smux_connect
, NULL
, 0);
1232 smux_connect_thread
= thread_add_timer (master
, smux_connect
, NULL
, 10);
1235 smux_read_thread
= thread_add_read (master
, smux_read
, NULL
, sock
);
1243 smux_str2oid (const char *str
, oid
*oid
, size_t *oid_len
)
1259 if (! isdigit (*str
))
1262 while (isdigit (*str
))
1265 val
+= (*str
- '0');
1286 smux_oid_dup (oid
*objid
, size_t objid_len
)
1290 new = XMALLOC (MTYPE_TMP
, sizeof (oid
) * objid_len
);
1291 oid_copy (new, objid
, objid_len
);
1297 smux_peer_oid (struct vty
*vty
, const char *oid_str
, const char *passwd_str
)
1300 oid oid
[MAX_OID_LEN
];
1303 ret
= smux_str2oid (oid_str
, oid
, &oid_len
);
1306 vty_out (vty
, "object ID malformed%s", VTY_NEWLINE
);
1316 /* careful, smux_passwd might point to string constant */
1323 smux_oid
= smux_oid_dup (oid
, oid_len
);
1324 smux_oid_len
= oid_len
;
1327 smux_passwd
= strdup (passwd_str
);
1329 smux_passwd
= strdup ("");
1335 smux_header_generic (struct variable
*v
, oid
*name
, size_t *length
, int exact
,
1336 size_t *var_len
, WriteMethod
**write_method
)
1338 oid fulloid
[MAX_OID_LEN
];
1341 oid_copy (fulloid
, v
->name
, v
->namelen
);
1342 fulloid
[v
->namelen
] = 0;
1343 /* Check against full instance. */
1344 ret
= oid_compare (name
, *length
, fulloid
, v
->namelen
+ 1);
1346 /* Check single instance. */
1347 if ((exact
&& (ret
!= 0)) || (!exact
&& (ret
>= 0)))
1348 return MATCH_FAILED
;
1350 /* In case of getnext, fill in full instance. */
1351 memcpy (name
, fulloid
, (v
->namelen
+ 1) * sizeof (oid
));
1352 *length
= v
->namelen
+ 1;
1355 *var_len
= sizeof(long); /* default to 'long' results */
1357 return MATCH_SUCCEEDED
;
1361 smux_peer_default ()
1369 /* careful, smux_passwd might be pointing at string constant */
1382 "SNMP MUX protocol settings\n"
1383 "SNMP MUX peer settings\n"
1384 "Object ID used in SMUX peering\n")
1386 if (smux_peer_oid (vty
, argv
[0], NULL
) == 0)
1395 DEFUN (smux_peer_password
,
1396 smux_peer_password_cmd
,
1397 "smux peer OID PASSWORD",
1398 "SNMP MUX protocol settings\n"
1399 "SNMP MUX peer settings\n"
1400 "SMUX peering object ID\n"
1401 "SMUX peering password\n")
1403 if (smux_peer_oid (vty
, argv
[0], argv
[1]) == 0)
1412 DEFUN (no_smux_peer
,
1416 "SNMP MUX protocol settings\n"
1417 "SNMP MUX peer settings\n")
1420 return smux_peer_default ();
1423 ALIAS (no_smux_peer
,
1424 no_smux_peer_oid_cmd
,
1427 "SNMP MUX protocol settings\n"
1428 "SNMP MUX peer settings\n"
1429 "SMUX peering object ID\n")
1431 ALIAS (no_smux_peer
,
1432 no_smux_peer_oid_password_cmd
,
1433 "no smux peer OID PASSWORD",
1435 "SNMP MUX protocol settings\n"
1436 "SNMP MUX peer settings\n"
1437 "SMUX peering object ID\n"
1438 "SMUX peering password\n")
1441 config_write_smux (struct vty
*vty
)
1448 vty_out (vty
, "smux peer ");
1449 for (i
= 0; i
< smux_oid_len
; i
++)
1451 vty_out (vty
, "%s%d", first
? "" : ".", (int) smux_oid
[i
]);
1454 vty_out (vty
, " %s%s", smux_passwd
, VTY_NEWLINE
);
1459 /* Register subtree to smux master tree. */
1461 smux_register_mib (const char *descr
, struct variable
*var
,
1462 size_t width
, int num
,
1463 oid name
[], size_t namelen
)
1465 struct subtree
*tree
;
1467 tree
= (struct subtree
*)malloc(sizeof(struct subtree
));
1468 oid_copy (tree
->name
, name
, namelen
);
1469 tree
->name_len
= namelen
;
1470 tree
->variables
= var
;
1471 tree
->variables_num
= num
;
1472 tree
->variables_width
= width
;
1473 tree
->registered
= 0;
1474 listnode_add_sort(treelist
, tree
);
1480 /* Setting configuration to default. */
1481 smux_peer_default ();
1484 /* Compare function to keep treelist sorted */
1486 smux_tree_cmp(struct subtree
*tree1
, struct subtree
*tree2
)
1488 return oid_compare(tree1
->name
, tree1
->name_len
,
1489 tree2
->name
, tree2
->name_len
);
1492 /* Initialize some values then schedule first SMUX connection. */
1494 smux_init (struct thread_master
*tm
)
1496 /* copy callers thread master */
1499 /* Make MIB tree. */
1500 treelist
= list_new();
1501 treelist
->cmp
= (int (*)(void *, void *))smux_tree_cmp
;
1503 /* Install commands. */
1504 install_node (&smux_node
, config_write_smux
);
1506 install_element (CONFIG_NODE
, &smux_peer_cmd
);
1507 install_element (CONFIG_NODE
, &smux_peer_password_cmd
);
1508 install_element (CONFIG_NODE
, &no_smux_peer_cmd
);
1509 install_element (CONFIG_NODE
, &no_smux_peer_oid_cmd
);
1510 install_element (CONFIG_NODE
, &no_smux_peer_oid_password_cmd
);
1516 /* Schedule first connection. */
1517 smux_event (SMUX_SCHEDULE
, 0);
1519 #endif /* HAVE_SNMP */