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>
27 #include <net-snmp/net-snmp-includes.h>
31 #include <snmp_impl.h>
38 #include <lib/version.h>
40 #include "sockunion.h"
43 #define min(A,B) ((A) < (B) ? (A) : (B))
45 enum smux_event
{SMUX_SCHEDULE
, SMUX_CONNECT
, SMUX_READ
};
47 void smux_event (enum smux_event
, int);
53 /* SMUX subtree list. */
54 struct list
*treelist
;
61 char *smux_passwd
= NULL
;
63 /* SMUX read threads. */
64 struct thread
*smux_read_thread
;
66 /* SMUX connect thrads. */
67 struct thread
*smux_connect_thread
;
69 /* SMUX debug flag. */
72 /* SMUX failure count. */
76 static struct cmd_node smux_node
=
79 "" /* SMUX has no interface. */
83 static struct thread_master
*master
;
86 oid_copy (void *dest
, const void *src
, size_t size
)
88 return memcpy (dest
, src
, size
* sizeof (oid
));
92 oid2in_addr (oid oid
[], int len
, struct in_addr
*addr
)
100 pnt
= (u_char
*) addr
;
102 for (i
= 0; i
< len
; i
++)
107 oid_copy_addr (oid oid
[], struct in_addr
*addr
, int len
)
115 pnt
= (u_char
*) addr
;
117 for (i
= 0; i
< len
; i
++)
122 oid_compare (oid
*o1
, int o1_len
, oid
*o2
, int o2_len
)
126 for (i
= 0; i
< min (o1_len
, o2_len
); i
++)
130 else if (o1
[i
] > o2
[i
])
142 oid_compare_part (oid
*o1
, int o1_len
, oid
*o2
, int o2_len
)
146 for (i
= 0; i
< min (o1_len
, o2_len
); i
++)
150 else if (o1
[i
] > o2
[i
])
160 smux_oid_dump (const char *prefix
, const oid
*oid
, size_t oid_len
)
164 char buf
[MAX_OID_LEN
* 3];
168 for (i
= 0; i
< oid_len
; i
++)
170 sprintf (buf
+ strlen (buf
), "%s%d", first
? "" : ".", (int) oid
[i
]);
173 zlog_debug ("%s: %s", prefix
, buf
);
181 struct addrinfo hints
, *res0
, *res
;
184 struct sockaddr_in serv
;
190 memset(&hints
, 0, sizeof(hints
));
191 hints
.ai_family
= PF_UNSPEC
;
192 hints
.ai_socktype
= SOCK_STREAM
;
193 gai
= getaddrinfo(NULL
, "smux", &hints
, &res0
);
194 if (gai
== EAI_SERVICE
)
196 char servbuf
[NI_MAXSERV
];
197 sprintf(servbuf
,"%d",SMUX_PORT_DEFAULT
);
198 servbuf
[sizeof (servbuf
) - 1] = '\0';
199 gai
= getaddrinfo(NULL
, servbuf
, &hints
, &res0
);
203 zlog_warn("Cannot locate loopback service smux");
206 for(res
=res0
; res
; res
=res
->ai_next
)
208 if (res
->ai_family
!= AF_INET
210 && res
->ai_family
!= AF_INET6
211 #endif /* HAVE_IPV6 */
215 sock
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
218 sockopt_reuseaddr (sock
);
219 sockopt_reuseport (sock
);
220 ret
= connect (sock
, res
->ai_addr
, res
->ai_addrlen
);
231 zlog_warn ("Can't connect to SNMP agent with SMUX");
233 sock
= socket (AF_INET
, SOCK_STREAM
, 0);
236 zlog_warn ("Can't make socket for SNMP");
240 memset (&serv
, 0, sizeof (struct sockaddr_in
));
241 serv
.sin_family
= AF_INET
;
242 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
243 serv
.sin_len
= sizeof (struct sockaddr_in
);
244 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
246 sp
= getservbyname ("smux", "tcp");
248 serv
.sin_port
= sp
->s_port
;
250 serv
.sin_port
= htons (SMUX_PORT_DEFAULT
);
252 serv
.sin_addr
.s_addr
= htonl (INADDR_LOOPBACK
);
254 sockopt_reuseaddr (sock
);
255 sockopt_reuseport (sock
);
257 ret
= connect (sock
, (struct sockaddr
*) &serv
, sizeof (struct sockaddr_in
));
262 zlog_warn ("Can't connect to SNMP agent with SMUX");
270 smux_getresp_send (oid objid
[], size_t objid_len
, long reqid
, long errstat
,
271 long errindex
, u_char val_type
, void *arg
, size_t arg_len
)
275 u_char
*ptr
, *h1
, *h1e
, *h2
, *h2e
;
284 zlog_debug ("SMUX GETRSP send");
285 zlog_debug ("SMUX GETRSP reqid: %ld", reqid
);
289 /* Place holder h1 for complete sequence */
290 ptr
= asn_build_sequence (ptr
, &len
, (u_char
) SMUX_GETRSP
, 0);
293 ptr
= asn_build_int (ptr
, &len
,
294 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
295 &reqid
, sizeof (reqid
));
298 zlog_debug ("SMUX GETRSP errstat: %ld", errstat
);
300 ptr
= asn_build_int (ptr
, &len
,
301 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
302 &errstat
, sizeof (errstat
));
304 zlog_debug ("SMUX GETRSP errindex: %ld", errindex
);
306 ptr
= asn_build_int (ptr
, &len
,
307 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
308 &errindex
, sizeof (errindex
));
311 /* Place holder h2 for one variable */
312 ptr
= asn_build_sequence (ptr
, &len
,
313 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
317 ptr
= snmp_build_var_op (ptr
, objid
, &objid_len
,
318 val_type
, arg_len
, arg
, &len
);
320 /* Now variable size is known, fill in size */
321 asn_build_sequence(h2
,&length
,(u_char
)(ASN_SEQUENCE
|ASN_CONSTRUCTOR
),ptr
-h2e
);
323 /* Fill in size of whole sequence */
324 asn_build_sequence(h1
,&length
,(u_char
)SMUX_GETRSP
,ptr
-h1e
);
327 zlog_debug ("SMUX getresp send: %td", (ptr
- buf
));
329 ret
= send (smux_sock
, buf
, (ptr
- buf
), 0);
333 smux_var (u_char
*ptr
, size_t len
, oid objid
[], size_t *objid_len
,
335 u_char
*var_val_type
,
344 zlog_debug ("SMUX var parse: len %zd", len
);
347 ptr
= asn_parse_header (ptr
, &len
, &type
);
351 zlog_debug ("SMUX var parse: type %d len %zd", type
, len
);
352 zlog_debug ("SMUX var parse: type must be %d",
353 (ASN_SEQUENCE
| ASN_CONSTRUCTOR
));
356 /* Parse var option. */
357 *objid_len
= MAX_OID_LEN
;
358 ptr
= snmp_parse_var_op(ptr
, objid
, objid_len
, &val_type
,
359 &val_len
, &val
, &len
);
362 *var_val_len
= val_len
;
365 *var_value
= (void*) val
;
368 *var_val_type
= val_type
;
370 /* Requested object id length is objid_len. */
372 smux_oid_dump ("Request OID", objid
, *objid_len
);
375 zlog_debug ("SMUX val_type: %d", val_type
);
377 /* Check request value type. */
382 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
384 zlog_debug ("ASN_NULL");
388 zlog_debug ("ASN_INTEGER");
394 zlog_debug ("ASN_COUNTER");
397 zlog_debug ("ASN_COUNTER64");
400 zlog_debug ("ASN_IPADDRESS");
403 zlog_debug ("ASN_OCTET_STR");
408 zlog_debug ("ASN_OPAQUE");
410 case SNMP_NOSUCHOBJECT
:
411 zlog_debug ("SNMP_NOSUCHOBJECT");
413 case SNMP_NOSUCHINSTANCE
:
414 zlog_debug ("SNMP_NOSUCHINSTANCE");
416 case SNMP_ENDOFMIBVIEW
:
417 zlog_debug ("SNMP_ENDOFMIBVIEW");
420 zlog_debug ("ASN_BIT_STR");
423 zlog_debug ("Unknown type");
429 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
430 ucd-snmp smux and as such suppose, that the peer receives in the message
431 only one variable. Fortunately, IBM seems to do the same in AIX. */
434 smux_set (oid
*reqid
, size_t *reqid_len
,
435 u_char val_type
, void *val
, size_t val_len
, int action
)
438 struct subtree
*subtree
;
444 u_char
*statP
= NULL
;
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 statP
= (*v
->findVar
) (v
, suffix
, &suffix_len
, 1,
478 &val_len
, &write_method
);
482 return (*write_method
)(action
, val
, val_type
, val_len
,
483 statP
, suffix
, suffix_len
, v
);
487 return SNMP_ERR_READONLY
;
491 /* If above execution is failed or oid is small (so
492 there is no further match). */
494 return SNMP_ERR_NOSUCHNAME
;
498 return SNMP_ERR_NOSUCHNAME
;
502 smux_get (oid
*reqid
, size_t *reqid_len
, int exact
,
503 u_char
*val_type
,void **val
, size_t *val_len
)
506 struct subtree
*subtree
;
512 WriteMethod
*write_method
=NULL
;
513 struct listnode
*node
, *nnode
;
516 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
,subtree
))
518 subresult
= oid_compare_part (reqid
, *reqid_len
,
519 subtree
->name
, subtree
->name_len
);
521 /* Subtree matched. */
524 /* Prepare suffix. */
525 suffix
= reqid
+ subtree
->name_len
;
526 suffix_len
= *reqid_len
- subtree
->name_len
;
529 /* Check variables. */
530 for (j
= 0; j
< subtree
->variables_num
; j
++)
532 v
= &subtree
->variables
[j
];
534 /* Always check suffix */
535 result
= oid_compare_part (suffix
, suffix_len
,
536 v
->name
, v
->namelen
);
538 /* This is exact match so result must be zero. */
542 zlog_debug ("SMUX function call index is %d", v
->magic
);
544 *val
= (*v
->findVar
) (v
, suffix
, &suffix_len
, exact
,
545 val_len
, &write_method
);
547 /* There is no instance. */
549 return SNMP_NOSUCHINSTANCE
;
551 /* Call is suceed. */
557 /* If above execution is failed or oid is small (so
558 there is no further match). */
560 return SNMP_ERR_NOSUCHNAME
;
564 return SNMP_ERR_NOSUCHNAME
;
568 smux_getnext (oid
*reqid
, size_t *reqid_len
, int exact
,
569 u_char
*val_type
,void **val
, size_t *val_len
)
572 oid save
[MAX_OID_LEN
];
574 struct subtree
*subtree
;
580 WriteMethod
*write_method
=NULL
;
581 struct listnode
*node
, *nnode
;
584 /* Save incoming request. */
585 oid_copy (save
, reqid
, *reqid_len
);
586 savelen
= *reqid_len
;
589 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
591 subresult
= oid_compare_part (reqid
, *reqid_len
,
592 subtree
->name
, subtree
->name_len
);
594 /* If request is in the tree. The agent has to make sure we
595 only receive requests we have registered for. */
596 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
597 behave as if it manages the whole SNMP MIB tree itself. It's the
598 duty of the master agent to collect the best answer and return it
599 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
600 :-). ucd-snmp really behaves bad here as it actually might ask
601 multiple times for the same GETNEXT request as it throws away the
602 answer when it expects it in a different subtree and might come
603 back later with the very same request. --jochen */
607 /* Prepare suffix. */
608 suffix
= reqid
+ subtree
->name_len
;
609 suffix_len
= *reqid_len
- subtree
->name_len
;
612 oid_copy(reqid
, subtree
->name
, subtree
->name_len
);
613 *reqid_len
= subtree
->name_len
;
615 for (j
= 0; j
< subtree
->variables_num
; j
++)
618 v
= &subtree
->variables
[j
];
620 /* Next then check result >= 0. */
622 result
= oid_compare_part (suffix
, suffix_len
,
623 v
->name
, v
->namelen
);
628 zlog_debug ("SMUX function call index is %d", v
->magic
);
631 oid_copy(suffix
, v
->name
, v
->namelen
);
632 suffix_len
= v
->namelen
;
634 *val
= (*v
->findVar
) (v
, suffix
, &suffix_len
, exact
,
635 val_len
, &write_method
);
636 *reqid_len
= suffix_len
+ subtree
->name_len
;
646 memcpy (reqid
, save
, savelen
* sizeof(oid
));
647 *reqid_len
= savelen
;
649 return SNMP_ERR_NOSUCHNAME
;
652 /* GET message header. */
654 smux_parse_get_header (u_char
*ptr
, size_t *len
, long *reqid
)
661 ptr
= asn_parse_int (ptr
, len
, &type
, reqid
, sizeof (*reqid
));
664 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid
, (int) *len
);
667 ptr
= asn_parse_int (ptr
, len
, &type
, &errstat
, sizeof (errstat
));
670 zlog_debug ("SMUX GET errstat %ld len: %zd", errstat
, *len
);
673 ptr
= asn_parse_int (ptr
, len
, &type
, &errindex
, sizeof (errindex
));
676 zlog_debug ("SMUX GET errindex %ld len: %zd", errindex
, *len
);
682 smux_parse_set (u_char
*ptr
, size_t len
, int action
)
685 oid oid
[MAX_OID_LEN
];
693 zlog_debug ("SMUX SET(%s) message parse: len %zd",
694 (RESERVE1
== action
) ? "RESERVE1" : ((FREE
== action
) ? "FREE" : "COMMIT"),
697 /* Parse SET message header. */
698 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
700 /* Parse SET message object ID. */
701 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, &val_len
, &val_type
, &val
);
703 ret
= smux_set (oid
, &oid_len
, val_type
, val
, val_len
, action
);
705 zlog_debug ("SMUX SET ret %d", ret
);
708 if (RESERVE1
== action
)
709 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
713 smux_parse_get (u_char
*ptr
, size_t len
, int exact
)
716 oid oid
[MAX_OID_LEN
];
724 zlog_debug ("SMUX GET message parse: len %zd", len
);
726 /* Parse GET message header. */
727 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
729 /* Parse GET message object ID. We needn't the value come */
730 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, NULL
, NULL
, NULL
);
732 /* Traditional getstatptr. */
734 ret
= smux_get (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
736 ret
= smux_getnext (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
740 smux_getresp_send (oid
, oid_len
, reqid
, 0, 0, val_type
, val
, val_len
);
742 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
745 /* Parse SMUX_CLOSE message. */
747 smux_parse_close (u_char
*ptr
, int len
)
753 reason
= (reason
<< 8) | (long) *ptr
;
756 zlog_info ("SMUX_CLOSE with reason: %ld", reason
);
759 /* SMUX_RRSP message. */
761 smux_parse_rrsp (u_char
*ptr
, size_t len
)
766 ptr
= asn_parse_int (ptr
, &len
, &val
, &errstat
, sizeof (errstat
));
769 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val
, errstat
);
772 /* Parse SMUX message. */
774 smux_parse (u_char
*ptr
, size_t len
)
776 /* This buffer we'll use for SOUT message. We could allocate it with
777 malloc and save only static pointer/lenght, but IMHO static
778 buffer is a faster solusion. */
779 static u_char sout_save_buff
[SMUXMAXPKTSIZE
];
780 static int sout_save_len
= 0;
782 int len_income
= len
; /* see note below: YYY */
786 rollback
= ptr
[2]; /* important only for SMUX_SOUT */
788 process_rest
: /* see note below: YYY */
790 /* Parse SMUX message type and subsequent length. */
791 ptr
= asn_parse_header (ptr
, &len
, &type
);
794 zlog_debug ("SMUX message received type: %d rest len: %zd", type
, len
);
799 /* Open must be not send from SNMP agent. */
800 zlog_warn ("SMUX_OPEN received: resetting connection.");
804 /* SMUX_RREQ message is invalid for us. */
805 zlog_warn ("SMUX_RREQ received: resetting connection.");
809 /* SMUX_SOUT message is now valied for us. */
811 zlog_debug ("SMUX_SOUT(%s)", rollback
? "rollback" : "commit");
813 if (sout_save_len
> 0)
815 smux_parse_set (sout_save_buff
, sout_save_len
, rollback
? FREE
: COMMIT
);
819 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len
);
823 /* YYY: this strange code has to solve the "slow peer"
824 problem: When agent sends SMUX_SOUT message it doesn't
825 wait any responce and may send some next message to
826 subagent. Then the peer in 'smux_read()' will recieve
827 from socket the 'concatenated' buffer, contaning both
828 SMUX_SOUT message and the next one
829 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
830 the buffer is longer than 3 ( length of SMUX_SOUT ), we
831 must process the rest of it. This effect may be observed
832 if 'debug_smux' is set to '1' */
834 len
= len_income
- 3;
839 /* SMUX_GETRSP message is invalid for us. */
840 zlog_warn ("SMUX_GETRSP received: resetting connection.");
844 /* Close SMUX connection. */
846 zlog_debug ("SMUX_CLOSE");
847 smux_parse_close (ptr
, len
);
851 /* This is response for register message. */
853 zlog_debug ("SMUX_RRSP");
854 smux_parse_rrsp (ptr
, len
);
857 /* Exact request for object id. */
859 zlog_debug ("SMUX_GET");
860 smux_parse_get (ptr
, len
, 1);
863 /* Next request for object id. */
865 zlog_debug ("SMUX_GETNEXT");
866 smux_parse_get (ptr
, len
, 0);
869 /* SMUX_SET is supported with some limitations. */
871 zlog_debug ("SMUX_SET");
873 /* save the data for future SMUX_SOUT */
874 memcpy (sout_save_buff
, ptr
, len
);
876 smux_parse_set (ptr
, len
, RESERVE1
);
879 zlog_info ("Unknown type: %d", type
);
885 /* SMUX message read function. */
887 smux_read (struct thread
*t
)
891 u_char buf
[SMUXMAXPKTSIZE
];
895 sock
= THREAD_FD (t
);
896 smux_read_thread
= NULL
;
899 zlog_debug ("SMUX read start");
901 /* Read message from SMUX socket. */
902 len
= recv (sock
, buf
, SMUXMAXPKTSIZE
, 0);
906 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno
));
909 smux_event (SMUX_CONNECT
, 0);
915 zlog_warn ("SMUX connection closed: %d", sock
);
918 smux_event (SMUX_CONNECT
, 0);
923 zlog_debug ("SMUX read len: %d", len
);
925 /* Parse the message. */
926 ret
= smux_parse (buf
, len
);
932 smux_event (SMUX_CONNECT
, 0);
936 /* Regiser read thread. */
937 smux_event (SMUX_READ
, sock
);
949 u_char progname
[] = QUAGGA_PROGNAME
"-" QUAGGA_VERSION
;
953 smux_oid_dump ("SMUX open oid", smux_oid
, smux_oid_len
);
954 zlog_debug ("SMUX open progname: %s", progname
);
955 zlog_debug ("SMUX open password: %s", smux_passwd
);
961 /* SMUX Header. As placeholder. */
962 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_OPEN
, 0);
966 ptr
= asn_build_int (ptr
, &len
,
967 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
968 &version
, sizeof (version
));
970 /* SMUX connection oid. */
971 ptr
= asn_build_objid (ptr
, &len
,
973 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
974 smux_oid
, smux_oid_len
);
976 /* SMUX connection description. */
977 ptr
= asn_build_string (ptr
, &len
,
979 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
980 progname
, strlen (progname
));
982 /* SMUX connection password. */
983 ptr
= asn_build_string (ptr
, &len
,
985 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
986 (u_char
*)smux_passwd
, strlen (smux_passwd
));
988 /* Fill in real SMUX header. We exclude ASN header size (2). */
990 asn_build_header (buf
, &len
, (u_char
) SMUX_OPEN
, (ptr
- buf
) - 2);
992 return send (sock
, buf
, (ptr
- buf
), 0);
996 smux_trap (const oid
*name
, size_t namelen
,
997 const oid
*iname
, size_t inamelen
,
998 const struct trap_object
*trapobj
, size_t trapobjlen
,
999 unsigned int tick
, u_char sptrap
)
1005 struct in_addr addr
;
1013 /* When SMUX connection is not established. */
1018 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_TRAP
, 0);
1020 /* Sub agent enterprise oid. */
1021 ptr
= asn_build_objid (ptr
, &len
,
1023 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1024 smux_oid
, smux_oid_len
);
1028 ptr
= asn_build_string (ptr
, &len
,
1030 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_IPADDRESS
),
1031 (u_char
*)&addr
, sizeof (addr
));
1033 /* Generic trap integer. */
1034 val
= SNMP_TRAP_ENTERPRISESPECIFIC
;
1035 ptr
= asn_build_int (ptr
, &len
,
1036 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1037 (long *)&val
, sizeof (val
));
1039 /* Specific trap integer. */
1041 ptr
= asn_build_int (ptr
, &len
,
1042 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1043 (long *)&val
, sizeof (val
));
1045 /* Timeticks timestamp. */
1047 ptr
= asn_build_unsigned_int (ptr
, &len
,
1048 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_TIMETICKS
),
1049 &val
, sizeof (val
));
1053 ptr
= asn_build_sequence (ptr
, &len
,
1054 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1058 /* Iteration for each objects. */
1060 for (i
= 0; i
< trapobjlen
; i
++)
1063 oid oid
[MAX_OID_LEN
];
1070 if (trapobj
[i
].namelen
> 0)
1072 oid_copy (oid
, name
, namelen
);
1073 oid_copy (oid
+ namelen
, trapobj
[i
].name
, trapobj
[i
].namelen
);
1074 oid_copy (oid
+ namelen
+ trapobj
[i
].namelen
, iname
, inamelen
);
1075 oid_len
= namelen
+ trapobj
[i
].namelen
+ inamelen
;
1079 oid_copy (oid
, name
, namelen
);
1080 oid_copy (oid
+ namelen
, trapobj
[i
].name
, trapobj
[i
].namelen
* (-1));
1081 oid_len
= namelen
+ trapobj
[i
].namelen
* (-1) ;
1086 smux_oid_dump ("Trap", name
, namelen
);
1087 if (trapobj
[i
].namelen
< 0)
1088 smux_oid_dump ("Trap",
1089 trapobj
[i
].name
, (- 1) * (trapobj
[i
].namelen
));
1092 smux_oid_dump ("Trap", trapobj
[i
].name
, (trapobj
[i
].namelen
));
1093 smux_oid_dump ("Trap", iname
, inamelen
);
1095 smux_oid_dump ("Trap", oid
, oid_len
);
1096 zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ
, (u_long
)oid_len
);
1099 ret
= smux_get (oid
, &oid_len
, 1, &val_type
, &val
, &val_len
);
1102 zlog_debug ("smux_get result %d", ret
);
1105 ptr
= snmp_build_var_op (ptr
, oid
, &oid_len
,
1106 val_type
, val_len
, val
, &len
);
1109 /* Now variable size is known, fill in size */
1110 asn_build_sequence(h1
, &length
,
1111 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1114 /* Fill in size of whole sequence */
1116 asn_build_header (buf
, &len
, (u_char
) SMUX_TRAP
, (ptr
- buf
) - 2);
1118 return send (smux_sock
, buf
, (ptr
- buf
), 0);
1122 smux_register (int sock
)
1130 struct subtree
*subtree
;
1131 struct listnode
*node
, *nnode
;
1135 for (ALL_LIST_ELEMENTS (treelist
, node
, nnode
, subtree
))
1140 /* SMUX RReq Header. */
1141 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_RREQ
, 0);
1143 /* Register MIB tree. */
1144 ptr
= asn_build_objid (ptr
, &len
,
1146 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1147 subtree
->name
, subtree
->name_len
);
1151 ptr
= asn_build_int (ptr
, &len
,
1152 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1153 &priority
, sizeof (priority
));
1156 operation
= 2; /* Register R/W */
1157 ptr
= asn_build_int (ptr
, &len
,
1158 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1159 &operation
, sizeof (operation
));
1163 smux_oid_dump ("SMUX register oid", subtree
->name
, subtree
->name_len
);
1164 zlog_debug ("SMUX register priority: %ld", priority
);
1165 zlog_debug ("SMUX register operation: %ld", operation
);
1169 asn_build_header (buf
, &len
, (u_char
) SMUX_RREQ
, (ptr
- buf
) - 2);
1170 ret
= send (sock
, buf
, (ptr
- buf
), 0);
1177 /* Try to connect to SNMP agent. */
1179 smux_connect (struct thread
*t
)
1184 zlog_debug ("SMUX connect try %d", fail
+ 1);
1186 /* Clear thread poner of myself. */
1187 smux_connect_thread
= NULL
;
1189 /* Make socket. Try to connect. */
1190 smux_sock
= smux_socket ();
1193 if (++fail
< SMUX_MAX_FAILURE
)
1194 smux_event (SMUX_CONNECT
, 0);
1198 /* Send OPEN PDU. */
1199 ret
= smux_open (smux_sock
);
1202 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno
));
1205 if (++fail
< SMUX_MAX_FAILURE
)
1206 smux_event (SMUX_CONNECT
, 0);
1210 /* Send any outstanding register PDUs. */
1211 ret
= smux_register (smux_sock
);
1214 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno
));
1217 if (++fail
< SMUX_MAX_FAILURE
)
1218 smux_event (SMUX_CONNECT
, 0);
1222 /* Everything goes fine. */
1223 smux_event (SMUX_READ
, smux_sock
);
1228 /* Clear all SMUX related resources. */
1232 if (smux_read_thread
)
1234 thread_cancel (smux_read_thread
);
1235 smux_read_thread
= NULL
;
1238 if (smux_connect_thread
)
1240 thread_cancel (smux_connect_thread
);
1241 smux_connect_thread
= NULL
;
1254 smux_event (enum smux_event event
, int sock
)
1259 smux_connect_thread
= thread_add_event (master
, smux_connect
, NULL
, 0);
1262 smux_connect_thread
= thread_add_timer (master
, smux_connect
, NULL
, 10);
1265 smux_read_thread
= thread_add_read (master
, smux_read
, NULL
, sock
);
1273 smux_str2oid (const char *str
, oid
*oid
, size_t *oid_len
)
1289 if (! isdigit (*str
))
1292 while (isdigit (*str
))
1295 val
+= (*str
- '0');
1316 smux_oid_dup (oid
*objid
, size_t objid_len
)
1320 new = XMALLOC (MTYPE_TMP
, sizeof (oid
) * objid_len
);
1321 oid_copy (new, objid
, objid_len
);
1327 smux_peer_oid (struct vty
*vty
, const char *oid_str
, const char *passwd_str
)
1330 oid oid
[MAX_OID_LEN
];
1333 ret
= smux_str2oid (oid_str
, oid
, &oid_len
);
1336 vty_out (vty
, "object ID malformed%s", VTY_NEWLINE
);
1346 /* careful, smux_passwd might point to string constant */
1353 smux_oid
= smux_oid_dup (oid
, oid_len
);
1354 smux_oid_len
= oid_len
;
1357 smux_passwd
= strdup (passwd_str
);
1359 smux_passwd
= strdup ("");
1365 smux_header_generic (struct variable
*v
, oid
*name
, size_t *length
, int exact
,
1366 size_t *var_len
, WriteMethod
**write_method
)
1368 oid fulloid
[MAX_OID_LEN
];
1371 oid_copy (fulloid
, v
->name
, v
->namelen
);
1372 fulloid
[v
->namelen
] = 0;
1373 /* Check against full instance. */
1374 ret
= oid_compare (name
, *length
, fulloid
, v
->namelen
+ 1);
1376 /* Check single instance. */
1377 if ((exact
&& (ret
!= 0)) || (!exact
&& (ret
>= 0)))
1378 return MATCH_FAILED
;
1380 /* In case of getnext, fill in full instance. */
1381 memcpy (name
, fulloid
, (v
->namelen
+ 1) * sizeof (oid
));
1382 *length
= v
->namelen
+ 1;
1385 *var_len
= sizeof(long); /* default to 'long' results */
1387 return MATCH_SUCCEEDED
;
1391 smux_peer_default (void)
1399 /* careful, smux_passwd might be pointing at string constant */
1412 "SNMP MUX protocol settings\n"
1413 "SNMP MUX peer settings\n"
1414 "Object ID used in SMUX peering\n")
1416 if (smux_peer_oid (vty
, argv
[0], NULL
) == 0)
1425 DEFUN (smux_peer_password
,
1426 smux_peer_password_cmd
,
1427 "smux peer OID PASSWORD",
1428 "SNMP MUX protocol settings\n"
1429 "SNMP MUX peer settings\n"
1430 "SMUX peering object ID\n"
1431 "SMUX peering password\n")
1433 if (smux_peer_oid (vty
, argv
[0], argv
[1]) == 0)
1442 DEFUN (no_smux_peer
,
1446 "SNMP MUX protocol settings\n"
1447 "SNMP MUX peer settings\n")
1450 return smux_peer_default ();
1453 ALIAS (no_smux_peer
,
1454 no_smux_peer_oid_cmd
,
1457 "SNMP MUX protocol settings\n"
1458 "SNMP MUX peer settings\n"
1459 "SMUX peering object ID\n")
1461 ALIAS (no_smux_peer
,
1462 no_smux_peer_oid_password_cmd
,
1463 "no smux peer OID PASSWORD",
1465 "SNMP MUX protocol settings\n"
1466 "SNMP MUX peer settings\n"
1467 "SMUX peering object ID\n"
1468 "SMUX peering password\n")
1471 config_write_smux (struct vty
*vty
)
1478 vty_out (vty
, "smux peer ");
1479 for (i
= 0; i
< smux_oid_len
; i
++)
1481 vty_out (vty
, "%s%d", first
? "" : ".", (int) smux_oid
[i
]);
1484 vty_out (vty
, " %s%s", smux_passwd
, VTY_NEWLINE
);
1489 /* Register subtree to smux master tree. */
1491 smux_register_mib (const char *descr
, struct variable
*var
,
1492 size_t width
, int num
,
1493 oid name
[], size_t namelen
)
1495 struct subtree
*tree
;
1497 tree
= (struct subtree
*)malloc(sizeof(struct subtree
));
1498 oid_copy (tree
->name
, name
, namelen
);
1499 tree
->name_len
= namelen
;
1500 tree
->variables
= var
;
1501 tree
->variables_num
= num
;
1502 tree
->variables_width
= width
;
1503 tree
->registered
= 0;
1504 listnode_add_sort(treelist
, tree
);
1507 /* Compare function to keep treelist sorted */
1509 smux_tree_cmp(struct subtree
*tree1
, struct subtree
*tree2
)
1511 return oid_compare(tree1
->name
, tree1
->name_len
,
1512 tree2
->name
, tree2
->name_len
);
1515 /* Initialize some values then schedule first SMUX connection. */
1517 smux_init (struct thread_master
*tm
)
1519 /* copy callers thread master */
1522 /* Make MIB tree. */
1523 treelist
= list_new();
1524 treelist
->cmp
= (int (*)(void *, void *))smux_tree_cmp
;
1526 /* Install commands. */
1527 install_node (&smux_node
, config_write_smux
);
1529 install_element (CONFIG_NODE
, &smux_peer_cmd
);
1530 install_element (CONFIG_NODE
, &smux_peer_password_cmd
);
1531 install_element (CONFIG_NODE
, &no_smux_peer_cmd
);
1532 install_element (CONFIG_NODE
, &no_smux_peer_oid_cmd
);
1533 install_element (CONFIG_NODE
, &no_smux_peer_oid_password_cmd
);
1539 /* Close any existing connections. */
1542 /* Schedule first connection. */
1543 smux_event (SMUX_SCHEDULE
, 0);
1545 #endif /* HAVE_SNMP */