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 */