blob: 145ec90bba03ab1b7679c57f6917ea70f300cddf [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* SNMP support
2 * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
3 *
4 * This file is part of GNU Zebra.
5 *
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
9 * later version.
10 *
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.
15 *
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
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
24#ifdef HAVE_SNMP
paul07661cb2003-03-18 00:03:05 +000025#include <net-snmp/net-snmp-config.h>
Joakim Tjernlundfb62a3c2008-05-13 20:03:32 +020026#include <net-snmp/net-snmp-includes.h>
paul718e3742002-12-13 20:15:29 +000027
paul718e3742002-12-13 20:15:29 +000028#include "log.h"
29#include "thread.h"
30#include "linklist.h"
31#include "command.h"
gdt5e4fa162004-03-16 14:38:36 +000032#include <lib/version.h>
paul718e3742002-12-13 20:15:29 +000033#include "memory.h"
34#include "sockunion.h"
pauldd488a72003-06-19 01:21:07 +000035#include "smux.h"
paul718e3742002-12-13 20:15:29 +000036
37#define min(A,B) ((A) < (B) ? (A) : (B))
38
39enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
40
41void smux_event (enum smux_event, int);
42
43
44/* SMUX socket. */
45int smux_sock = -1;
46
47/* SMUX subtree list. */
48struct list *treelist;
49
50/* SMUX oid. */
hassoc75105a2004-10-13 10:33:26 +000051oid *smux_oid = NULL;
paul718e3742002-12-13 20:15:29 +000052size_t smux_oid_len;
53
paul718e3742002-12-13 20:15:29 +000054/* SMUX password. */
hassoc75105a2004-10-13 10:33:26 +000055char *smux_passwd = NULL;
paul718e3742002-12-13 20:15:29 +000056
57/* SMUX read threads. */
58struct thread *smux_read_thread;
59
60/* SMUX connect thrads. */
61struct thread *smux_connect_thread;
62
63/* SMUX debug flag. */
64int debug_smux = 0;
65
66/* SMUX failure count. */
67int fail = 0;
68
69/* SMUX node. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080070static struct cmd_node smux_node =
paul718e3742002-12-13 20:15:29 +000071{
72 SMUX_NODE,
73 "" /* SMUX has no interface. */
74};
pauldd488a72003-06-19 01:21:07 +000075
76/* thread master */
77static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +000078
79void *
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -070080oid_copy (void *dest, const void *src, size_t size)
paul718e3742002-12-13 20:15:29 +000081{
82 return memcpy (dest, src, size * sizeof (oid));
83}
84
85void
86oid2in_addr (oid oid[], int len, struct in_addr *addr)
87{
88 int i;
89 u_char *pnt;
90
91 if (len == 0)
92 return;
93
94 pnt = (u_char *) addr;
95
96 for (i = 0; i < len; i++)
97 *pnt++ = oid[i];
98}
99
100void
101oid_copy_addr (oid oid[], struct in_addr *addr, int len)
102{
103 int i;
104 u_char *pnt;
105
106 if (len == 0)
107 return;
108
109 pnt = (u_char *) addr;
110
111 for (i = 0; i < len; i++)
112 oid[i] = *pnt++;
113}
114
115int
116oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
117{
118 int i;
119
120 for (i = 0; i < min (o1_len, o2_len); i++)
121 {
122 if (o1[i] < o2[i])
123 return -1;
124 else if (o1[i] > o2[i])
125 return 1;
126 }
127 if (o1_len < o2_len)
128 return -1;
129 if (o1_len > o2_len)
130 return 1;
131
132 return 0;
133}
134
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100135static int
paul718e3742002-12-13 20:15:29 +0000136oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
137{
138 int i;
139
140 for (i = 0; i < min (o1_len, o2_len); i++)
141 {
142 if (o1[i] < o2[i])
143 return -1;
144 else if (o1[i] > o2[i])
145 return 1;
146 }
147 if (o1_len < o2_len)
148 return -1;
149
150 return 0;
151}
152
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100153static void
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -0700154smux_oid_dump (const char *prefix, const oid *oid, size_t oid_len)
paul718e3742002-12-13 20:15:29 +0000155{
paul9035efa2004-10-10 11:56:56 +0000156 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000157 int first = 1;
158 char buf[MAX_OID_LEN * 3];
159
160 buf[0] = '\0';
161
162 for (i = 0; i < oid_len; i++)
163 {
164 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
165 first = 0;
166 }
ajs8ddca702004-12-07 18:53:52 +0000167 zlog_debug ("%s: %s", prefix, buf);
paul718e3742002-12-13 20:15:29 +0000168}
169
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100170static int
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -0700171smux_socket (void)
paul718e3742002-12-13 20:15:29 +0000172{
173 int ret;
174#ifdef HAVE_IPV6
175 struct addrinfo hints, *res0, *res;
176 int gai;
177#else
178 struct sockaddr_in serv;
179 struct servent *sp;
180#endif
181 int sock = 0;
182
183#ifdef HAVE_IPV6
184 memset(&hints, 0, sizeof(hints));
185 hints.ai_family = PF_UNSPEC;
186 hints.ai_socktype = SOCK_STREAM;
187 gai = getaddrinfo(NULL, "smux", &hints, &res0);
188 if (gai == EAI_SERVICE)
189 {
190 char servbuf[NI_MAXSERV];
191 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
192 servbuf[sizeof (servbuf) - 1] = '\0';
193 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
194 }
195 if (gai)
196 {
197 zlog_warn("Cannot locate loopback service smux");
198 return -1;
199 }
200 for(res=res0; res; res=res->ai_next)
201 {
202 if (res->ai_family != AF_INET
203#ifdef HAVE_IPV6
204 && res->ai_family != AF_INET6
205#endif /* HAVE_IPV6 */
206 )
207 continue;
208
209 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
210 if (sock < 0)
211 continue;
212 sockopt_reuseaddr (sock);
213 sockopt_reuseport (sock);
214 ret = connect (sock, res->ai_addr, res->ai_addrlen);
215 if (ret < 0)
216 {
217 close(sock);
218 sock = -1;
219 continue;
220 }
221 break;
222 }
223 freeaddrinfo(res0);
224 if (sock < 0)
225 zlog_warn ("Can't connect to SNMP agent with SMUX");
226#else
227 sock = socket (AF_INET, SOCK_STREAM, 0);
228 if (sock < 0)
229 {
230 zlog_warn ("Can't make socket for SNMP");
231 return -1;
232 }
233
234 memset (&serv, 0, sizeof (struct sockaddr_in));
235 serv.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000236#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +0000237 serv.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000238#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +0000239
240 sp = getservbyname ("smux", "tcp");
241 if (sp != NULL)
242 serv.sin_port = sp->s_port;
243 else
244 serv.sin_port = htons (SMUX_PORT_DEFAULT);
245
246 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
247
248 sockopt_reuseaddr (sock);
249 sockopt_reuseport (sock);
250
251 ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
252 if (ret < 0)
253 {
254 close (sock);
255 smux_sock = -1;
256 zlog_warn ("Can't connect to SNMP agent with SMUX");
257 return -1;
258 }
259#endif
260 return sock;
261}
262
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100263static void
paul718e3742002-12-13 20:15:29 +0000264smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
265 long errindex, u_char val_type, void *arg, size_t arg_len)
266{
paul718e3742002-12-13 20:15:29 +0000267 u_char buf[BUFSIZ];
268 u_char *ptr, *h1, *h1e, *h2, *h2e;
paul70e149e2004-10-31 16:29:50 +0000269 size_t len, length;
paul718e3742002-12-13 20:15:29 +0000270
271 ptr = buf;
272 len = BUFSIZ;
273 length = len;
274
275 if (debug_smux)
276 {
ajs8ddca702004-12-07 18:53:52 +0000277 zlog_debug ("SMUX GETRSP send");
278 zlog_debug ("SMUX GETRSP reqid: %ld", reqid);
paul718e3742002-12-13 20:15:29 +0000279 }
280
281 h1 = ptr;
282 /* Place holder h1 for complete sequence */
283 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
284 h1e = ptr;
285
286 ptr = asn_build_int (ptr, &len,
287 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
288 &reqid, sizeof (reqid));
289
290 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000291 zlog_debug ("SMUX GETRSP errstat: %ld", errstat);
paul718e3742002-12-13 20:15:29 +0000292
293 ptr = asn_build_int (ptr, &len,
294 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
295 &errstat, sizeof (errstat));
296 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000297 zlog_debug ("SMUX GETRSP errindex: %ld", errindex);
paul718e3742002-12-13 20:15:29 +0000298
299 ptr = asn_build_int (ptr, &len,
300 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
301 &errindex, sizeof (errindex));
302
303 h2 = ptr;
304 /* Place holder h2 for one variable */
305 ptr = asn_build_sequence (ptr, &len,
306 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
307 0);
308 h2e = ptr;
309
310 ptr = snmp_build_var_op (ptr, objid, &objid_len,
311 val_type, arg_len, arg, &len);
312
313 /* Now variable size is known, fill in size */
314 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
315
316 /* Fill in size of whole sequence */
317 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
318
319 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100320 zlog_debug ("SMUX getresp send: %td", (ptr - buf));
paul718e3742002-12-13 20:15:29 +0000321
Stephen Hemminger004b1232011-12-07 00:55:15 +0400322 send (smux_sock, buf, (ptr - buf), 0);
paul718e3742002-12-13 20:15:29 +0000323}
324
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100325static u_char *
326smux_var (u_char *ptr, size_t len, oid objid[], size_t *objid_len,
paul718e3742002-12-13 20:15:29 +0000327 size_t *var_val_len,
328 u_char *var_val_type,
329 void **var_value)
330{
331 u_char type;
332 u_char val_type;
333 size_t val_len;
334 u_char *val;
335
336 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100337 zlog_debug ("SMUX var parse: len %zd", len);
paul718e3742002-12-13 20:15:29 +0000338
339 /* Parse header. */
340 ptr = asn_parse_header (ptr, &len, &type);
341
342 if (debug_smux)
343 {
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100344 zlog_debug ("SMUX var parse: type %d len %zd", type, len);
ajs8ddca702004-12-07 18:53:52 +0000345 zlog_debug ("SMUX var parse: type must be %d",
paul718e3742002-12-13 20:15:29 +0000346 (ASN_SEQUENCE | ASN_CONSTRUCTOR));
347 }
348
349 /* Parse var option. */
350 *objid_len = MAX_OID_LEN;
351 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
352 &val_len, &val, &len);
353
354 if (var_val_len)
355 *var_val_len = val_len;
356
357 if (var_value)
358 *var_value = (void*) val;
359
360 if (var_val_type)
361 *var_val_type = val_type;
362
363 /* Requested object id length is objid_len. */
364 if (debug_smux)
365 smux_oid_dump ("Request OID", objid, *objid_len);
366
367 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000368 zlog_debug ("SMUX val_type: %d", val_type);
paul718e3742002-12-13 20:15:29 +0000369
370 /* Check request value type. */
371 if (debug_smux)
372 switch (val_type)
373 {
374 case ASN_NULL:
375 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
376 ASN_NULL. */
ajs8ddca702004-12-07 18:53:52 +0000377 zlog_debug ("ASN_NULL");
paul718e3742002-12-13 20:15:29 +0000378 break;
379
380 case ASN_INTEGER:
ajs8ddca702004-12-07 18:53:52 +0000381 zlog_debug ("ASN_INTEGER");
paul718e3742002-12-13 20:15:29 +0000382 break;
383 case ASN_COUNTER:
384 case ASN_GAUGE:
385 case ASN_TIMETICKS:
386 case ASN_UINTEGER:
ajs8ddca702004-12-07 18:53:52 +0000387 zlog_debug ("ASN_COUNTER");
paul718e3742002-12-13 20:15:29 +0000388 break;
389 case ASN_COUNTER64:
ajs8ddca702004-12-07 18:53:52 +0000390 zlog_debug ("ASN_COUNTER64");
paul718e3742002-12-13 20:15:29 +0000391 break;
392 case ASN_IPADDRESS:
ajs8ddca702004-12-07 18:53:52 +0000393 zlog_debug ("ASN_IPADDRESS");
paul718e3742002-12-13 20:15:29 +0000394 break;
395 case ASN_OCTET_STR:
ajs8ddca702004-12-07 18:53:52 +0000396 zlog_debug ("ASN_OCTET_STR");
paul718e3742002-12-13 20:15:29 +0000397 break;
398 case ASN_OPAQUE:
399 case ASN_NSAP:
400 case ASN_OBJECT_ID:
ajs8ddca702004-12-07 18:53:52 +0000401 zlog_debug ("ASN_OPAQUE");
paul718e3742002-12-13 20:15:29 +0000402 break;
403 case SNMP_NOSUCHOBJECT:
ajs8ddca702004-12-07 18:53:52 +0000404 zlog_debug ("SNMP_NOSUCHOBJECT");
paul718e3742002-12-13 20:15:29 +0000405 break;
406 case SNMP_NOSUCHINSTANCE:
ajs8ddca702004-12-07 18:53:52 +0000407 zlog_debug ("SNMP_NOSUCHINSTANCE");
paul718e3742002-12-13 20:15:29 +0000408 break;
409 case SNMP_ENDOFMIBVIEW:
ajs8ddca702004-12-07 18:53:52 +0000410 zlog_debug ("SNMP_ENDOFMIBVIEW");
paul718e3742002-12-13 20:15:29 +0000411 break;
412 case ASN_BIT_STR:
ajs8ddca702004-12-07 18:53:52 +0000413 zlog_debug ("ASN_BIT_STR");
paul718e3742002-12-13 20:15:29 +0000414 break;
415 default:
ajs8ddca702004-12-07 18:53:52 +0000416 zlog_debug ("Unknown type");
paul718e3742002-12-13 20:15:29 +0000417 break;
418 }
419 return ptr;
420}
421
422/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
423 ucd-snmp smux and as such suppose, that the peer receives in the message
424 only one variable. Fortunately, IBM seems to do the same in AIX. */
425
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100426static int
paul718e3742002-12-13 20:15:29 +0000427smux_set (oid *reqid, size_t *reqid_len,
428 u_char val_type, void *val, size_t val_len, int action)
429{
430 int j;
431 struct subtree *subtree;
432 struct variable *v;
433 int subresult;
434 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000435 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000436 int result;
437 u_char *statP = NULL;
438 WriteMethod *write_method = NULL;
paul1eb8ef22005-04-07 07:30:20 +0000439 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000440
441 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000442 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +0000443 {
paul718e3742002-12-13 20:15:29 +0000444 subresult = oid_compare_part (reqid, *reqid_len,
445 subtree->name, subtree->name_len);
446
447 /* Subtree matched. */
448 if (subresult == 0)
449 {
450 /* Prepare suffix. */
451 suffix = reqid + subtree->name_len;
452 suffix_len = *reqid_len - subtree->name_len;
453 result = subresult;
454
455 /* Check variables. */
456 for (j = 0; j < subtree->variables_num; j++)
457 {
458 v = &subtree->variables[j];
459
460 /* Always check suffix */
461 result = oid_compare_part (suffix, suffix_len,
462 v->name, v->namelen);
463
464 /* This is exact match so result must be zero. */
465 if (result == 0)
466 {
467 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000468 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000469
470 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
471 &val_len, &write_method);
472
473 if (write_method)
474 {
475 return (*write_method)(action, val, val_type, val_len,
476 statP, suffix, suffix_len, v);
477 }
478 else
479 {
480 return SNMP_ERR_READONLY;
481 }
482 }
483
484 /* If above execution is failed or oid is small (so
485 there is no further match). */
486 if (result < 0)
487 return SNMP_ERR_NOSUCHNAME;
488 }
489 }
490 }
491 return SNMP_ERR_NOSUCHNAME;
492}
493
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100494static int
paul718e3742002-12-13 20:15:29 +0000495smux_get (oid *reqid, size_t *reqid_len, int exact,
496 u_char *val_type,void **val, size_t *val_len)
497{
498 int j;
499 struct subtree *subtree;
500 struct variable *v;
501 int subresult;
502 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000503 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000504 int result;
505 WriteMethod *write_method=NULL;
paul1eb8ef22005-04-07 07:30:20 +0000506 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000507
508 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000509 for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree))
paul718e3742002-12-13 20:15:29 +0000510 {
paul718e3742002-12-13 20:15:29 +0000511 subresult = oid_compare_part (reqid, *reqid_len,
512 subtree->name, subtree->name_len);
513
514 /* Subtree matched. */
515 if (subresult == 0)
516 {
517 /* Prepare suffix. */
518 suffix = reqid + subtree->name_len;
519 suffix_len = *reqid_len - subtree->name_len;
520 result = subresult;
521
522 /* Check variables. */
523 for (j = 0; j < subtree->variables_num; j++)
524 {
525 v = &subtree->variables[j];
526
527 /* Always check suffix */
528 result = oid_compare_part (suffix, suffix_len,
529 v->name, v->namelen);
530
531 /* This is exact match so result must be zero. */
532 if (result == 0)
533 {
534 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000535 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000536
537 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
538 val_len, &write_method);
539
540 /* There is no instance. */
541 if (*val == NULL)
542 return SNMP_NOSUCHINSTANCE;
543
544 /* Call is suceed. */
545 *val_type = v->type;
546
547 return 0;
548 }
549
550 /* If above execution is failed or oid is small (so
551 there is no further match). */
552 if (result < 0)
553 return SNMP_ERR_NOSUCHNAME;
554 }
555 }
556 }
557 return SNMP_ERR_NOSUCHNAME;
558}
559
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100560static int
paul718e3742002-12-13 20:15:29 +0000561smux_getnext (oid *reqid, size_t *reqid_len, int exact,
562 u_char *val_type,void **val, size_t *val_len)
563{
564 int j;
565 oid save[MAX_OID_LEN];
566 int savelen = 0;
567 struct subtree *subtree;
568 struct variable *v;
569 int subresult;
570 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000571 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000572 int result;
573 WriteMethod *write_method=NULL;
paul1eb8ef22005-04-07 07:30:20 +0000574 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000575
576
577 /* Save incoming request. */
578 oid_copy (save, reqid, *reqid_len);
579 savelen = *reqid_len;
580
581 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000582 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +0000583 {
paul718e3742002-12-13 20:15:29 +0000584 subresult = oid_compare_part (reqid, *reqid_len,
585 subtree->name, subtree->name_len);
586
587 /* If request is in the tree. The agent has to make sure we
588 only receive requests we have registered for. */
589 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
590 behave as if it manages the whole SNMP MIB tree itself. It's the
591 duty of the master agent to collect the best answer and return it
592 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
593 :-). ucd-snmp really behaves bad here as it actually might ask
594 multiple times for the same GETNEXT request as it throws away the
595 answer when it expects it in a different subtree and might come
596 back later with the very same request. --jochen */
597
598 if (subresult <= 0)
599 {
600 /* Prepare suffix. */
601 suffix = reqid + subtree->name_len;
602 suffix_len = *reqid_len - subtree->name_len;
603 if (subresult < 0)
604 {
605 oid_copy(reqid, subtree->name, subtree->name_len);
606 *reqid_len = subtree->name_len;
607 }
608 for (j = 0; j < subtree->variables_num; j++)
609 {
610 result = subresult;
611 v = &subtree->variables[j];
612
613 /* Next then check result >= 0. */
614 if (result == 0)
615 result = oid_compare_part (suffix, suffix_len,
616 v->name, v->namelen);
617
618 if (result <= 0)
619 {
620 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000621 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000622 if(result<0)
623 {
624 oid_copy(suffix, v->name, v->namelen);
625 suffix_len = v->namelen;
626 }
627 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
628 val_len, &write_method);
629 *reqid_len = suffix_len + subtree->name_len;
630 if (*val)
631 {
632 *val_type = v->type;
633 return 0;
634 }
635 }
636 }
637 }
638 }
639 memcpy (reqid, save, savelen * sizeof(oid));
640 *reqid_len = savelen;
641
642 return SNMP_ERR_NOSUCHNAME;
643}
644
645/* GET message header. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100646static u_char *
647smux_parse_get_header (u_char *ptr, size_t *len, long *reqid)
paul718e3742002-12-13 20:15:29 +0000648{
649 u_char type;
650 long errstat;
651 long errindex;
652
653 /* Request ID. */
654 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
655
656 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000657 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
paul718e3742002-12-13 20:15:29 +0000658
659 /* Error status. */
660 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
661
662 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100663 zlog_debug ("SMUX GET errstat %ld len: %zd", errstat, *len);
paul718e3742002-12-13 20:15:29 +0000664
665 /* Error index. */
666 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
667
668 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100669 zlog_debug ("SMUX GET errindex %ld len: %zd", errindex, *len);
paul718e3742002-12-13 20:15:29 +0000670
671 return ptr;
672}
673
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100674static void
675smux_parse_set (u_char *ptr, size_t len, int action)
paul718e3742002-12-13 20:15:29 +0000676{
677 long reqid;
678 oid oid[MAX_OID_LEN];
679 size_t oid_len;
680 u_char val_type;
681 void *val;
682 size_t val_len;
683 int ret;
684
685 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100686 zlog_debug ("SMUX SET(%s) message parse: len %zd",
paul718e3742002-12-13 20:15:29 +0000687 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
688 len);
689
690 /* Parse SET message header. */
691 ptr = smux_parse_get_header (ptr, &len, &reqid);
692
693 /* Parse SET message object ID. */
694 ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
695
696 ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
697 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000698 zlog_debug ("SMUX SET ret %d", ret);
paul718e3742002-12-13 20:15:29 +0000699
700 /* Return result. */
701 if (RESERVE1 == action)
702 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
703}
704
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100705static void
706smux_parse_get (u_char *ptr, size_t len, int exact)
paul718e3742002-12-13 20:15:29 +0000707{
708 long reqid;
709 oid oid[MAX_OID_LEN];
710 size_t oid_len;
711 u_char val_type;
712 void *val;
713 size_t val_len;
714 int ret;
715
716 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100717 zlog_debug ("SMUX GET message parse: len %zd", len);
paul718e3742002-12-13 20:15:29 +0000718
719 /* Parse GET message header. */
720 ptr = smux_parse_get_header (ptr, &len, &reqid);
721
722 /* Parse GET message object ID. We needn't the value come */
723 ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
724
725 /* Traditional getstatptr. */
726 if (exact)
727 ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
728 else
729 ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
730
731 /* Return result. */
732 if (ret == 0)
733 smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
734 else
735 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
736}
737
738/* Parse SMUX_CLOSE message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100739static void
740smux_parse_close (u_char *ptr, int len)
paul718e3742002-12-13 20:15:29 +0000741{
742 long reason = 0;
743
744 while (len--)
745 {
746 reason = (reason << 8) | (long) *ptr;
747 ptr++;
748 }
749 zlog_info ("SMUX_CLOSE with reason: %ld", reason);
750}
751
752/* SMUX_RRSP message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100753static void
754smux_parse_rrsp (u_char *ptr, size_t len)
paul718e3742002-12-13 20:15:29 +0000755{
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100756 u_char val;
paul718e3742002-12-13 20:15:29 +0000757 long errstat;
758
759 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
760
761 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000762 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
paul718e3742002-12-13 20:15:29 +0000763}
764
765/* Parse SMUX message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100766static int
767smux_parse (u_char *ptr, size_t len)
paul718e3742002-12-13 20:15:29 +0000768{
769 /* This buffer we'll use for SOUT message. We could allocate it with
770 malloc and save only static pointer/lenght, but IMHO static
771 buffer is a faster solusion. */
772 static u_char sout_save_buff[SMUXMAXPKTSIZE];
773 static int sout_save_len = 0;
774
775 int len_income = len; /* see note below: YYY */
776 u_char type;
777 u_char rollback;
778
779 rollback = ptr[2]; /* important only for SMUX_SOUT */
780
781process_rest: /* see note below: YYY */
782
783 /* Parse SMUX message type and subsequent length. */
784 ptr = asn_parse_header (ptr, &len, &type);
785
786 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100787 zlog_debug ("SMUX message received type: %d rest len: %zd", type, len);
paul718e3742002-12-13 20:15:29 +0000788
789 switch (type)
790 {
791 case SMUX_OPEN:
792 /* Open must be not send from SNMP agent. */
793 zlog_warn ("SMUX_OPEN received: resetting connection.");
794 return -1;
795 break;
796 case SMUX_RREQ:
797 /* SMUX_RREQ message is invalid for us. */
798 zlog_warn ("SMUX_RREQ received: resetting connection.");
799 return -1;
800 break;
801 case SMUX_SOUT:
802 /* SMUX_SOUT message is now valied for us. */
803 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000804 zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
paul718e3742002-12-13 20:15:29 +0000805
806 if (sout_save_len > 0)
807 {
808 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
809 sout_save_len = 0;
810 }
811 else
812 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
813
814 if (len_income > 3)
815 {
816 /* YYY: this strange code has to solve the "slow peer"
817 problem: When agent sends SMUX_SOUT message it doesn't
818 wait any responce and may send some next message to
819 subagent. Then the peer in 'smux_read()' will recieve
820 from socket the 'concatenated' buffer, contaning both
821 SMUX_SOUT message and the next one
822 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
823 the buffer is longer than 3 ( length of SMUX_SOUT ), we
824 must process the rest of it. This effect may be observed
825 if 'debug_smux' is set to '1' */
826 ptr++;
827 len = len_income - 3;
828 goto process_rest;
829 }
830 break;
831 case SMUX_GETRSP:
832 /* SMUX_GETRSP message is invalid for us. */
833 zlog_warn ("SMUX_GETRSP received: resetting connection.");
834 return -1;
835 break;
836 case SMUX_CLOSE:
837 /* Close SMUX connection. */
838 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000839 zlog_debug ("SMUX_CLOSE");
paul718e3742002-12-13 20:15:29 +0000840 smux_parse_close (ptr, len);
841 return -1;
842 break;
843 case SMUX_RRSP:
844 /* This is response for register message. */
845 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000846 zlog_debug ("SMUX_RRSP");
paul718e3742002-12-13 20:15:29 +0000847 smux_parse_rrsp (ptr, len);
848 break;
849 case SMUX_GET:
850 /* Exact request for object id. */
851 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000852 zlog_debug ("SMUX_GET");
paul718e3742002-12-13 20:15:29 +0000853 smux_parse_get (ptr, len, 1);
854 break;
855 case SMUX_GETNEXT:
856 /* Next request for object id. */
857 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000858 zlog_debug ("SMUX_GETNEXT");
paul718e3742002-12-13 20:15:29 +0000859 smux_parse_get (ptr, len, 0);
860 break;
861 case SMUX_SET:
862 /* SMUX_SET is supported with some limitations. */
863 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000864 zlog_debug ("SMUX_SET");
paul718e3742002-12-13 20:15:29 +0000865
866 /* save the data for future SMUX_SOUT */
867 memcpy (sout_save_buff, ptr, len);
868 sout_save_len = len;
869 smux_parse_set (ptr, len, RESERVE1);
870 break;
871 default:
872 zlog_info ("Unknown type: %d", type);
873 break;
874 }
875 return 0;
876}
877
878/* SMUX message read function. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100879static int
paul718e3742002-12-13 20:15:29 +0000880smux_read (struct thread *t)
881{
882 int sock;
883 int len;
884 u_char buf[SMUXMAXPKTSIZE];
885 int ret;
886
887 /* Clear thread. */
888 sock = THREAD_FD (t);
889 smux_read_thread = NULL;
890
891 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000892 zlog_debug ("SMUX read start");
paul718e3742002-12-13 20:15:29 +0000893
894 /* Read message from SMUX socket. */
895 len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
896
897 if (len < 0)
898 {
ajs6099b3b2004-11-20 02:06:59 +0000899 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000900 close (sock);
901 smux_sock = -1;
902 smux_event (SMUX_CONNECT, 0);
903 return -1;
904 }
905
906 if (len == 0)
907 {
908 zlog_warn ("SMUX connection closed: %d", sock);
909 close (sock);
910 smux_sock = -1;
911 smux_event (SMUX_CONNECT, 0);
912 return -1;
913 }
914
915 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000916 zlog_debug ("SMUX read len: %d", len);
paul718e3742002-12-13 20:15:29 +0000917
918 /* Parse the message. */
919 ret = smux_parse (buf, len);
920
921 if (ret < 0)
922 {
923 close (sock);
924 smux_sock = -1;
925 smux_event (SMUX_CONNECT, 0);
926 return -1;
927 }
928
929 /* Regiser read thread. */
930 smux_event (SMUX_READ, sock);
931
932 return 0;
933}
934
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100935static int
paul718e3742002-12-13 20:15:29 +0000936smux_open (int sock)
937{
938 u_char buf[BUFSIZ];
939 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +0000940 size_t len;
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100941 long version;
Stephen Hemminger004b1232011-12-07 00:55:15 +0400942 const char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION;
paul718e3742002-12-13 20:15:29 +0000943
944 if (debug_smux)
945 {
946 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
ajs8ddca702004-12-07 18:53:52 +0000947 zlog_debug ("SMUX open progname: %s", progname);
948 zlog_debug ("SMUX open password: %s", smux_passwd);
paul718e3742002-12-13 20:15:29 +0000949 }
950
951 ptr = buf;
952 len = BUFSIZ;
953
954 /* SMUX Header. As placeholder. */
955 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
956
957 /* SMUX Open. */
958 version = 0;
959 ptr = asn_build_int (ptr, &len,
960 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +0000961 &version, sizeof (version));
paul718e3742002-12-13 20:15:29 +0000962
963 /* SMUX connection oid. */
964 ptr = asn_build_objid (ptr, &len,
965 (u_char)
966 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
967 smux_oid, smux_oid_len);
968
969 /* SMUX connection description. */
970 ptr = asn_build_string (ptr, &len,
971 (u_char)
972 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
Stephen Hemminger004b1232011-12-07 00:55:15 +0400973 (const u_char *) progname, strlen (progname));
paul718e3742002-12-13 20:15:29 +0000974
975 /* SMUX connection password. */
976 ptr = asn_build_string (ptr, &len,
977 (u_char)
978 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100979 (u_char *)smux_passwd, strlen (smux_passwd));
paul718e3742002-12-13 20:15:29 +0000980
981 /* Fill in real SMUX header. We exclude ASN header size (2). */
982 len = BUFSIZ;
983 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
984
985 return send (sock, buf, (ptr - buf), 0);
986}
987
988int
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -0700989smux_trap (const oid *name, size_t namelen,
990 const oid *iname, size_t inamelen,
991 const struct trap_object *trapobj, size_t trapobjlen,
paul020709f2003-04-04 02:44:16 +0000992 unsigned int tick, u_char sptrap)
paul718e3742002-12-13 20:15:29 +0000993{
paul9035efa2004-10-10 11:56:56 +0000994 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000995 u_char buf[BUFSIZ];
996 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +0000997 size_t len, length;
paul718e3742002-12-13 20:15:29 +0000998 struct in_addr addr;
999 unsigned long val;
1000 u_char *h1, *h1e;
1001
1002 ptr = buf;
1003 len = BUFSIZ;
1004 length = len;
1005
1006 /* When SMUX connection is not established. */
1007 if (smux_sock < 0)
1008 return 0;
1009
1010 /* SMUX header. */
1011 ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
1012
1013 /* Sub agent enterprise oid. */
1014 ptr = asn_build_objid (ptr, &len,
1015 (u_char)
1016 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1017 smux_oid, smux_oid_len);
1018
1019 /* IP address. */
1020 addr.s_addr = 0;
1021 ptr = asn_build_string (ptr, &len,
1022 (u_char)
1023 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001024 (u_char *)&addr, sizeof (addr));
paul718e3742002-12-13 20:15:29 +00001025
1026 /* Generic trap integer. */
1027 val = SNMP_TRAP_ENTERPRISESPECIFIC;
1028 ptr = asn_build_int (ptr, &len,
1029 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001030 (long *)&val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001031
1032 /* Specific trap integer. */
paul020709f2003-04-04 02:44:16 +00001033 val = sptrap;
paul718e3742002-12-13 20:15:29 +00001034 ptr = asn_build_int (ptr, &len,
1035 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001036 (long *)&val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001037
1038 /* Timeticks timestamp. */
1039 val = 0;
1040 ptr = asn_build_unsigned_int (ptr, &len,
1041 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001042 &val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001043
1044 /* Variables. */
1045 h1 = ptr;
1046 ptr = asn_build_sequence (ptr, &len,
1047 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1048 0);
1049
1050
1051 /* Iteration for each objects. */
1052 h1e = ptr;
1053 for (i = 0; i < trapobjlen; i++)
1054 {
1055 int ret;
1056 oid oid[MAX_OID_LEN];
1057 size_t oid_len;
1058 void *val;
1059 size_t val_len;
1060 u_char val_type;
1061
1062 /* Make OID. */
vincent5e4914c2005-09-29 16:34:30 +00001063 if (trapobj[i].namelen > 0)
1064 {
1065 oid_copy (oid, name, namelen);
1066 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen);
1067 oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen);
1068 oid_len = namelen + trapobj[i].namelen + inamelen;
1069 }
1070 else
1071 {
1072 oid_copy (oid, name, namelen);
1073 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen * (-1));
1074 oid_len = namelen + trapobj[i].namelen * (-1) ;
1075 }
paul718e3742002-12-13 20:15:29 +00001076
vincent5e4914c2005-09-29 16:34:30 +00001077 if (debug_smux)
1078 {
1079 smux_oid_dump ("Trap", name, namelen);
1080 if (trapobj[i].namelen < 0)
1081 smux_oid_dump ("Trap",
1082 trapobj[i].name, (- 1) * (trapobj[i].namelen));
1083 else
1084 {
1085 smux_oid_dump ("Trap", trapobj[i].name, (trapobj[i].namelen));
1086 smux_oid_dump ("Trap", iname, inamelen);
1087 }
1088 smux_oid_dump ("Trap", oid, oid_len);
Andrew J. Schorreda9ba72007-04-27 18:13:15 +00001089 zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ, (u_long)oid_len);
vincent5e4914c2005-09-29 16:34:30 +00001090 }
paul718e3742002-12-13 20:15:29 +00001091
1092 ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
1093
1094 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +00001095 zlog_debug ("smux_get result %d", ret);
paul718e3742002-12-13 20:15:29 +00001096
1097 if (ret == 0)
1098 ptr = snmp_build_var_op (ptr, oid, &oid_len,
1099 val_type, val_len, val, &len);
1100 }
1101
1102 /* Now variable size is known, fill in size */
1103 asn_build_sequence(h1, &length,
1104 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1105 ptr - h1e);
1106
1107 /* Fill in size of whole sequence */
1108 len = BUFSIZ;
1109 asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
1110
1111 return send (smux_sock, buf, (ptr - buf), 0);
1112}
1113
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001114static int
paul718e3742002-12-13 20:15:29 +00001115smux_register (int sock)
1116{
1117 u_char buf[BUFSIZ];
1118 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +00001119 int ret;
1120 size_t len;
paul718e3742002-12-13 20:15:29 +00001121 long priority;
1122 long operation;
1123 struct subtree *subtree;
paul1eb8ef22005-04-07 07:30:20 +00001124 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00001125
1126 ret = 0;
1127
paul1eb8ef22005-04-07 07:30:20 +00001128 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +00001129 {
1130 ptr = buf;
1131 len = BUFSIZ;
1132
paul718e3742002-12-13 20:15:29 +00001133 /* SMUX RReq Header. */
1134 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
1135
1136 /* Register MIB tree. */
1137 ptr = asn_build_objid (ptr, &len,
1138 (u_char)
1139 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1140 subtree->name, subtree->name_len);
1141
1142 /* Priority. */
1143 priority = -1;
1144 ptr = asn_build_int (ptr, &len,
1145 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001146 &priority, sizeof (priority));
paul718e3742002-12-13 20:15:29 +00001147
1148 /* Operation. */
1149 operation = 2; /* Register R/W */
1150 ptr = asn_build_int (ptr, &len,
1151 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001152 &operation, sizeof (operation));
paul718e3742002-12-13 20:15:29 +00001153
1154 if (debug_smux)
1155 {
1156 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
ajs8ddca702004-12-07 18:53:52 +00001157 zlog_debug ("SMUX register priority: %ld", priority);
1158 zlog_debug ("SMUX register operation: %ld", operation);
paul718e3742002-12-13 20:15:29 +00001159 }
1160
1161 len = BUFSIZ;
1162 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
1163 ret = send (sock, buf, (ptr - buf), 0);
1164 if (ret < 0)
1165 return ret;
1166 }
1167 return ret;
1168}
1169
1170/* Try to connect to SNMP agent. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001171static int
paul718e3742002-12-13 20:15:29 +00001172smux_connect (struct thread *t)
1173{
1174 int ret;
1175
1176 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +00001177 zlog_debug ("SMUX connect try %d", fail + 1);
paul718e3742002-12-13 20:15:29 +00001178
1179 /* Clear thread poner of myself. */
1180 smux_connect_thread = NULL;
1181
1182 /* Make socket. Try to connect. */
1183 smux_sock = smux_socket ();
1184 if (smux_sock < 0)
1185 {
1186 if (++fail < SMUX_MAX_FAILURE)
1187 smux_event (SMUX_CONNECT, 0);
1188 return 0;
1189 }
1190
1191 /* Send OPEN PDU. */
1192 ret = smux_open (smux_sock);
1193 if (ret < 0)
1194 {
ajs6099b3b2004-11-20 02:06:59 +00001195 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001196 close (smux_sock);
1197 smux_sock = -1;
1198 if (++fail < SMUX_MAX_FAILURE)
1199 smux_event (SMUX_CONNECT, 0);
1200 return -1;
1201 }
1202
1203 /* Send any outstanding register PDUs. */
1204 ret = smux_register (smux_sock);
1205 if (ret < 0)
1206 {
ajs6099b3b2004-11-20 02:06:59 +00001207 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001208 close (smux_sock);
1209 smux_sock = -1;
1210 if (++fail < SMUX_MAX_FAILURE)
1211 smux_event (SMUX_CONNECT, 0);
1212 return -1;
1213 }
1214
1215 /* Everything goes fine. */
1216 smux_event (SMUX_READ, smux_sock);
1217
1218 return 0;
1219}
1220
1221/* Clear all SMUX related resources. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001222static void
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -07001223smux_stop (void)
paul718e3742002-12-13 20:15:29 +00001224{
1225 if (smux_read_thread)
Paul Jakmaa56ef882007-10-22 15:53:17 +00001226 {
1227 thread_cancel (smux_read_thread);
1228 smux_read_thread = NULL;
1229 }
1230
paul718e3742002-12-13 20:15:29 +00001231 if (smux_connect_thread)
Paul Jakmaa56ef882007-10-22 15:53:17 +00001232 {
1233 thread_cancel (smux_connect_thread);
1234 smux_connect_thread = NULL;
1235 }
paul718e3742002-12-13 20:15:29 +00001236
1237 if (smux_sock >= 0)
1238 {
1239 close (smux_sock);
1240 smux_sock = -1;
1241 }
1242}
1243
pauldd488a72003-06-19 01:21:07 +00001244
paul718e3742002-12-13 20:15:29 +00001245
1246void
1247smux_event (enum smux_event event, int sock)
1248{
1249 switch (event)
1250 {
1251 case SMUX_SCHEDULE:
1252 smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
1253 break;
1254 case SMUX_CONNECT:
1255 smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
1256 break;
1257 case SMUX_READ:
1258 smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
1259 break;
1260 default:
1261 break;
1262 }
1263}
1264
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001265static int
paul9035efa2004-10-10 11:56:56 +00001266smux_str2oid (const char *str, oid *oid, size_t *oid_len)
paul718e3742002-12-13 20:15:29 +00001267{
1268 int len;
1269 int val;
1270
1271 len = 0;
1272 val = 0;
1273 *oid_len = 0;
1274
1275 if (*str == '.')
1276 str++;
1277 if (*str == '\0')
1278 return 0;
1279
1280 while (1)
1281 {
1282 if (! isdigit (*str))
1283 return -1;
1284
1285 while (isdigit (*str))
1286 {
1287 val *= 10;
1288 val += (*str - '0');
1289 str++;
1290 }
1291
1292 if (*str == '\0')
1293 break;
1294 if (*str != '.')
1295 return -1;
1296
1297 oid[len++] = val;
1298 val = 0;
1299 str++;
1300 }
1301
1302 oid[len++] = val;
1303 *oid_len = len;
1304
1305 return 0;
1306}
1307
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001308static oid *
paul718e3742002-12-13 20:15:29 +00001309smux_oid_dup (oid *objid, size_t objid_len)
1310{
1311 oid *new;
1312
1313 new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
1314 oid_copy (new, objid, objid_len);
1315
1316 return new;
1317}
1318
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001319static int
paul9035efa2004-10-10 11:56:56 +00001320smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str)
paul718e3742002-12-13 20:15:29 +00001321{
1322 int ret;
1323 oid oid[MAX_OID_LEN];
1324 size_t oid_len;
1325
1326 ret = smux_str2oid (oid_str, oid, &oid_len);
1327 if (ret != 0)
1328 {
1329 vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
1330 return CMD_WARNING;
1331 }
1332
hassoc75105a2004-10-13 10:33:26 +00001333 if (smux_oid)
1334 {
1335 free (smux_oid);
1336 smux_oid = NULL;
1337 }
paul718e3742002-12-13 20:15:29 +00001338
paul9035efa2004-10-10 11:56:56 +00001339 /* careful, smux_passwd might point to string constant */
hassoc75105a2004-10-13 10:33:26 +00001340 if (smux_passwd)
paul718e3742002-12-13 20:15:29 +00001341 {
1342 free (smux_passwd);
1343 smux_passwd = NULL;
1344 }
1345
1346 smux_oid = smux_oid_dup (oid, oid_len);
1347 smux_oid_len = oid_len;
1348
1349 if (passwd_str)
1350 smux_passwd = strdup (passwd_str);
hassoc75105a2004-10-13 10:33:26 +00001351 else
1352 smux_passwd = strdup ("");
paul718e3742002-12-13 20:15:29 +00001353
hassoc75105a2004-10-13 10:33:26 +00001354 return 0;
paul718e3742002-12-13 20:15:29 +00001355}
1356
1357int
1358smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1359 size_t *var_len, WriteMethod **write_method)
1360{
1361 oid fulloid[MAX_OID_LEN];
1362 int ret;
1363
1364 oid_copy (fulloid, v->name, v->namelen);
1365 fulloid[v->namelen] = 0;
1366 /* Check against full instance. */
1367 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1368
1369 /* Check single instance. */
1370 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1371 return MATCH_FAILED;
1372
1373 /* In case of getnext, fill in full instance. */
1374 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1375 *length = v->namelen + 1;
1376
1377 *write_method = 0;
1378 *var_len = sizeof(long); /* default to 'long' results */
1379
1380 return MATCH_SUCCEEDED;
1381}
1382
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001383static int
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -07001384smux_peer_default (void)
paul718e3742002-12-13 20:15:29 +00001385{
hassoc75105a2004-10-13 10:33:26 +00001386 if (smux_oid)
paul718e3742002-12-13 20:15:29 +00001387 {
1388 free (smux_oid);
hassoc75105a2004-10-13 10:33:26 +00001389 smux_oid = NULL;
paul718e3742002-12-13 20:15:29 +00001390 }
paul9035efa2004-10-10 11:56:56 +00001391
1392 /* careful, smux_passwd might be pointing at string constant */
hassoc75105a2004-10-13 10:33:26 +00001393 if (smux_passwd)
paul718e3742002-12-13 20:15:29 +00001394 {
1395 free (smux_passwd);
hassoc75105a2004-10-13 10:33:26 +00001396 smux_passwd = NULL;
paul718e3742002-12-13 20:15:29 +00001397 }
hassoc75105a2004-10-13 10:33:26 +00001398
paul718e3742002-12-13 20:15:29 +00001399 return CMD_SUCCESS;
1400}
1401
1402DEFUN (smux_peer,
1403 smux_peer_cmd,
1404 "smux peer OID",
1405 "SNMP MUX protocol settings\n"
1406 "SNMP MUX peer settings\n"
1407 "Object ID used in SMUX peering\n")
1408{
hassoc75105a2004-10-13 10:33:26 +00001409 if (smux_peer_oid (vty, argv[0], NULL) == 0)
1410 {
1411 smux_start();
1412 return CMD_SUCCESS;
1413 }
1414 else
1415 return CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00001416}
1417
1418DEFUN (smux_peer_password,
1419 smux_peer_password_cmd,
1420 "smux peer OID PASSWORD",
1421 "SNMP MUX protocol settings\n"
1422 "SNMP MUX peer settings\n"
1423 "SMUX peering object ID\n"
1424 "SMUX peering password\n")
1425{
hassoc75105a2004-10-13 10:33:26 +00001426 if (smux_peer_oid (vty, argv[0], argv[1]) == 0)
1427 {
1428 smux_start();
1429 return CMD_SUCCESS;
1430 }
1431 else
1432 return CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00001433}
1434
1435DEFUN (no_smux_peer,
1436 no_smux_peer_cmd,
hassoc75105a2004-10-13 10:33:26 +00001437 "no smux peer",
1438 NO_STR
1439 "SNMP MUX protocol settings\n"
1440 "SNMP MUX peer settings\n")
1441{
1442 smux_stop();
1443 return smux_peer_default ();
1444}
1445
1446ALIAS (no_smux_peer,
1447 no_smux_peer_oid_cmd,
paul718e3742002-12-13 20:15:29 +00001448 "no smux peer OID",
1449 NO_STR
1450 "SNMP MUX protocol settings\n"
1451 "SNMP MUX peer settings\n"
hassoc75105a2004-10-13 10:33:26 +00001452 "SMUX peering object ID\n")
paul718e3742002-12-13 20:15:29 +00001453
hassoc75105a2004-10-13 10:33:26 +00001454ALIAS (no_smux_peer,
1455 no_smux_peer_oid_password_cmd,
paul718e3742002-12-13 20:15:29 +00001456 "no smux peer OID PASSWORD",
1457 NO_STR
1458 "SNMP MUX protocol settings\n"
1459 "SNMP MUX peer settings\n"
1460 "SMUX peering object ID\n"
1461 "SMUX peering password\n")
paul718e3742002-12-13 20:15:29 +00001462
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001463static int
paul718e3742002-12-13 20:15:29 +00001464config_write_smux (struct vty *vty)
1465{
1466 int first = 1;
paul9035efa2004-10-10 11:56:56 +00001467 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001468
hassoc75105a2004-10-13 10:33:26 +00001469 if (smux_oid)
paul718e3742002-12-13 20:15:29 +00001470 {
1471 vty_out (vty, "smux peer ");
1472 for (i = 0; i < smux_oid_len; i++)
1473 {
1474 vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
1475 first = 0;
1476 }
1477 vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
1478 }
1479 return 0;
1480}
1481
1482/* Register subtree to smux master tree. */
1483void
paulc9eca012004-10-11 11:28:44 +00001484smux_register_mib (const char *descr, struct variable *var,
1485 size_t width, int num,
paul718e3742002-12-13 20:15:29 +00001486 oid name[], size_t namelen)
1487{
1488 struct subtree *tree;
1489
1490 tree = (struct subtree *)malloc(sizeof(struct subtree));
1491 oid_copy (tree->name, name, namelen);
1492 tree->name_len = namelen;
1493 tree->variables = var;
1494 tree->variables_num = num;
1495 tree->variables_width = width;
1496 tree->registered = 0;
1497 listnode_add_sort(treelist, tree);
1498}
1499
paul718e3742002-12-13 20:15:29 +00001500/* Compare function to keep treelist sorted */
1501static int
1502smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
1503{
1504 return oid_compare(tree1->name, tree1->name_len,
1505 tree2->name, tree2->name_len);
1506}
1507
1508/* Initialize some values then schedule first SMUX connection. */
1509void
hassoc75105a2004-10-13 10:33:26 +00001510smux_init (struct thread_master *tm)
paul718e3742002-12-13 20:15:29 +00001511{
pauldd488a72003-06-19 01:21:07 +00001512 /* copy callers thread master */
1513 master = tm;
paul718e3742002-12-13 20:15:29 +00001514
1515 /* Make MIB tree. */
1516 treelist = list_new();
1517 treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
1518
1519 /* Install commands. */
1520 install_node (&smux_node, config_write_smux);
1521
1522 install_element (CONFIG_NODE, &smux_peer_cmd);
1523 install_element (CONFIG_NODE, &smux_peer_password_cmd);
1524 install_element (CONFIG_NODE, &no_smux_peer_cmd);
hassoc75105a2004-10-13 10:33:26 +00001525 install_element (CONFIG_NODE, &no_smux_peer_oid_cmd);
1526 install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd);
paul718e3742002-12-13 20:15:29 +00001527}
1528
1529void
1530smux_start(void)
1531{
Paul Jakmaa56ef882007-10-22 15:53:17 +00001532 /* Close any existing connections. */
1533 smux_stop();
1534
paul718e3742002-12-13 20:15:29 +00001535 /* Schedule first connection. */
1536 smux_event (SMUX_SCHEDULE, 0);
1537}
1538#endif /* HAVE_SNMP */