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
;
447 for (node
= treelist
->head
; node
; node
= node
->next
)
449 subtree
= node
->data
;
450 subresult
= oid_compare_part (reqid
, *reqid_len
,
451 subtree
->name
, subtree
->name_len
);
453 /* Subtree matched. */
456 /* Prepare suffix. */
457 suffix
= reqid
+ subtree
->name_len
;
458 suffix_len
= *reqid_len
- subtree
->name_len
;
461 /* Check variables. */
462 for (j
= 0; j
< subtree
->variables_num
; j
++)
464 v
= &subtree
->variables
[j
];
466 /* Always check suffix */
467 result
= oid_compare_part (suffix
, suffix_len
,
468 v
->name
, v
->namelen
);
470 /* This is exact match so result must be zero. */
474 zlog_debug ("SMUX function call index is %d", v
->magic
);
476 statP
= (*v
->findVar
) (v
, suffix
, &suffix_len
, 1,
477 &val_len
, &write_method
);
481 return (*write_method
)(action
, val
, val_type
, val_len
,
482 statP
, suffix
, suffix_len
, v
);
486 return SNMP_ERR_READONLY
;
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_get (oid
*reqid
, size_t *reqid_len
, int exact
,
502 u_char
*val_type
,void **val
, size_t *val_len
)
505 struct subtree
*subtree
;
511 WriteMethod
*write_method
=NULL
;
512 struct listnode
*node
;
515 for (node
= treelist
->head
; node
; node
= node
->next
)
517 subtree
= node
->data
;
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
;
584 /* Save incoming request. */
585 oid_copy (save
, reqid
, *reqid_len
);
586 savelen
= *reqid_len
;
589 for (node
= treelist
->head
; node
; node
= node
->next
)
591 subtree
= node
->data
;
592 subresult
= oid_compare_part (reqid
, *reqid_len
,
593 subtree
->name
, subtree
->name_len
);
595 /* If request is in the tree. The agent has to make sure we
596 only receive requests we have registered for. */
597 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
598 behave as if it manages the whole SNMP MIB tree itself. It's the
599 duty of the master agent to collect the best answer and return it
600 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
601 :-). ucd-snmp really behaves bad here as it actually might ask
602 multiple times for the same GETNEXT request as it throws away the
603 answer when it expects it in a different subtree and might come
604 back later with the very same request. --jochen */
608 /* Prepare suffix. */
609 suffix
= reqid
+ subtree
->name_len
;
610 suffix_len
= *reqid_len
- subtree
->name_len
;
613 oid_copy(reqid
, subtree
->name
, subtree
->name_len
);
614 *reqid_len
= subtree
->name_len
;
616 for (j
= 0; j
< subtree
->variables_num
; j
++)
619 v
= &subtree
->variables
[j
];
621 /* Next then check result >= 0. */
623 result
= oid_compare_part (suffix
, suffix_len
,
624 v
->name
, v
->namelen
);
629 zlog_debug ("SMUX function call index is %d", v
->magic
);
632 oid_copy(suffix
, v
->name
, v
->namelen
);
633 suffix_len
= v
->namelen
;
635 *val
= (*v
->findVar
) (v
, suffix
, &suffix_len
, exact
,
636 val_len
, &write_method
);
637 *reqid_len
= suffix_len
+ subtree
->name_len
;
647 memcpy (reqid
, save
, savelen
* sizeof(oid
));
648 *reqid_len
= savelen
;
650 return SNMP_ERR_NOSUCHNAME
;
653 /* GET message header. */
655 smux_parse_get_header (char *ptr
, size_t *len
, long *reqid
)
662 ptr
= asn_parse_int (ptr
, len
, &type
, reqid
, sizeof (*reqid
));
665 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid
, (int) *len
);
668 ptr
= asn_parse_int (ptr
, len
, &type
, &errstat
, sizeof (errstat
));
671 zlog_debug ("SMUX GET errstat %ld len: %ld", errstat
, *len
);
674 ptr
= asn_parse_int (ptr
, len
, &type
, &errindex
, sizeof (errindex
));
677 zlog_debug ("SMUX GET errindex %ld len: %ld", errindex
, *len
);
683 smux_parse_set (char *ptr
, size_t len
, int action
)
686 oid oid
[MAX_OID_LEN
];
694 zlog_debug ("SMUX SET(%s) message parse: len %ld",
695 (RESERVE1
== action
) ? "RESERVE1" : ((FREE
== action
) ? "FREE" : "COMMIT"),
698 /* Parse SET message header. */
699 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
701 /* Parse SET message object ID. */
702 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, &val_len
, &val_type
, &val
);
704 ret
= smux_set (oid
, &oid_len
, val_type
, val
, val_len
, action
);
706 zlog_debug ("SMUX SET ret %d", ret
);
709 if (RESERVE1
== action
)
710 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
714 smux_parse_get (char *ptr
, size_t len
, int exact
)
717 oid oid
[MAX_OID_LEN
];
725 zlog_debug ("SMUX GET message parse: len %ld", len
);
727 /* Parse GET message header. */
728 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
730 /* Parse GET message object ID. We needn't the value come */
731 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, NULL
, NULL
, NULL
);
733 /* Traditional getstatptr. */
735 ret
= smux_get (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
737 ret
= smux_getnext (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
741 smux_getresp_send (oid
, oid_len
, reqid
, 0, 0, val_type
, val
, val_len
);
743 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
746 /* Parse SMUX_CLOSE message. */
748 smux_parse_close (char *ptr
, int len
)
754 reason
= (reason
<< 8) | (long) *ptr
;
757 zlog_info ("SMUX_CLOSE with reason: %ld", reason
);
760 /* SMUX_RRSP message. */
762 smux_parse_rrsp (char *ptr
, size_t len
)
767 ptr
= asn_parse_int (ptr
, &len
, &val
, &errstat
, sizeof (errstat
));
770 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val
, errstat
);
773 /* Parse SMUX message. */
775 smux_parse (char *ptr
, size_t len
)
777 /* This buffer we'll use for SOUT message. We could allocate it with
778 malloc and save only static pointer/lenght, but IMHO static
779 buffer is a faster solusion. */
780 static u_char sout_save_buff
[SMUXMAXPKTSIZE
];
781 static int sout_save_len
= 0;
783 int len_income
= len
; /* see note below: YYY */
787 rollback
= ptr
[2]; /* important only for SMUX_SOUT */
789 process_rest
: /* see note below: YYY */
791 /* Parse SMUX message type and subsequent length. */
792 ptr
= asn_parse_header (ptr
, &len
, &type
);
795 zlog_debug ("SMUX message received type: %d rest len: %ld", type
, len
);
800 /* Open must be not send from SNMP agent. */
801 zlog_warn ("SMUX_OPEN received: resetting connection.");
805 /* SMUX_RREQ message is invalid for us. */
806 zlog_warn ("SMUX_RREQ received: resetting connection.");
810 /* SMUX_SOUT message is now valied for us. */
812 zlog_debug ("SMUX_SOUT(%s)", rollback
? "rollback" : "commit");
814 if (sout_save_len
> 0)
816 smux_parse_set (sout_save_buff
, sout_save_len
, rollback
? FREE
: COMMIT
);
820 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len
);
824 /* YYY: this strange code has to solve the "slow peer"
825 problem: When agent sends SMUX_SOUT message it doesn't
826 wait any responce and may send some next message to
827 subagent. Then the peer in 'smux_read()' will recieve
828 from socket the 'concatenated' buffer, contaning both
829 SMUX_SOUT message and the next one
830 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
831 the buffer is longer than 3 ( length of SMUX_SOUT ), we
832 must process the rest of it. This effect may be observed
833 if 'debug_smux' is set to '1' */
835 len
= len_income
- 3;
840 /* SMUX_GETRSP message is invalid for us. */
841 zlog_warn ("SMUX_GETRSP received: resetting connection.");
845 /* Close SMUX connection. */
847 zlog_debug ("SMUX_CLOSE");
848 smux_parse_close (ptr
, len
);
852 /* This is response for register message. */
854 zlog_debug ("SMUX_RRSP");
855 smux_parse_rrsp (ptr
, len
);
858 /* Exact request for object id. */
860 zlog_debug ("SMUX_GET");
861 smux_parse_get (ptr
, len
, 1);
864 /* Next request for object id. */
866 zlog_debug ("SMUX_GETNEXT");
867 smux_parse_get (ptr
, len
, 0);
870 /* SMUX_SET is supported with some limitations. */
872 zlog_debug ("SMUX_SET");
874 /* save the data for future SMUX_SOUT */
875 memcpy (sout_save_buff
, ptr
, len
);
877 smux_parse_set (ptr
, len
, RESERVE1
);
880 zlog_info ("Unknown type: %d", type
);
886 /* SMUX message read function. */
888 smux_read (struct thread
*t
)
892 u_char buf
[SMUXMAXPKTSIZE
];
896 sock
= THREAD_FD (t
);
897 smux_read_thread
= NULL
;
900 zlog_debug ("SMUX read start");
902 /* Read message from SMUX socket. */
903 len
= recv (sock
, buf
, SMUXMAXPKTSIZE
, 0);
907 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno
));
910 smux_event (SMUX_CONNECT
, 0);
916 zlog_warn ("SMUX connection closed: %d", sock
);
919 smux_event (SMUX_CONNECT
, 0);
924 zlog_debug ("SMUX read len: %d", len
);
926 /* Parse the message. */
927 ret
= smux_parse (buf
, len
);
933 smux_event (SMUX_CONNECT
, 0);
937 /* Regiser read thread. */
938 smux_event (SMUX_READ
, sock
);
950 u_char progname
[] = QUAGGA_PROGNAME
"-" QUAGGA_VERSION
;
954 smux_oid_dump ("SMUX open oid", smux_oid
, smux_oid_len
);
955 zlog_debug ("SMUX open progname: %s", progname
);
956 zlog_debug ("SMUX open password: %s", smux_passwd
);
962 /* SMUX Header. As placeholder. */
963 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_OPEN
, 0);
967 ptr
= asn_build_int (ptr
, &len
,
968 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
969 &version
, sizeof (u_long
));
971 /* SMUX connection oid. */
972 ptr
= asn_build_objid (ptr
, &len
,
974 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
975 smux_oid
, smux_oid_len
);
977 /* SMUX connection description. */
978 ptr
= asn_build_string (ptr
, &len
,
980 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
981 progname
, strlen (progname
));
983 /* SMUX connection password. */
984 ptr
= asn_build_string (ptr
, &len
,
986 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
987 smux_passwd
, strlen (smux_passwd
));
989 /* Fill in real SMUX header. We exclude ASN header size (2). */
991 asn_build_header (buf
, &len
, (u_char
) SMUX_OPEN
, (ptr
- buf
) - 2);
993 return send (sock
, buf
, (ptr
- buf
), 0);
997 smux_trap (oid
*name
, size_t namelen
,
998 oid
*iname
, size_t inamelen
,
999 struct trap_object
*trapobj
, size_t trapobjlen
,
1000 unsigned int tick
, u_char sptrap
)
1006 struct in_addr addr
;
1014 /* When SMUX connection is not established. */
1019 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_TRAP
, 0);
1021 /* Sub agent enterprise oid. */
1022 ptr
= asn_build_objid (ptr
, &len
,
1024 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1025 smux_oid
, smux_oid_len
);
1029 ptr
= asn_build_string (ptr
, &len
,
1031 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_IPADDRESS
),
1032 (u_char
*)&addr
, sizeof (struct in_addr
));
1034 /* Generic trap integer. */
1035 val
= SNMP_TRAP_ENTERPRISESPECIFIC
;
1036 ptr
= asn_build_int (ptr
, &len
,
1037 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1038 &val
, sizeof (int));
1040 /* Specific trap integer. */
1042 ptr
= asn_build_int (ptr
, &len
,
1043 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1044 &val
, sizeof (int));
1046 /* Timeticks timestamp. */
1048 ptr
= asn_build_unsigned_int (ptr
, &len
,
1049 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_TIMETICKS
),
1050 &val
, sizeof (int));
1054 ptr
= asn_build_sequence (ptr
, &len
,
1055 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1059 /* Iteration for each objects. */
1061 for (i
= 0; i
< trapobjlen
; i
++)
1064 oid oid
[MAX_OID_LEN
];
1071 oid_copy (oid
, name
, namelen
);
1072 oid_copy (oid
+ namelen
, trapobj
[i
].name
, trapobj
[i
].namelen
);
1073 oid_copy (oid
+ namelen
+ trapobj
[i
].namelen
, iname
, inamelen
);
1074 oid_len
= namelen
+ trapobj
[i
].namelen
+ inamelen
;
1077 smux_oid_dump ("Trap", oid
, oid_len
);
1079 ret
= smux_get (oid
, &oid_len
, 1, &val_type
, &val
, &val_len
);
1082 zlog_debug ("smux_get result %d", ret
);
1085 ptr
= snmp_build_var_op (ptr
, oid
, &oid_len
,
1086 val_type
, val_len
, val
, &len
);
1089 /* Now variable size is known, fill in size */
1090 asn_build_sequence(h1
, &length
,
1091 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1094 /* Fill in size of whole sequence */
1096 asn_build_header (buf
, &len
, (u_char
) SMUX_TRAP
, (ptr
- buf
) - 2);
1098 return send (smux_sock
, buf
, (ptr
- buf
), 0);
1102 smux_register (int sock
)
1110 struct subtree
*subtree
;
1111 struct listnode
*node
;
1115 for (node
= treelist
->head
; node
; node
= node
->next
)
1120 subtree
= node
->data
;
1122 /* SMUX RReq Header. */
1123 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_RREQ
, 0);
1125 /* Register MIB tree. */
1126 ptr
= asn_build_objid (ptr
, &len
,
1128 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1129 subtree
->name
, subtree
->name_len
);
1133 ptr
= asn_build_int (ptr
, &len
,
1134 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1135 &priority
, sizeof (u_long
));
1138 operation
= 2; /* Register R/W */
1139 ptr
= asn_build_int (ptr
, &len
,
1140 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1141 &operation
, sizeof (u_long
));
1145 smux_oid_dump ("SMUX register oid", subtree
->name
, subtree
->name_len
);
1146 zlog_debug ("SMUX register priority: %ld", priority
);
1147 zlog_debug ("SMUX register operation: %ld", operation
);
1151 asn_build_header (buf
, &len
, (u_char
) SMUX_RREQ
, (ptr
- buf
) - 2);
1152 ret
= send (sock
, buf
, (ptr
- buf
), 0);
1159 /* Try to connect to SNMP agent. */
1161 smux_connect (struct thread
*t
)
1166 zlog_debug ("SMUX connect try %d", fail
+ 1);
1168 /* Clear thread poner of myself. */
1169 smux_connect_thread
= NULL
;
1171 /* Make socket. Try to connect. */
1172 smux_sock
= smux_socket ();
1175 if (++fail
< SMUX_MAX_FAILURE
)
1176 smux_event (SMUX_CONNECT
, 0);
1180 /* Send OPEN PDU. */
1181 ret
= smux_open (smux_sock
);
1184 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno
));
1187 if (++fail
< SMUX_MAX_FAILURE
)
1188 smux_event (SMUX_CONNECT
, 0);
1192 /* Send any outstanding register PDUs. */
1193 ret
= smux_register (smux_sock
);
1196 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno
));
1199 if (++fail
< SMUX_MAX_FAILURE
)
1200 smux_event (SMUX_CONNECT
, 0);
1204 /* Everything goes fine. */
1205 smux_event (SMUX_READ
, smux_sock
);
1210 /* Clear all SMUX related resources. */
1214 if (smux_read_thread
)
1215 thread_cancel (smux_read_thread
);
1216 if (smux_connect_thread
)
1217 thread_cancel (smux_connect_thread
);
1229 smux_event (enum smux_event event
, int sock
)
1234 smux_connect_thread
= thread_add_event (master
, smux_connect
, NULL
, 0);
1237 smux_connect_thread
= thread_add_timer (master
, smux_connect
, NULL
, 10);
1240 smux_read_thread
= thread_add_read (master
, smux_read
, NULL
, sock
);
1248 smux_str2oid (const char *str
, oid
*oid
, size_t *oid_len
)
1264 if (! isdigit (*str
))
1267 while (isdigit (*str
))
1270 val
+= (*str
- '0');
1291 smux_oid_dup (oid
*objid
, size_t objid_len
)
1295 new = XMALLOC (MTYPE_TMP
, sizeof (oid
) * objid_len
);
1296 oid_copy (new, objid
, objid_len
);
1302 smux_peer_oid (struct vty
*vty
, const char *oid_str
, const char *passwd_str
)
1305 oid oid
[MAX_OID_LEN
];
1308 ret
= smux_str2oid (oid_str
, oid
, &oid_len
);
1311 vty_out (vty
, "object ID malformed%s", VTY_NEWLINE
);
1321 /* careful, smux_passwd might point to string constant */
1328 smux_oid
= smux_oid_dup (oid
, oid_len
);
1329 smux_oid_len
= oid_len
;
1332 smux_passwd
= strdup (passwd_str
);
1334 smux_passwd
= strdup ("");
1340 smux_header_generic (struct variable
*v
, oid
*name
, size_t *length
, int exact
,
1341 size_t *var_len
, WriteMethod
**write_method
)
1343 oid fulloid
[MAX_OID_LEN
];
1346 oid_copy (fulloid
, v
->name
, v
->namelen
);
1347 fulloid
[v
->namelen
] = 0;
1348 /* Check against full instance. */
1349 ret
= oid_compare (name
, *length
, fulloid
, v
->namelen
+ 1);
1351 /* Check single instance. */
1352 if ((exact
&& (ret
!= 0)) || (!exact
&& (ret
>= 0)))
1353 return MATCH_FAILED
;
1355 /* In case of getnext, fill in full instance. */
1356 memcpy (name
, fulloid
, (v
->namelen
+ 1) * sizeof (oid
));
1357 *length
= v
->namelen
+ 1;
1360 *var_len
= sizeof(long); /* default to 'long' results */
1362 return MATCH_SUCCEEDED
;
1366 smux_peer_default ()
1374 /* careful, smux_passwd might be pointing at string constant */
1387 "SNMP MUX protocol settings\n"
1388 "SNMP MUX peer settings\n"
1389 "Object ID used in SMUX peering\n")
1391 if (smux_peer_oid (vty
, argv
[0], NULL
) == 0)
1400 DEFUN (smux_peer_password
,
1401 smux_peer_password_cmd
,
1402 "smux peer OID PASSWORD",
1403 "SNMP MUX protocol settings\n"
1404 "SNMP MUX peer settings\n"
1405 "SMUX peering object ID\n"
1406 "SMUX peering password\n")
1408 if (smux_peer_oid (vty
, argv
[0], argv
[1]) == 0)
1417 DEFUN (no_smux_peer
,
1421 "SNMP MUX protocol settings\n"
1422 "SNMP MUX peer settings\n")
1425 return smux_peer_default ();
1428 ALIAS (no_smux_peer
,
1429 no_smux_peer_oid_cmd
,
1432 "SNMP MUX protocol settings\n"
1433 "SNMP MUX peer settings\n"
1434 "SMUX peering object ID\n")
1436 ALIAS (no_smux_peer
,
1437 no_smux_peer_oid_password_cmd
,
1438 "no smux peer OID PASSWORD",
1440 "SNMP MUX protocol settings\n"
1441 "SNMP MUX peer settings\n"
1442 "SMUX peering object ID\n"
1443 "SMUX peering password\n")
1446 config_write_smux (struct vty
*vty
)
1453 vty_out (vty
, "smux peer ");
1454 for (i
= 0; i
< smux_oid_len
; i
++)
1456 vty_out (vty
, "%s%d", first
? "" : ".", (int) smux_oid
[i
]);
1459 vty_out (vty
, " %s%s", smux_passwd
, VTY_NEWLINE
);
1464 /* Register subtree to smux master tree. */
1466 smux_register_mib (const char *descr
, struct variable
*var
,
1467 size_t width
, int num
,
1468 oid name
[], size_t namelen
)
1470 struct subtree
*tree
;
1472 tree
= (struct subtree
*)malloc(sizeof(struct subtree
));
1473 oid_copy (tree
->name
, name
, namelen
);
1474 tree
->name_len
= namelen
;
1475 tree
->variables
= var
;
1476 tree
->variables_num
= num
;
1477 tree
->variables_width
= width
;
1478 tree
->registered
= 0;
1479 listnode_add_sort(treelist
, tree
);
1485 /* Setting configuration to default. */
1486 smux_peer_default ();
1489 /* Compare function to keep treelist sorted */
1491 smux_tree_cmp(struct subtree
*tree1
, struct subtree
*tree2
)
1493 return oid_compare(tree1
->name
, tree1
->name_len
,
1494 tree2
->name
, tree2
->name_len
);
1497 /* Initialize some values then schedule first SMUX connection. */
1499 smux_init (struct thread_master
*tm
)
1501 /* copy callers thread master */
1504 /* Make MIB tree. */
1505 treelist
= list_new();
1506 treelist
->cmp
= (int (*)(void *, void *))smux_tree_cmp
;
1508 /* Install commands. */
1509 install_node (&smux_node
, config_write_smux
);
1511 install_element (CONFIG_NODE
, &smux_peer_cmd
);
1512 install_element (CONFIG_NODE
, &smux_peer_password_cmd
);
1513 install_element (CONFIG_NODE
, &no_smux_peer_cmd
);
1514 install_element (CONFIG_NODE
, &no_smux_peer_oid_cmd
);
1515 install_element (CONFIG_NODE
, &no_smux_peer_oid_password_cmd
);
1521 /* Schedule first connection. */
1522 smux_event (SMUX_SCHEDULE
, 0);
1524 #endif /* HAVE_SNMP */