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
;
240 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
241 serv
.sin_len
= sizeof (struct sockaddr_in
);
242 #endif /* HAVE_STRUCT_SOCKADDR_IN_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 (version
));
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 (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 (val
));
1037 /* Specific trap integer. */
1039 ptr
= asn_build_int (ptr
, &len
,
1040 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1041 &val
, sizeof (val
));
1043 /* Timeticks timestamp. */
1045 ptr
= asn_build_unsigned_int (ptr
, &len
,
1046 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_TIMETICKS
),
1047 &val
, sizeof (val
));
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 if (trapobj
[i
].namelen
> 0)
1070 oid_copy (oid
, name
, namelen
);
1071 oid_copy (oid
+ namelen
, trapobj
[i
].name
, trapobj
[i
].namelen
);
1072 oid_copy (oid
+ namelen
+ trapobj
[i
].namelen
, iname
, inamelen
);
1073 oid_len
= namelen
+ trapobj
[i
].namelen
+ inamelen
;
1077 oid_copy (oid
, name
, namelen
);
1078 oid_copy (oid
+ namelen
, trapobj
[i
].name
, trapobj
[i
].namelen
* (-1));
1079 oid_len
= namelen
+ trapobj
[i
].namelen
* (-1) ;
1084 smux_oid_dump ("Trap", name
, namelen
);
1085 if (trapobj
[i
].namelen
< 0)
1086 smux_oid_dump ("Trap",
1087 trapobj
[i
].name
, (- 1) * (trapobj
[i
].namelen
));
1090 smux_oid_dump ("Trap", trapobj
[i
].name
, (trapobj
[i
].namelen
));
1091 smux_oid_dump ("Trap", iname
, inamelen
);
1093 smux_oid_dump ("Trap", oid
, oid_len
);
1094 zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ
, (u_long
)oid_len
);
1097 ret
= smux_get (oid
, &oid_len
, 1, &val_type
, &val
, &val_len
);
1100 zlog_debug ("smux_get result %d", ret
);
1103 ptr
= snmp_build_var_op (ptr
, oid
, &oid_len
,
1104 val_type
, val_len
, val
, &len
);
1107 /* Now variable size is known, fill in size */
1108 asn_build_sequence(h1
, &length
,
1109 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1112 /* Fill in size of whole sequence */
1114 asn_build_header (buf
, &len
, (u_char
) SMUX_TRAP
, (ptr
- buf
) - 2);
1116 return send (smux_sock
, buf
, (ptr
- buf
), 0);
1120 smux_register (int sock
)
1128 struct subtree
*subtree
;
1129 struct listnode
*node
, *nnode
;
1133 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
1138 /* SMUX RReq Header. */
1139 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_RREQ
, 0);
1141 /* Register MIB tree. */
1142 ptr
= asn_build_objid (ptr
, &len
,
1144 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1145 subtree
->name
, subtree
->name_len
);
1149 ptr
= asn_build_int (ptr
, &len
,
1150 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1151 &priority
, sizeof (priority
));
1154 operation
= 2; /* Register R/W */
1155 ptr
= asn_build_int (ptr
, &len
,
1156 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1157 &operation
, sizeof (operation
));
1161 smux_oid_dump ("SMUX register oid", subtree
->name
, subtree
->name_len
);
1162 zlog_debug ("SMUX register priority: %ld", priority
);
1163 zlog_debug ("SMUX register operation: %ld", operation
);
1167 asn_build_header (buf
, &len
, (u_char
) SMUX_RREQ
, (ptr
- buf
) - 2);
1168 ret
= send (sock
, buf
, (ptr
- buf
), 0);
1175 /* Try to connect to SNMP agent. */
1177 smux_connect (struct thread
*t
)
1182 zlog_debug ("SMUX connect try %d", fail
+ 1);
1184 /* Clear thread poner of myself. */
1185 smux_connect_thread
= NULL
;
1187 /* Make socket. Try to connect. */
1188 smux_sock
= smux_socket ();
1191 if (++fail
< SMUX_MAX_FAILURE
)
1192 smux_event (SMUX_CONNECT
, 0);
1196 /* Send OPEN PDU. */
1197 ret
= smux_open (smux_sock
);
1200 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno
));
1203 if (++fail
< SMUX_MAX_FAILURE
)
1204 smux_event (SMUX_CONNECT
, 0);
1208 /* Send any outstanding register PDUs. */
1209 ret
= smux_register (smux_sock
);
1212 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno
));
1215 if (++fail
< SMUX_MAX_FAILURE
)
1216 smux_event (SMUX_CONNECT
, 0);
1220 /* Everything goes fine. */
1221 smux_event (SMUX_READ
, smux_sock
);
1226 /* Clear all SMUX related resources. */
1230 if (smux_read_thread
)
1231 thread_cancel (smux_read_thread
);
1232 if (smux_connect_thread
)
1233 thread_cancel (smux_connect_thread
);
1245 smux_event (enum smux_event event
, int sock
)
1250 smux_connect_thread
= thread_add_event (master
, smux_connect
, NULL
, 0);
1253 smux_connect_thread
= thread_add_timer (master
, smux_connect
, NULL
, 10);
1256 smux_read_thread
= thread_add_read (master
, smux_read
, NULL
, sock
);
1264 smux_str2oid (const char *str
, oid
*oid
, size_t *oid_len
)
1280 if (! isdigit (*str
))
1283 while (isdigit (*str
))
1286 val
+= (*str
- '0');
1307 smux_oid_dup (oid
*objid
, size_t objid_len
)
1311 new = XMALLOC (MTYPE_TMP
, sizeof (oid
) * objid_len
);
1312 oid_copy (new, objid
, objid_len
);
1318 smux_peer_oid (struct vty
*vty
, const char *oid_str
, const char *passwd_str
)
1321 oid oid
[MAX_OID_LEN
];
1324 ret
= smux_str2oid (oid_str
, oid
, &oid_len
);
1327 vty_out (vty
, "object ID malformed%s", VTY_NEWLINE
);
1337 /* careful, smux_passwd might point to string constant */
1344 smux_oid
= smux_oid_dup (oid
, oid_len
);
1345 smux_oid_len
= oid_len
;
1348 smux_passwd
= strdup (passwd_str
);
1350 smux_passwd
= strdup ("");
1356 smux_header_generic (struct variable
*v
, oid
*name
, size_t *length
, int exact
,
1357 size_t *var_len
, WriteMethod
**write_method
)
1359 oid fulloid
[MAX_OID_LEN
];
1362 oid_copy (fulloid
, v
->name
, v
->namelen
);
1363 fulloid
[v
->namelen
] = 0;
1364 /* Check against full instance. */
1365 ret
= oid_compare (name
, *length
, fulloid
, v
->namelen
+ 1);
1367 /* Check single instance. */
1368 if ((exact
&& (ret
!= 0)) || (!exact
&& (ret
>= 0)))
1369 return MATCH_FAILED
;
1371 /* In case of getnext, fill in full instance. */
1372 memcpy (name
, fulloid
, (v
->namelen
+ 1) * sizeof (oid
));
1373 *length
= v
->namelen
+ 1;
1376 *var_len
= sizeof(long); /* default to 'long' results */
1378 return MATCH_SUCCEEDED
;
1382 smux_peer_default ()
1390 /* careful, smux_passwd might be pointing at string constant */
1403 "SNMP MUX protocol settings\n"
1404 "SNMP MUX peer settings\n"
1405 "Object ID used in SMUX peering\n")
1407 if (smux_peer_oid (vty
, argv
[0], NULL
) == 0)
1416 DEFUN (smux_peer_password
,
1417 smux_peer_password_cmd
,
1418 "smux peer OID PASSWORD",
1419 "SNMP MUX protocol settings\n"
1420 "SNMP MUX peer settings\n"
1421 "SMUX peering object ID\n"
1422 "SMUX peering password\n")
1424 if (smux_peer_oid (vty
, argv
[0], argv
[1]) == 0)
1433 DEFUN (no_smux_peer
,
1437 "SNMP MUX protocol settings\n"
1438 "SNMP MUX peer settings\n")
1441 return smux_peer_default ();
1444 ALIAS (no_smux_peer
,
1445 no_smux_peer_oid_cmd
,
1448 "SNMP MUX protocol settings\n"
1449 "SNMP MUX peer settings\n"
1450 "SMUX peering object ID\n")
1452 ALIAS (no_smux_peer
,
1453 no_smux_peer_oid_password_cmd
,
1454 "no smux peer OID PASSWORD",
1456 "SNMP MUX protocol settings\n"
1457 "SNMP MUX peer settings\n"
1458 "SMUX peering object ID\n"
1459 "SMUX peering password\n")
1462 config_write_smux (struct vty
*vty
)
1469 vty_out (vty
, "smux peer ");
1470 for (i
= 0; i
< smux_oid_len
; i
++)
1472 vty_out (vty
, "%s%d", first
? "" : ".", (int) smux_oid
[i
]);
1475 vty_out (vty
, " %s%s", smux_passwd
, VTY_NEWLINE
);
1480 /* Register subtree to smux master tree. */
1482 smux_register_mib (const char *descr
, struct variable
*var
,
1483 size_t width
, int num
,
1484 oid name
[], size_t namelen
)
1486 struct subtree
*tree
;
1488 tree
= (struct subtree
*)malloc(sizeof(struct subtree
));
1489 oid_copy (tree
->name
, name
, namelen
);
1490 tree
->name_len
= namelen
;
1491 tree
->variables
= var
;
1492 tree
->variables_num
= num
;
1493 tree
->variables_width
= width
;
1494 tree
->registered
= 0;
1495 listnode_add_sort(treelist
, tree
);
1501 /* Setting configuration to default. */
1502 smux_peer_default ();
1505 /* Compare function to keep treelist sorted */
1507 smux_tree_cmp(struct subtree
*tree1
, struct subtree
*tree2
)
1509 return oid_compare(tree1
->name
, tree1
->name_len
,
1510 tree2
->name
, tree2
->name_len
);
1513 /* Initialize some values then schedule first SMUX connection. */
1515 smux_init (struct thread_master
*tm
)
1517 /* copy callers thread master */
1520 /* Make MIB tree. */
1521 treelist
= list_new();
1522 treelist
->cmp
= (int (*)(void *, void *))smux_tree_cmp
;
1524 /* Install commands. */
1525 install_node (&smux_node
, config_write_smux
);
1527 install_element (CONFIG_NODE
, &smux_peer_cmd
);
1528 install_element (CONFIG_NODE
, &smux_peer_password_cmd
);
1529 install_element (CONFIG_NODE
, &no_smux_peer_cmd
);
1530 install_element (CONFIG_NODE
, &no_smux_peer_oid_cmd
);
1531 install_element (CONFIG_NODE
, &no_smux_peer_oid_password_cmd
);
1537 /* Schedule first connection. */
1538 smux_event (SMUX_SCHEDULE
, 0);
1540 #endif /* HAVE_SNMP */