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
;
58 /* SMUX default oid. */
59 oid
*smux_default_oid
;
60 size_t smux_default_oid_len
;
64 char *smux_default_passwd
= "";
66 /* SMUX read threads. */
67 struct thread
*smux_read_thread
;
69 /* SMUX connect thrads. */
70 struct thread
*smux_connect_thread
;
72 /* SMUX debug flag. */
75 /* SMUX failure count. */
79 struct cmd_node smux_node
=
82 "" /* SMUX has no interface. */
86 static struct thread_master
*master
;
89 oid_copy (void *dest
, void *src
, size_t size
)
91 return memcpy (dest
, src
, size
* sizeof (oid
));
95 oid2in_addr (oid oid
[], int len
, struct in_addr
*addr
)
103 pnt
= (u_char
*) addr
;
105 for (i
= 0; i
< len
; i
++)
110 oid_copy_addr (oid oid
[], struct in_addr
*addr
, int len
)
118 pnt
= (u_char
*) addr
;
120 for (i
= 0; i
< len
; i
++)
125 oid_compare (oid
*o1
, int o1_len
, oid
*o2
, int o2_len
)
129 for (i
= 0; i
< min (o1_len
, o2_len
); i
++)
133 else if (o1
[i
] > o2
[i
])
145 oid_compare_part (oid
*o1
, int o1_len
, oid
*o2
, int o2_len
)
149 for (i
= 0; i
< min (o1_len
, o2_len
); i
++)
153 else if (o1
[i
] > o2
[i
])
163 smux_oid_dump (char *prefix
, oid
*oid
, size_t oid_len
)
167 char buf
[MAX_OID_LEN
* 3];
171 for (i
= 0; i
< oid_len
; i
++)
173 sprintf (buf
+ strlen (buf
), "%s%d", first
? "" : ".", (int) oid
[i
]);
176 zlog_info ("%s: %s", prefix
, buf
);
184 struct addrinfo hints
, *res0
, *res
;
187 struct sockaddr_in serv
;
193 memset(&hints
, 0, sizeof(hints
));
194 hints
.ai_family
= PF_UNSPEC
;
195 hints
.ai_socktype
= SOCK_STREAM
;
196 gai
= getaddrinfo(NULL
, "smux", &hints
, &res0
);
197 if (gai
== EAI_SERVICE
)
199 char servbuf
[NI_MAXSERV
];
200 sprintf(servbuf
,"%d",SMUX_PORT_DEFAULT
);
201 servbuf
[sizeof (servbuf
) - 1] = '\0';
202 gai
= getaddrinfo(NULL
, servbuf
, &hints
, &res0
);
206 zlog_warn("Cannot locate loopback service smux");
209 for(res
=res0
; res
; res
=res
->ai_next
)
211 if (res
->ai_family
!= AF_INET
213 && res
->ai_family
!= AF_INET6
214 #endif /* HAVE_IPV6 */
218 sock
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
221 sockopt_reuseaddr (sock
);
222 sockopt_reuseport (sock
);
223 ret
= connect (sock
, res
->ai_addr
, res
->ai_addrlen
);
234 zlog_warn ("Can't connect to SNMP agent with SMUX");
236 sock
= socket (AF_INET
, SOCK_STREAM
, 0);
239 zlog_warn ("Can't make socket for SNMP");
243 memset (&serv
, 0, sizeof (struct sockaddr_in
));
244 serv
.sin_family
= AF_INET
;
246 serv
.sin_len
= sizeof (struct sockaddr_in
);
247 #endif /* HAVE_SIN_LEN */
249 sp
= getservbyname ("smux", "tcp");
251 serv
.sin_port
= sp
->s_port
;
253 serv
.sin_port
= htons (SMUX_PORT_DEFAULT
);
255 serv
.sin_addr
.s_addr
= htonl (INADDR_LOOPBACK
);
257 sockopt_reuseaddr (sock
);
258 sockopt_reuseport (sock
);
260 ret
= connect (sock
, (struct sockaddr
*) &serv
, sizeof (struct sockaddr_in
));
265 zlog_warn ("Can't connect to SNMP agent with SMUX");
273 smux_getresp_send (oid objid
[], size_t objid_len
, long reqid
, long errstat
,
274 long errindex
, u_char val_type
, void *arg
, size_t arg_len
)
278 u_char
*ptr
, *h1
, *h1e
, *h2
, *h2e
;
287 zlog_info ("SMUX GETRSP send");
288 zlog_info ("SMUX GETRSP reqid: %ld", reqid
);
292 /* Place holder h1 for complete sequence */
293 ptr
= asn_build_sequence (ptr
, &len
, (u_char
) SMUX_GETRSP
, 0);
296 ptr
= asn_build_int (ptr
, &len
,
297 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
298 &reqid
, sizeof (reqid
));
301 zlog_info ("SMUX GETRSP errstat: %ld", errstat
);
303 ptr
= asn_build_int (ptr
, &len
,
304 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
305 &errstat
, sizeof (errstat
));
307 zlog_info ("SMUX GETRSP errindex: %ld", errindex
);
309 ptr
= asn_build_int (ptr
, &len
,
310 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
311 &errindex
, sizeof (errindex
));
314 /* Place holder h2 for one variable */
315 ptr
= asn_build_sequence (ptr
, &len
,
316 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
320 ptr
= snmp_build_var_op (ptr
, objid
, &objid_len
,
321 val_type
, arg_len
, arg
, &len
);
323 /* Now variable size is known, fill in size */
324 asn_build_sequence(h2
,&length
,(u_char
)(ASN_SEQUENCE
|ASN_CONSTRUCTOR
),ptr
-h2e
);
326 /* Fill in size of whole sequence */
327 asn_build_sequence(h1
,&length
,(u_char
)SMUX_GETRSP
,ptr
-h1e
);
330 zlog_info ("SMUX getresp send: %d", ptr
- buf
);
332 ret
= send (smux_sock
, buf
, (ptr
- buf
), 0);
336 smux_var (char *ptr
, int len
, oid objid
[], size_t *objid_len
,
338 u_char
*var_val_type
,
347 zlog_info ("SMUX var parse: len %d", len
);
350 ptr
= asn_parse_header (ptr
, &len
, &type
);
354 zlog_info ("SMUX var parse: type %d len %d", type
, len
);
355 zlog_info ("SMUX var parse: type must be %d",
356 (ASN_SEQUENCE
| ASN_CONSTRUCTOR
));
359 /* Parse var option. */
360 *objid_len
= MAX_OID_LEN
;
361 ptr
= snmp_parse_var_op(ptr
, objid
, objid_len
, &val_type
,
362 &val_len
, &val
, &len
);
365 *var_val_len
= val_len
;
368 *var_value
= (void*) val
;
371 *var_val_type
= val_type
;
373 /* Requested object id length is objid_len. */
375 smux_oid_dump ("Request OID", objid
, *objid_len
);
378 zlog_info ("SMUX val_type: %d", val_type
);
380 /* Check request value type. */
385 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
387 zlog_info ("ASN_NULL");
391 zlog_info ("ASN_INTEGER");
397 zlog_info ("ASN_COUNTER");
400 zlog_info ("ASN_COUNTER64");
403 zlog_info ("ASN_IPADDRESS");
406 zlog_info ("ASN_OCTET_STR");
411 zlog_info ("ASN_OPAQUE");
413 case SNMP_NOSUCHOBJECT
:
414 zlog_info ("SNMP_NOSUCHOBJECT");
416 case SNMP_NOSUCHINSTANCE
:
417 zlog_info ("SNMP_NOSUCHINSTANCE");
419 case SNMP_ENDOFMIBVIEW
:
420 zlog_info ("SNMP_ENDOFMIBVIEW");
423 zlog_info ("ASN_BIT_STR");
426 zlog_info ("Unknown type");
432 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
433 ucd-snmp smux and as such suppose, that the peer receives in the message
434 only one variable. Fortunately, IBM seems to do the same in AIX. */
437 smux_set (oid
*reqid
, size_t *reqid_len
,
438 u_char val_type
, void *val
, size_t val_len
, int action
)
441 struct subtree
*subtree
;
447 u_char
*statP
= NULL
;
448 WriteMethod
*write_method
= NULL
;
449 struct listnode
*node
;
452 for (node
= treelist
->head
; node
; node
= node
->next
)
454 subtree
= node
->data
;
455 subresult
= oid_compare_part (reqid
, *reqid_len
,
456 subtree
->name
, subtree
->name_len
);
458 /* Subtree matched. */
461 /* Prepare suffix. */
462 suffix
= reqid
+ subtree
->name_len
;
463 suffix_len
= *reqid_len
- subtree
->name_len
;
466 /* Check variables. */
467 for (j
= 0; j
< subtree
->variables_num
; j
++)
469 v
= &subtree
->variables
[j
];
471 /* Always check suffix */
472 result
= oid_compare_part (suffix
, suffix_len
,
473 v
->name
, v
->namelen
);
475 /* This is exact match so result must be zero. */
479 zlog_info ("SMUX function call index is %d", v
->magic
);
481 statP
= (*v
->findVar
) (v
, suffix
, &suffix_len
, 1,
482 &val_len
, &write_method
);
486 return (*write_method
)(action
, val
, val_type
, val_len
,
487 statP
, suffix
, suffix_len
, v
);
491 return SNMP_ERR_READONLY
;
495 /* If above execution is failed or oid is small (so
496 there is no further match). */
498 return SNMP_ERR_NOSUCHNAME
;
502 return SNMP_ERR_NOSUCHNAME
;
506 smux_get (oid
*reqid
, size_t *reqid_len
, int exact
,
507 u_char
*val_type
,void **val
, size_t *val_len
)
510 struct subtree
*subtree
;
516 WriteMethod
*write_method
=NULL
;
517 struct listnode
*node
;
520 for (node
= treelist
->head
; node
; node
= node
->next
)
522 subtree
= node
->data
;
523 subresult
= oid_compare_part (reqid
, *reqid_len
,
524 subtree
->name
, subtree
->name_len
);
526 /* Subtree matched. */
529 /* Prepare suffix. */
530 suffix
= reqid
+ subtree
->name_len
;
531 suffix_len
= *reqid_len
- subtree
->name_len
;
534 /* Check variables. */
535 for (j
= 0; j
< subtree
->variables_num
; j
++)
537 v
= &subtree
->variables
[j
];
539 /* Always check suffix */
540 result
= oid_compare_part (suffix
, suffix_len
,
541 v
->name
, v
->namelen
);
543 /* This is exact match so result must be zero. */
547 zlog_info ("SMUX function call index is %d", v
->magic
);
549 *val
= (*v
->findVar
) (v
, suffix
, &suffix_len
, exact
,
550 val_len
, &write_method
);
552 /* There is no instance. */
554 return SNMP_NOSUCHINSTANCE
;
556 /* Call is suceed. */
562 /* If above execution is failed or oid is small (so
563 there is no further match). */
565 return SNMP_ERR_NOSUCHNAME
;
569 return SNMP_ERR_NOSUCHNAME
;
573 smux_getnext (oid
*reqid
, size_t *reqid_len
, int exact
,
574 u_char
*val_type
,void **val
, size_t *val_len
)
577 oid save
[MAX_OID_LEN
];
579 struct subtree
*subtree
;
585 WriteMethod
*write_method
=NULL
;
586 struct listnode
*node
;
589 /* Save incoming request. */
590 oid_copy (save
, reqid
, *reqid_len
);
591 savelen
= *reqid_len
;
594 for (node
= treelist
->head
; node
; node
= node
->next
)
596 subtree
= node
->data
;
597 subresult
= oid_compare_part (reqid
, *reqid_len
,
598 subtree
->name
, subtree
->name_len
);
600 /* If request is in the tree. The agent has to make sure we
601 only receive requests we have registered for. */
602 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
603 behave as if it manages the whole SNMP MIB tree itself. It's the
604 duty of the master agent to collect the best answer and return it
605 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
606 :-). ucd-snmp really behaves bad here as it actually might ask
607 multiple times for the same GETNEXT request as it throws away the
608 answer when it expects it in a different subtree and might come
609 back later with the very same request. --jochen */
613 /* Prepare suffix. */
614 suffix
= reqid
+ subtree
->name_len
;
615 suffix_len
= *reqid_len
- subtree
->name_len
;
618 oid_copy(reqid
, subtree
->name
, subtree
->name_len
);
619 *reqid_len
= subtree
->name_len
;
621 for (j
= 0; j
< subtree
->variables_num
; j
++)
624 v
= &subtree
->variables
[j
];
626 /* Next then check result >= 0. */
628 result
= oid_compare_part (suffix
, suffix_len
,
629 v
->name
, v
->namelen
);
634 zlog_info ("SMUX function call index is %d", v
->magic
);
637 oid_copy(suffix
, v
->name
, v
->namelen
);
638 suffix_len
= v
->namelen
;
640 *val
= (*v
->findVar
) (v
, suffix
, &suffix_len
, exact
,
641 val_len
, &write_method
);
642 *reqid_len
= suffix_len
+ subtree
->name_len
;
652 memcpy (reqid
, save
, savelen
* sizeof(oid
));
653 *reqid_len
= savelen
;
655 return SNMP_ERR_NOSUCHNAME
;
658 /* GET message header. */
660 smux_parse_get_header (char *ptr
, size_t *len
, long *reqid
)
667 ptr
= asn_parse_int (ptr
, len
, &type
, reqid
, sizeof (*reqid
));
670 zlog_info ("SMUX GET reqid: %d len: %d", (int) *reqid
, (int) *len
);
673 ptr
= asn_parse_int (ptr
, len
, &type
, &errstat
, sizeof (errstat
));
676 zlog_info ("SMUX GET errstat %ld len: %d", errstat
, *len
);
679 ptr
= asn_parse_int (ptr
, len
, &type
, &errindex
, sizeof (errindex
));
682 zlog_info ("SMUX GET errindex %ld len: %d", errindex
, *len
);
688 smux_parse_set (char *ptr
, size_t len
, int action
)
691 oid oid
[MAX_OID_LEN
];
699 zlog_info ("SMUX SET(%s) message parse: len %d",
700 (RESERVE1
== action
) ? "RESERVE1" : ((FREE
== action
) ? "FREE" : "COMMIT"),
703 /* Parse SET message header. */
704 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
706 /* Parse SET message object ID. */
707 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, &val_len
, &val_type
, &val
);
709 ret
= smux_set (oid
, &oid_len
, val_type
, val
, val_len
, action
);
711 zlog_info ("SMUX SET ret %d", ret
);
714 if (RESERVE1
== action
)
715 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
719 smux_parse_get (char *ptr
, size_t len
, int exact
)
722 oid oid
[MAX_OID_LEN
];
730 zlog_info ("SMUX GET message parse: len %d", len
);
732 /* Parse GET message header. */
733 ptr
= smux_parse_get_header (ptr
, &len
, &reqid
);
735 /* Parse GET message object ID. We needn't the value come */
736 ptr
= smux_var (ptr
, len
, oid
, &oid_len
, NULL
, NULL
, NULL
);
738 /* Traditional getstatptr. */
740 ret
= smux_get (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
742 ret
= smux_getnext (oid
, &oid_len
, exact
, &val_type
, &val
, &val_len
);
746 smux_getresp_send (oid
, oid_len
, reqid
, 0, 0, val_type
, val
, val_len
);
748 smux_getresp_send (oid
, oid_len
, reqid
, ret
, 3, ASN_NULL
, NULL
, 0);
751 /* Parse SMUX_CLOSE message. */
753 smux_parse_close (char *ptr
, int len
)
759 reason
= (reason
<< 8) | (long) *ptr
;
762 zlog_info ("SMUX_CLOSE with reason: %ld", reason
);
765 /* SMUX_RRSP message. */
767 smux_parse_rrsp (char *ptr
, int len
)
772 ptr
= asn_parse_int (ptr
, &len
, &val
, &errstat
, sizeof (errstat
));
775 zlog_info ("SMUX_RRSP value: %d errstat: %ld", val
, errstat
);
778 /* Parse SMUX message. */
780 smux_parse (char *ptr
, int len
)
782 /* This buffer we'll use for SOUT message. We could allocate it with
783 malloc and save only static pointer/lenght, but IMHO static
784 buffer is a faster solusion. */
785 static u_char sout_save_buff
[SMUXMAXPKTSIZE
];
786 static int sout_save_len
= 0;
788 int len_income
= len
; /* see note below: YYY */
792 rollback
= ptr
[2]; /* important only for SMUX_SOUT */
794 process_rest
: /* see note below: YYY */
796 /* Parse SMUX message type and subsequent length. */
797 ptr
= asn_parse_header (ptr
, &len
, &type
);
800 zlog_info ("SMUX message received type: %d rest len: %d", type
, len
);
805 /* Open must be not send from SNMP agent. */
806 zlog_warn ("SMUX_OPEN received: resetting connection.");
810 /* SMUX_RREQ message is invalid for us. */
811 zlog_warn ("SMUX_RREQ received: resetting connection.");
815 /* SMUX_SOUT message is now valied for us. */
817 zlog_info ("SMUX_SOUT(%s)", rollback
? "rollback" : "commit");
819 if (sout_save_len
> 0)
821 smux_parse_set (sout_save_buff
, sout_save_len
, rollback
? FREE
: COMMIT
);
825 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len
);
829 /* YYY: this strange code has to solve the "slow peer"
830 problem: When agent sends SMUX_SOUT message it doesn't
831 wait any responce and may send some next message to
832 subagent. Then the peer in 'smux_read()' will recieve
833 from socket the 'concatenated' buffer, contaning both
834 SMUX_SOUT message and the next one
835 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
836 the buffer is longer than 3 ( length of SMUX_SOUT ), we
837 must process the rest of it. This effect may be observed
838 if 'debug_smux' is set to '1' */
840 len
= len_income
- 3;
845 /* SMUX_GETRSP message is invalid for us. */
846 zlog_warn ("SMUX_GETRSP received: resetting connection.");
850 /* Close SMUX connection. */
852 zlog_info ("SMUX_CLOSE");
853 smux_parse_close (ptr
, len
);
857 /* This is response for register message. */
859 zlog_info ("SMUX_RRSP");
860 smux_parse_rrsp (ptr
, len
);
863 /* Exact request for object id. */
865 zlog_info ("SMUX_GET");
866 smux_parse_get (ptr
, len
, 1);
869 /* Next request for object id. */
871 zlog_info ("SMUX_GETNEXT");
872 smux_parse_get (ptr
, len
, 0);
875 /* SMUX_SET is supported with some limitations. */
877 zlog_info ("SMUX_SET");
879 /* save the data for future SMUX_SOUT */
880 memcpy (sout_save_buff
, ptr
, len
);
882 smux_parse_set (ptr
, len
, RESERVE1
);
885 zlog_info ("Unknown type: %d", type
);
891 /* SMUX message read function. */
893 smux_read (struct thread
*t
)
897 u_char buf
[SMUXMAXPKTSIZE
];
901 sock
= THREAD_FD (t
);
902 smux_read_thread
= NULL
;
905 zlog_info ("SMUX read start");
907 /* Read message from SMUX socket. */
908 len
= recv (sock
, buf
, SMUXMAXPKTSIZE
, 0);
912 zlog_warn ("Can't read all SMUX packet: %s", strerror (errno
));
915 smux_event (SMUX_CONNECT
, 0);
921 zlog_warn ("SMUX connection closed: %d", sock
);
924 smux_event (SMUX_CONNECT
, 0);
929 zlog_info ("SMUX read len: %d", len
);
931 /* Parse the message. */
932 ret
= smux_parse (buf
, len
);
938 smux_event (SMUX_CONNECT
, 0);
942 /* Regiser read thread. */
943 smux_event (SMUX_READ
, sock
);
955 u_char progname
[] = QUAGGA_PROGNAME
"-" QUAGGA_VERSION
;
959 smux_oid_dump ("SMUX open oid", smux_oid
, smux_oid_len
);
960 zlog_info ("SMUX open progname: %s", progname
);
961 zlog_info ("SMUX open password: %s", smux_passwd
);
967 /* SMUX Header. As placeholder. */
968 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_OPEN
, 0);
972 ptr
= asn_build_int (ptr
, &len
,
973 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
974 &version
, sizeof (u_long
));
976 /* SMUX connection oid. */
977 ptr
= asn_build_objid (ptr
, &len
,
979 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
980 smux_oid
, smux_oid_len
);
982 /* SMUX connection description. */
983 ptr
= asn_build_string (ptr
, &len
,
985 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
986 progname
, strlen (progname
));
988 /* SMUX connection password. */
989 ptr
= asn_build_string (ptr
, &len
,
991 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
992 smux_passwd
, strlen (smux_passwd
));
994 /* Fill in real SMUX header. We exclude ASN header size (2). */
996 asn_build_header (buf
, &len
, (u_char
) SMUX_OPEN
, (ptr
- buf
) - 2);
998 return send (sock
, buf
, (ptr
- buf
), 0);
1002 smux_trap (oid
*name
, size_t namelen
,
1003 oid
*iname
, size_t inamelen
,
1004 struct trap_object
*trapobj
, size_t trapobjlen
,
1005 unsigned int tick
, u_char sptrap
)
1011 struct in_addr addr
;
1019 /* When SMUX connection is not established. */
1024 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_TRAP
, 0);
1026 /* Sub agent enterprise oid. */
1027 ptr
= asn_build_objid (ptr
, &len
,
1029 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1030 smux_oid
, smux_oid_len
);
1034 ptr
= asn_build_string (ptr
, &len
,
1036 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_IPADDRESS
),
1037 (u_char
*)&addr
, sizeof (struct in_addr
));
1039 /* Generic trap integer. */
1040 val
= SNMP_TRAP_ENTERPRISESPECIFIC
;
1041 ptr
= asn_build_int (ptr
, &len
,
1042 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1043 &val
, sizeof (int));
1045 /* Specific trap integer. */
1047 ptr
= asn_build_int (ptr
, &len
,
1048 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1049 &val
, sizeof (int));
1051 /* Timeticks timestamp. */
1053 ptr
= asn_build_unsigned_int (ptr
, &len
,
1054 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_TIMETICKS
),
1055 &val
, sizeof (int));
1059 ptr
= asn_build_sequence (ptr
, &len
,
1060 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1064 /* Iteration for each objects. */
1066 for (i
= 0; i
< trapobjlen
; i
++)
1069 oid oid
[MAX_OID_LEN
];
1076 oid_copy (oid
, name
, namelen
);
1077 oid_copy (oid
+ namelen
, trapobj
[i
].name
, trapobj
[i
].namelen
);
1078 oid_copy (oid
+ namelen
+ trapobj
[i
].namelen
, iname
, inamelen
);
1079 oid_len
= namelen
+ trapobj
[i
].namelen
+ inamelen
;
1082 smux_oid_dump ("Trap", oid
, oid_len
);
1084 ret
= smux_get (oid
, &oid_len
, 1, &val_type
, &val
, &val_len
);
1087 zlog_info ("smux_get result %d", ret
);
1090 ptr
= snmp_build_var_op (ptr
, oid
, &oid_len
,
1091 val_type
, val_len
, val
, &len
);
1094 /* Now variable size is known, fill in size */
1095 asn_build_sequence(h1
, &length
,
1096 (u_char
) (ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1099 /* Fill in size of whole sequence */
1101 asn_build_header (buf
, &len
, (u_char
) SMUX_TRAP
, (ptr
- buf
) - 2);
1103 return send (smux_sock
, buf
, (ptr
- buf
), 0);
1107 smux_register (int sock
)
1114 struct subtree
*subtree
;
1115 struct listnode
*node
;
1119 for (node
= treelist
->head
; node
; node
= node
->next
)
1124 subtree
= node
->data
;
1126 /* SMUX RReq Header. */
1127 ptr
= asn_build_header (ptr
, &len
, (u_char
) SMUX_RREQ
, 0);
1129 /* Register MIB tree. */
1130 ptr
= asn_build_objid (ptr
, &len
,
1132 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1133 subtree
->name
, subtree
->name_len
);
1137 ptr
= asn_build_int (ptr
, &len
,
1138 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1139 &priority
, sizeof (u_long
));
1142 operation
= 2; /* Register R/W */
1143 ptr
= asn_build_int (ptr
, &len
,
1144 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1145 &operation
, sizeof (u_long
));
1149 smux_oid_dump ("SMUX register oid", subtree
->name
, subtree
->name_len
);
1150 zlog_info ("SMUX register priority: %ld", priority
);
1151 zlog_info ("SMUX register operation: %ld", operation
);
1155 asn_build_header (buf
, &len
, (u_char
) SMUX_RREQ
, (ptr
- buf
) - 2);
1156 ret
= send (sock
, buf
, (ptr
- buf
), 0);
1163 /* Try to connect to SNMP agent. */
1165 smux_connect (struct thread
*t
)
1170 zlog_info ("SMUX connect try %d", fail
+ 1);
1172 /* Clear thread poner of myself. */
1173 smux_connect_thread
= NULL
;
1175 /* Make socket. Try to connect. */
1176 smux_sock
= smux_socket ();
1179 if (++fail
< SMUX_MAX_FAILURE
)
1180 smux_event (SMUX_CONNECT
, 0);
1184 /* Send OPEN PDU. */
1185 ret
= smux_open (smux_sock
);
1188 zlog_warn ("SMUX open message send failed: %s", strerror (errno
));
1191 if (++fail
< SMUX_MAX_FAILURE
)
1192 smux_event (SMUX_CONNECT
, 0);
1196 /* Send any outstanding register PDUs. */
1197 ret
= smux_register (smux_sock
);
1200 zlog_warn ("SMUX register message send failed: %s", strerror (errno
));
1203 if (++fail
< SMUX_MAX_FAILURE
)
1204 smux_event (SMUX_CONNECT
, 0);
1208 /* Everything goes fine. */
1209 smux_event (SMUX_READ
, smux_sock
);
1214 /* Clear all SMUX related resources. */
1218 if (smux_read_thread
)
1219 thread_cancel (smux_read_thread
);
1220 if (smux_connect_thread
)
1221 thread_cancel (smux_connect_thread
);
1233 smux_event (enum smux_event event
, int sock
)
1238 smux_connect_thread
= thread_add_event (master
, smux_connect
, NULL
, 0);
1241 smux_connect_thread
= thread_add_timer (master
, smux_connect
, NULL
, 10);
1244 smux_read_thread
= thread_add_read (master
, smux_read
, NULL
, sock
);
1252 smux_str2oid (char *str
, oid
*oid
, size_t *oid_len
)
1268 if (! isdigit (*str
))
1271 while (isdigit (*str
))
1274 val
+= (*str
- '0');
1295 smux_oid_dup (oid
*objid
, size_t objid_len
)
1299 new = XMALLOC (MTYPE_TMP
, sizeof (oid
) * objid_len
);
1300 oid_copy (new, objid
, objid_len
);
1306 smux_peer_oid (struct vty
*vty
, char *oid_str
, char *passwd_str
)
1309 oid oid
[MAX_OID_LEN
];
1312 ret
= smux_str2oid (oid_str
, oid
, &oid_len
);
1315 vty_out (vty
, "object ID malformed%s", VTY_NEWLINE
);
1319 if (smux_oid
&& smux_oid
!= smux_default_oid
)
1322 if (smux_passwd
&& smux_passwd
!= smux_default_passwd
)
1328 smux_oid
= smux_oid_dup (oid
, oid_len
);
1329 smux_oid_len
= oid_len
;
1332 smux_passwd
= strdup (passwd_str
);
1338 smux_header_generic (struct variable
*v
, oid
*name
, size_t *length
, int exact
,
1339 size_t *var_len
, WriteMethod
**write_method
)
1341 oid fulloid
[MAX_OID_LEN
];
1344 oid_copy (fulloid
, v
->name
, v
->namelen
);
1345 fulloid
[v
->namelen
] = 0;
1346 /* Check against full instance. */
1347 ret
= oid_compare (name
, *length
, fulloid
, v
->namelen
+ 1);
1349 /* Check single instance. */
1350 if ((exact
&& (ret
!= 0)) || (!exact
&& (ret
>= 0)))
1351 return MATCH_FAILED
;
1353 /* In case of getnext, fill in full instance. */
1354 memcpy (name
, fulloid
, (v
->namelen
+ 1) * sizeof (oid
));
1355 *length
= v
->namelen
+ 1;
1358 *var_len
= sizeof(long); /* default to 'long' results */
1360 return MATCH_SUCCEEDED
;
1364 smux_peer_default ()
1366 if (smux_oid
!= smux_default_oid
)
1369 smux_oid
= smux_default_oid
;
1370 smux_oid_len
= smux_default_oid_len
;
1372 if (smux_passwd
!= smux_default_passwd
)
1375 smux_passwd
= smux_default_passwd
;
1383 "SNMP MUX protocol settings\n"
1384 "SNMP MUX peer settings\n"
1385 "Object ID used in SMUX peering\n")
1387 return smux_peer_oid (vty
, argv
[0], NULL
);
1390 DEFUN (smux_peer_password
,
1391 smux_peer_password_cmd
,
1392 "smux peer OID PASSWORD",
1393 "SNMP MUX protocol settings\n"
1394 "SNMP MUX peer settings\n"
1395 "SMUX peering object ID\n"
1396 "SMUX peering password\n")
1398 return smux_peer_oid (vty
, argv
[0], argv
[1]);
1401 DEFUN (no_smux_peer
,
1405 "SNMP MUX protocol settings\n"
1406 "SNMP MUX peer settings\n"
1407 "Object ID used in SMUX peering\n")
1409 return smux_peer_default ();
1412 DEFUN (no_smux_peer_password
,
1413 no_smux_peer_password_cmd
,
1414 "no smux peer OID PASSWORD",
1416 "SNMP MUX protocol settings\n"
1417 "SNMP MUX peer settings\n"
1418 "SMUX peering object ID\n"
1419 "SMUX peering password\n")
1421 return smux_peer_default ();
1425 config_write_smux (struct vty
*vty
)
1430 if (smux_oid
!= smux_default_oid
|| smux_passwd
!= smux_default_passwd
)
1432 vty_out (vty
, "smux peer ");
1433 for (i
= 0; i
< smux_oid_len
; i
++)
1435 vty_out (vty
, "%s%d", first
? "" : ".", (int) smux_oid
[i
]);
1438 vty_out (vty
, " %s%s", smux_passwd
, VTY_NEWLINE
);
1443 /* Register subtree to smux master tree. */
1445 smux_register_mib (char *descr
, struct variable
*var
, size_t width
, int num
,
1446 oid name
[], size_t namelen
)
1448 struct subtree
*tree
;
1450 tree
= (struct subtree
*)malloc(sizeof(struct subtree
));
1451 oid_copy (tree
->name
, name
, namelen
);
1452 tree
->name_len
= namelen
;
1453 tree
->variables
= var
;
1454 tree
->variables_num
= num
;
1455 tree
->variables_width
= width
;
1456 tree
->registered
= 0;
1457 listnode_add_sort(treelist
, tree
);
1463 /* Setting configuration to default. */
1464 smux_peer_default ();
1467 /* Compare function to keep treelist sorted */
1469 smux_tree_cmp(struct subtree
*tree1
, struct subtree
*tree2
)
1471 return oid_compare(tree1
->name
, tree1
->name_len
,
1472 tree2
->name
, tree2
->name_len
);
1475 /* Initialize some values then schedule first SMUX connection. */
1477 smux_init (struct thread_master
*tm
, oid defoid
[], size_t defoid_len
)
1479 /* Set default SMUX oid. */
1480 smux_default_oid
= defoid
;
1481 smux_default_oid_len
= defoid_len
;
1483 smux_oid
= smux_default_oid
;
1484 smux_oid_len
= smux_default_oid_len
;
1485 smux_passwd
= smux_default_passwd
;
1487 /* copy callers thread master */
1490 /* Make MIB tree. */
1491 treelist
= list_new();
1492 treelist
->cmp
= (int (*)(void *, void *))smux_tree_cmp
;
1494 /* Install commands. */
1495 install_node (&smux_node
, config_write_smux
);
1497 install_element (CONFIG_NODE
, &smux_peer_cmd
);
1498 install_element (CONFIG_NODE
, &smux_peer_password_cmd
);
1499 install_element (CONFIG_NODE
, &no_smux_peer_cmd
);
1500 install_element (CONFIG_NODE
, &no_smux_peer_password_cmd
);
1506 /* Schedule first connection. */
1507 smux_event (SMUX_SCHEDULE
, 0);
1509 #endif /* HAVE_SNMP */