blob: 29370050f84b920329cd90ef2e0ff54dbfc9dfbc [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
Vincent Bernatd6be5fb2012-05-24 09:44:43 +020024#if defined HAVE_SNMP && defined SNMP_SMUX
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
Vincent Bernat3a4c9682012-05-23 00:52:46 +020037#define SMUX_PORT_DEFAULT 199
38
39#define SMUXMAXPKTSIZE 1500
40#define SMUXMAXSTRLEN 256
41
42#define SMUX_OPEN (ASN_APPLICATION | ASN_CONSTRUCTOR | 0)
43#define SMUX_CLOSE (ASN_APPLICATION | ASN_PRIMITIVE | 1)
44#define SMUX_RREQ (ASN_APPLICATION | ASN_CONSTRUCTOR | 2)
45#define SMUX_RRSP (ASN_APPLICATION | ASN_PRIMITIVE | 3)
46#define SMUX_SOUT (ASN_APPLICATION | ASN_PRIMITIVE | 4)
47
48#define SMUX_GET (ASN_CONTEXT | ASN_CONSTRUCTOR | 0)
49#define SMUX_GETNEXT (ASN_CONTEXT | ASN_CONSTRUCTOR | 1)
50#define SMUX_GETRSP (ASN_CONTEXT | ASN_CONSTRUCTOR | 2)
51#define SMUX_SET (ASN_CONTEXT | ASN_CONSTRUCTOR | 3)
52#define SMUX_TRAP (ASN_CONTEXT | ASN_CONSTRUCTOR | 4)
53
54#define SMUX_MAX_FAILURE 3
55
56/* SNMP tree. */
57struct subtree
58{
59 /* Tree's oid. */
60 oid name[MAX_OID_LEN];
61 u_char name_len;
62
63 /* List of the variables. */
64 struct variable *variables;
65
66 /* Length of the variables list. */
67 int variables_num;
68
69 /* Width of the variables list. */
70 int variables_width;
71
72 /* Registered flag. */
73 int registered;
74};
75
paul718e3742002-12-13 20:15:29 +000076#define min(A,B) ((A) < (B) ? (A) : (B))
77
78enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
79
80void smux_event (enum smux_event, int);
81
82
83/* SMUX socket. */
84int smux_sock = -1;
85
86/* SMUX subtree list. */
87struct list *treelist;
88
89/* SMUX oid. */
hassoc75105a2004-10-13 10:33:26 +000090oid *smux_oid = NULL;
paul718e3742002-12-13 20:15:29 +000091size_t smux_oid_len;
92
paul718e3742002-12-13 20:15:29 +000093/* SMUX password. */
hassoc75105a2004-10-13 10:33:26 +000094char *smux_passwd = NULL;
paul718e3742002-12-13 20:15:29 +000095
96/* SMUX read threads. */
97struct thread *smux_read_thread;
98
99/* SMUX connect thrads. */
100struct thread *smux_connect_thread;
101
102/* SMUX debug flag. */
103int debug_smux = 0;
104
105/* SMUX failure count. */
106int fail = 0;
107
108/* SMUX node. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -0800109static struct cmd_node smux_node =
paul718e3742002-12-13 20:15:29 +0000110{
111 SMUX_NODE,
112 "" /* SMUX has no interface. */
113};
pauldd488a72003-06-19 01:21:07 +0000114
115/* thread master */
116static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +0000117
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100118static int
paul718e3742002-12-13 20:15:29 +0000119oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
120{
121 int i;
122
123 for (i = 0; i < min (o1_len, o2_len); i++)
124 {
125 if (o1[i] < o2[i])
126 return -1;
127 else if (o1[i] > o2[i])
128 return 1;
129 }
130 if (o1_len < o2_len)
131 return -1;
132
133 return 0;
134}
135
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100136static void
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -0700137smux_oid_dump (const char *prefix, const oid *oid, size_t oid_len)
paul718e3742002-12-13 20:15:29 +0000138{
paul9035efa2004-10-10 11:56:56 +0000139 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000140 int first = 1;
141 char buf[MAX_OID_LEN * 3];
142
143 buf[0] = '\0';
144
145 for (i = 0; i < oid_len; i++)
146 {
147 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
148 first = 0;
149 }
ajs8ddca702004-12-07 18:53:52 +0000150 zlog_debug ("%s: %s", prefix, buf);
paul718e3742002-12-13 20:15:29 +0000151}
152
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100153static int
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -0700154smux_socket (void)
paul718e3742002-12-13 20:15:29 +0000155{
156 int ret;
157#ifdef HAVE_IPV6
158 struct addrinfo hints, *res0, *res;
159 int gai;
160#else
161 struct sockaddr_in serv;
162 struct servent *sp;
163#endif
164 int sock = 0;
165
166#ifdef HAVE_IPV6
167 memset(&hints, 0, sizeof(hints));
168 hints.ai_family = PF_UNSPEC;
169 hints.ai_socktype = SOCK_STREAM;
170 gai = getaddrinfo(NULL, "smux", &hints, &res0);
171 if (gai == EAI_SERVICE)
172 {
173 char servbuf[NI_MAXSERV];
174 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
175 servbuf[sizeof (servbuf) - 1] = '\0';
176 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
177 }
178 if (gai)
179 {
180 zlog_warn("Cannot locate loopback service smux");
181 return -1;
182 }
183 for(res=res0; res; res=res->ai_next)
184 {
185 if (res->ai_family != AF_INET
186#ifdef HAVE_IPV6
187 && res->ai_family != AF_INET6
188#endif /* HAVE_IPV6 */
189 )
190 continue;
191
192 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
193 if (sock < 0)
194 continue;
195 sockopt_reuseaddr (sock);
196 sockopt_reuseport (sock);
197 ret = connect (sock, res->ai_addr, res->ai_addrlen);
198 if (ret < 0)
199 {
200 close(sock);
201 sock = -1;
202 continue;
203 }
204 break;
205 }
206 freeaddrinfo(res0);
207 if (sock < 0)
208 zlog_warn ("Can't connect to SNMP agent with SMUX");
209#else
210 sock = socket (AF_INET, SOCK_STREAM, 0);
211 if (sock < 0)
212 {
213 zlog_warn ("Can't make socket for SNMP");
214 return -1;
215 }
216
217 memset (&serv, 0, sizeof (struct sockaddr_in));
218 serv.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000219#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +0000220 serv.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000221#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +0000222
223 sp = getservbyname ("smux", "tcp");
224 if (sp != NULL)
225 serv.sin_port = sp->s_port;
226 else
227 serv.sin_port = htons (SMUX_PORT_DEFAULT);
228
229 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
230
231 sockopt_reuseaddr (sock);
232 sockopt_reuseport (sock);
233
234 ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
235 if (ret < 0)
236 {
237 close (sock);
238 smux_sock = -1;
239 zlog_warn ("Can't connect to SNMP agent with SMUX");
240 return -1;
241 }
242#endif
243 return sock;
244}
245
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100246static void
paul718e3742002-12-13 20:15:29 +0000247smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
248 long errindex, u_char val_type, void *arg, size_t arg_len)
249{
paul718e3742002-12-13 20:15:29 +0000250 u_char buf[BUFSIZ];
251 u_char *ptr, *h1, *h1e, *h2, *h2e;
paul70e149e2004-10-31 16:29:50 +0000252 size_t len, length;
paul718e3742002-12-13 20:15:29 +0000253
254 ptr = buf;
255 len = BUFSIZ;
256 length = len;
257
258 if (debug_smux)
259 {
ajs8ddca702004-12-07 18:53:52 +0000260 zlog_debug ("SMUX GETRSP send");
261 zlog_debug ("SMUX GETRSP reqid: %ld", reqid);
paul718e3742002-12-13 20:15:29 +0000262 }
263
264 h1 = ptr;
265 /* Place holder h1 for complete sequence */
266 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
267 h1e = ptr;
268
269 ptr = asn_build_int (ptr, &len,
270 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
271 &reqid, sizeof (reqid));
272
273 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000274 zlog_debug ("SMUX GETRSP errstat: %ld", errstat);
paul718e3742002-12-13 20:15:29 +0000275
276 ptr = asn_build_int (ptr, &len,
277 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
278 &errstat, sizeof (errstat));
279 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000280 zlog_debug ("SMUX GETRSP errindex: %ld", errindex);
paul718e3742002-12-13 20:15:29 +0000281
282 ptr = asn_build_int (ptr, &len,
283 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
284 &errindex, sizeof (errindex));
285
286 h2 = ptr;
287 /* Place holder h2 for one variable */
288 ptr = asn_build_sequence (ptr, &len,
289 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
290 0);
291 h2e = ptr;
292
293 ptr = snmp_build_var_op (ptr, objid, &objid_len,
294 val_type, arg_len, arg, &len);
295
296 /* Now variable size is known, fill in size */
297 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
298
299 /* Fill in size of whole sequence */
300 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
301
302 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100303 zlog_debug ("SMUX getresp send: %td", (ptr - buf));
paul718e3742002-12-13 20:15:29 +0000304
Stephen Hemminger004b1232011-12-07 00:55:15 +0400305 send (smux_sock, buf, (ptr - buf), 0);
paul718e3742002-12-13 20:15:29 +0000306}
307
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100308static u_char *
309smux_var (u_char *ptr, size_t len, oid objid[], size_t *objid_len,
paul718e3742002-12-13 20:15:29 +0000310 size_t *var_val_len,
311 u_char *var_val_type,
312 void **var_value)
313{
314 u_char type;
315 u_char val_type;
316 size_t val_len;
317 u_char *val;
318
319 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100320 zlog_debug ("SMUX var parse: len %zd", len);
paul718e3742002-12-13 20:15:29 +0000321
322 /* Parse header. */
323 ptr = asn_parse_header (ptr, &len, &type);
324
325 if (debug_smux)
326 {
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100327 zlog_debug ("SMUX var parse: type %d len %zd", type, len);
ajs8ddca702004-12-07 18:53:52 +0000328 zlog_debug ("SMUX var parse: type must be %d",
paul718e3742002-12-13 20:15:29 +0000329 (ASN_SEQUENCE | ASN_CONSTRUCTOR));
330 }
331
332 /* Parse var option. */
333 *objid_len = MAX_OID_LEN;
334 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
335 &val_len, &val, &len);
336
337 if (var_val_len)
338 *var_val_len = val_len;
339
340 if (var_value)
341 *var_value = (void*) val;
342
343 if (var_val_type)
344 *var_val_type = val_type;
345
346 /* Requested object id length is objid_len. */
347 if (debug_smux)
348 smux_oid_dump ("Request OID", objid, *objid_len);
349
350 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000351 zlog_debug ("SMUX val_type: %d", val_type);
paul718e3742002-12-13 20:15:29 +0000352
353 /* Check request value type. */
354 if (debug_smux)
355 switch (val_type)
356 {
357 case ASN_NULL:
358 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
359 ASN_NULL. */
ajs8ddca702004-12-07 18:53:52 +0000360 zlog_debug ("ASN_NULL");
paul718e3742002-12-13 20:15:29 +0000361 break;
362
363 case ASN_INTEGER:
ajs8ddca702004-12-07 18:53:52 +0000364 zlog_debug ("ASN_INTEGER");
paul718e3742002-12-13 20:15:29 +0000365 break;
366 case ASN_COUNTER:
367 case ASN_GAUGE:
368 case ASN_TIMETICKS:
369 case ASN_UINTEGER:
ajs8ddca702004-12-07 18:53:52 +0000370 zlog_debug ("ASN_COUNTER");
paul718e3742002-12-13 20:15:29 +0000371 break;
372 case ASN_COUNTER64:
ajs8ddca702004-12-07 18:53:52 +0000373 zlog_debug ("ASN_COUNTER64");
paul718e3742002-12-13 20:15:29 +0000374 break;
375 case ASN_IPADDRESS:
ajs8ddca702004-12-07 18:53:52 +0000376 zlog_debug ("ASN_IPADDRESS");
paul718e3742002-12-13 20:15:29 +0000377 break;
378 case ASN_OCTET_STR:
ajs8ddca702004-12-07 18:53:52 +0000379 zlog_debug ("ASN_OCTET_STR");
paul718e3742002-12-13 20:15:29 +0000380 break;
381 case ASN_OPAQUE:
382 case ASN_NSAP:
383 case ASN_OBJECT_ID:
ajs8ddca702004-12-07 18:53:52 +0000384 zlog_debug ("ASN_OPAQUE");
paul718e3742002-12-13 20:15:29 +0000385 break;
386 case SNMP_NOSUCHOBJECT:
ajs8ddca702004-12-07 18:53:52 +0000387 zlog_debug ("SNMP_NOSUCHOBJECT");
paul718e3742002-12-13 20:15:29 +0000388 break;
389 case SNMP_NOSUCHINSTANCE:
ajs8ddca702004-12-07 18:53:52 +0000390 zlog_debug ("SNMP_NOSUCHINSTANCE");
paul718e3742002-12-13 20:15:29 +0000391 break;
392 case SNMP_ENDOFMIBVIEW:
ajs8ddca702004-12-07 18:53:52 +0000393 zlog_debug ("SNMP_ENDOFMIBVIEW");
paul718e3742002-12-13 20:15:29 +0000394 break;
395 case ASN_BIT_STR:
ajs8ddca702004-12-07 18:53:52 +0000396 zlog_debug ("ASN_BIT_STR");
paul718e3742002-12-13 20:15:29 +0000397 break;
398 default:
ajs8ddca702004-12-07 18:53:52 +0000399 zlog_debug ("Unknown type");
paul718e3742002-12-13 20:15:29 +0000400 break;
401 }
402 return ptr;
403}
404
405/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
406 ucd-snmp smux and as such suppose, that the peer receives in the message
407 only one variable. Fortunately, IBM seems to do the same in AIX. */
408
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100409static int
paul718e3742002-12-13 20:15:29 +0000410smux_set (oid *reqid, size_t *reqid_len,
411 u_char val_type, void *val, size_t val_len, int action)
412{
413 int j;
414 struct subtree *subtree;
415 struct variable *v;
416 int subresult;
417 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000418 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000419 int result;
420 u_char *statP = NULL;
421 WriteMethod *write_method = NULL;
paul1eb8ef22005-04-07 07:30:20 +0000422 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000423
424 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000425 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +0000426 {
paul718e3742002-12-13 20:15:29 +0000427 subresult = oid_compare_part (reqid, *reqid_len,
428 subtree->name, subtree->name_len);
429
430 /* Subtree matched. */
431 if (subresult == 0)
432 {
433 /* Prepare suffix. */
434 suffix = reqid + subtree->name_len;
435 suffix_len = *reqid_len - subtree->name_len;
436 result = subresult;
437
438 /* Check variables. */
439 for (j = 0; j < subtree->variables_num; j++)
440 {
441 v = &subtree->variables[j];
442
443 /* Always check suffix */
444 result = oid_compare_part (suffix, suffix_len,
445 v->name, v->namelen);
446
447 /* This is exact match so result must be zero. */
448 if (result == 0)
449 {
450 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000451 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000452
453 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
454 &val_len, &write_method);
455
456 if (write_method)
457 {
458 return (*write_method)(action, val, val_type, val_len,
Vincent Bernat3a4c9682012-05-23 00:52:46 +0200459 statP, suffix, suffix_len);
paul718e3742002-12-13 20:15:29 +0000460 }
461 else
462 {
463 return SNMP_ERR_READONLY;
464 }
465 }
466
467 /* If above execution is failed or oid is small (so
468 there is no further match). */
469 if (result < 0)
470 return SNMP_ERR_NOSUCHNAME;
471 }
472 }
473 }
474 return SNMP_ERR_NOSUCHNAME;
475}
476
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100477static int
paul718e3742002-12-13 20:15:29 +0000478smux_get (oid *reqid, size_t *reqid_len, int exact,
479 u_char *val_type,void **val, size_t *val_len)
480{
481 int j;
482 struct subtree *subtree;
483 struct variable *v;
484 int subresult;
485 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000486 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000487 int result;
488 WriteMethod *write_method=NULL;
paul1eb8ef22005-04-07 07:30:20 +0000489 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000490
491 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000492 for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree))
paul718e3742002-12-13 20:15:29 +0000493 {
paul718e3742002-12-13 20:15:29 +0000494 subresult = oid_compare_part (reqid, *reqid_len,
495 subtree->name, subtree->name_len);
496
497 /* Subtree matched. */
498 if (subresult == 0)
499 {
500 /* Prepare suffix. */
501 suffix = reqid + subtree->name_len;
502 suffix_len = *reqid_len - subtree->name_len;
503 result = subresult;
504
505 /* Check variables. */
506 for (j = 0; j < subtree->variables_num; j++)
507 {
508 v = &subtree->variables[j];
509
510 /* Always check suffix */
511 result = oid_compare_part (suffix, suffix_len,
512 v->name, v->namelen);
513
514 /* This is exact match so result must be zero. */
515 if (result == 0)
516 {
517 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000518 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000519
520 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
521 val_len, &write_method);
522
523 /* There is no instance. */
524 if (*val == NULL)
525 return SNMP_NOSUCHINSTANCE;
526
527 /* Call is suceed. */
528 *val_type = v->type;
529
530 return 0;
531 }
532
533 /* If above execution is failed or oid is small (so
534 there is no further match). */
535 if (result < 0)
536 return SNMP_ERR_NOSUCHNAME;
537 }
538 }
539 }
540 return SNMP_ERR_NOSUCHNAME;
541}
542
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100543static int
paul718e3742002-12-13 20:15:29 +0000544smux_getnext (oid *reqid, size_t *reqid_len, int exact,
545 u_char *val_type,void **val, size_t *val_len)
546{
547 int j;
548 oid save[MAX_OID_LEN];
549 int savelen = 0;
550 struct subtree *subtree;
551 struct variable *v;
552 int subresult;
553 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000554 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000555 int result;
556 WriteMethod *write_method=NULL;
paul1eb8ef22005-04-07 07:30:20 +0000557 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000558
559
560 /* Save incoming request. */
561 oid_copy (save, reqid, *reqid_len);
562 savelen = *reqid_len;
563
564 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000565 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +0000566 {
paul718e3742002-12-13 20:15:29 +0000567 subresult = oid_compare_part (reqid, *reqid_len,
568 subtree->name, subtree->name_len);
569
570 /* If request is in the tree. The agent has to make sure we
571 only receive requests we have registered for. */
572 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
573 behave as if it manages the whole SNMP MIB tree itself. It's the
574 duty of the master agent to collect the best answer and return it
575 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
576 :-). ucd-snmp really behaves bad here as it actually might ask
577 multiple times for the same GETNEXT request as it throws away the
578 answer when it expects it in a different subtree and might come
579 back later with the very same request. --jochen */
580
581 if (subresult <= 0)
582 {
583 /* Prepare suffix. */
584 suffix = reqid + subtree->name_len;
585 suffix_len = *reqid_len - subtree->name_len;
586 if (subresult < 0)
587 {
588 oid_copy(reqid, subtree->name, subtree->name_len);
589 *reqid_len = subtree->name_len;
590 }
591 for (j = 0; j < subtree->variables_num; j++)
592 {
593 result = subresult;
594 v = &subtree->variables[j];
595
596 /* Next then check result >= 0. */
597 if (result == 0)
598 result = oid_compare_part (suffix, suffix_len,
599 v->name, v->namelen);
600
601 if (result <= 0)
602 {
603 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000604 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000605 if(result<0)
606 {
607 oid_copy(suffix, v->name, v->namelen);
608 suffix_len = v->namelen;
609 }
610 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
611 val_len, &write_method);
612 *reqid_len = suffix_len + subtree->name_len;
613 if (*val)
614 {
615 *val_type = v->type;
616 return 0;
617 }
618 }
619 }
620 }
621 }
622 memcpy (reqid, save, savelen * sizeof(oid));
623 *reqid_len = savelen;
624
625 return SNMP_ERR_NOSUCHNAME;
626}
627
628/* GET message header. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100629static u_char *
630smux_parse_get_header (u_char *ptr, size_t *len, long *reqid)
paul718e3742002-12-13 20:15:29 +0000631{
632 u_char type;
633 long errstat;
634 long errindex;
635
636 /* Request ID. */
637 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
638
639 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000640 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
paul718e3742002-12-13 20:15:29 +0000641
642 /* Error status. */
643 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
644
645 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100646 zlog_debug ("SMUX GET errstat %ld len: %zd", errstat, *len);
paul718e3742002-12-13 20:15:29 +0000647
648 /* Error index. */
649 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
650
651 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100652 zlog_debug ("SMUX GET errindex %ld len: %zd", errindex, *len);
paul718e3742002-12-13 20:15:29 +0000653
654 return ptr;
655}
656
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100657static void
658smux_parse_set (u_char *ptr, size_t len, int action)
paul718e3742002-12-13 20:15:29 +0000659{
660 long reqid;
661 oid oid[MAX_OID_LEN];
662 size_t oid_len;
663 u_char val_type;
664 void *val;
665 size_t val_len;
666 int ret;
667
668 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100669 zlog_debug ("SMUX SET(%s) message parse: len %zd",
paul718e3742002-12-13 20:15:29 +0000670 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
671 len);
672
673 /* Parse SET message header. */
674 ptr = smux_parse_get_header (ptr, &len, &reqid);
675
676 /* Parse SET message object ID. */
677 ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
678
679 ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
680 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000681 zlog_debug ("SMUX SET ret %d", ret);
paul718e3742002-12-13 20:15:29 +0000682
683 /* Return result. */
684 if (RESERVE1 == action)
685 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
686}
687
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100688static void
689smux_parse_get (u_char *ptr, size_t len, int exact)
paul718e3742002-12-13 20:15:29 +0000690{
691 long reqid;
692 oid oid[MAX_OID_LEN];
693 size_t oid_len;
694 u_char val_type;
695 void *val;
696 size_t val_len;
697 int ret;
698
699 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100700 zlog_debug ("SMUX GET message parse: len %zd", len);
paul718e3742002-12-13 20:15:29 +0000701
702 /* Parse GET message header. */
703 ptr = smux_parse_get_header (ptr, &len, &reqid);
704
705 /* Parse GET message object ID. We needn't the value come */
706 ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
707
708 /* Traditional getstatptr. */
709 if (exact)
710 ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
711 else
712 ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
713
714 /* Return result. */
715 if (ret == 0)
716 smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
717 else
718 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
719}
720
721/* Parse SMUX_CLOSE message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100722static void
723smux_parse_close (u_char *ptr, int len)
paul718e3742002-12-13 20:15:29 +0000724{
725 long reason = 0;
726
727 while (len--)
728 {
729 reason = (reason << 8) | (long) *ptr;
730 ptr++;
731 }
732 zlog_info ("SMUX_CLOSE with reason: %ld", reason);
733}
734
735/* SMUX_RRSP message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100736static void
737smux_parse_rrsp (u_char *ptr, size_t len)
paul718e3742002-12-13 20:15:29 +0000738{
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100739 u_char val;
paul718e3742002-12-13 20:15:29 +0000740 long errstat;
741
742 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
743
744 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000745 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
paul718e3742002-12-13 20:15:29 +0000746}
747
748/* Parse SMUX message. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100749static int
750smux_parse (u_char *ptr, size_t len)
paul718e3742002-12-13 20:15:29 +0000751{
752 /* This buffer we'll use for SOUT message. We could allocate it with
753 malloc and save only static pointer/lenght, but IMHO static
754 buffer is a faster solusion. */
755 static u_char sout_save_buff[SMUXMAXPKTSIZE];
756 static int sout_save_len = 0;
757
758 int len_income = len; /* see note below: YYY */
759 u_char type;
760 u_char rollback;
761
762 rollback = ptr[2]; /* important only for SMUX_SOUT */
763
764process_rest: /* see note below: YYY */
765
766 /* Parse SMUX message type and subsequent length. */
767 ptr = asn_parse_header (ptr, &len, &type);
768
769 if (debug_smux)
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100770 zlog_debug ("SMUX message received type: %d rest len: %zd", type, len);
paul718e3742002-12-13 20:15:29 +0000771
772 switch (type)
773 {
774 case SMUX_OPEN:
775 /* Open must be not send from SNMP agent. */
776 zlog_warn ("SMUX_OPEN received: resetting connection.");
777 return -1;
778 break;
779 case SMUX_RREQ:
780 /* SMUX_RREQ message is invalid for us. */
781 zlog_warn ("SMUX_RREQ received: resetting connection.");
782 return -1;
783 break;
784 case SMUX_SOUT:
785 /* SMUX_SOUT message is now valied for us. */
786 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000787 zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
paul718e3742002-12-13 20:15:29 +0000788
789 if (sout_save_len > 0)
790 {
791 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
792 sout_save_len = 0;
793 }
794 else
795 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
796
797 if (len_income > 3)
798 {
799 /* YYY: this strange code has to solve the "slow peer"
800 problem: When agent sends SMUX_SOUT message it doesn't
801 wait any responce and may send some next message to
802 subagent. Then the peer in 'smux_read()' will recieve
803 from socket the 'concatenated' buffer, contaning both
804 SMUX_SOUT message and the next one
805 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
806 the buffer is longer than 3 ( length of SMUX_SOUT ), we
807 must process the rest of it. This effect may be observed
808 if 'debug_smux' is set to '1' */
809 ptr++;
810 len = len_income - 3;
811 goto process_rest;
812 }
813 break;
814 case SMUX_GETRSP:
815 /* SMUX_GETRSP message is invalid for us. */
816 zlog_warn ("SMUX_GETRSP received: resetting connection.");
817 return -1;
818 break;
819 case SMUX_CLOSE:
820 /* Close SMUX connection. */
821 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000822 zlog_debug ("SMUX_CLOSE");
paul718e3742002-12-13 20:15:29 +0000823 smux_parse_close (ptr, len);
824 return -1;
825 break;
826 case SMUX_RRSP:
827 /* This is response for register message. */
828 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000829 zlog_debug ("SMUX_RRSP");
paul718e3742002-12-13 20:15:29 +0000830 smux_parse_rrsp (ptr, len);
831 break;
832 case SMUX_GET:
833 /* Exact request for object id. */
834 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000835 zlog_debug ("SMUX_GET");
paul718e3742002-12-13 20:15:29 +0000836 smux_parse_get (ptr, len, 1);
837 break;
838 case SMUX_GETNEXT:
839 /* Next request for object id. */
840 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000841 zlog_debug ("SMUX_GETNEXT");
paul718e3742002-12-13 20:15:29 +0000842 smux_parse_get (ptr, len, 0);
843 break;
844 case SMUX_SET:
845 /* SMUX_SET is supported with some limitations. */
846 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000847 zlog_debug ("SMUX_SET");
paul718e3742002-12-13 20:15:29 +0000848
849 /* save the data for future SMUX_SOUT */
850 memcpy (sout_save_buff, ptr, len);
851 sout_save_len = len;
852 smux_parse_set (ptr, len, RESERVE1);
853 break;
854 default:
855 zlog_info ("Unknown type: %d", type);
856 break;
857 }
858 return 0;
859}
860
861/* SMUX message read function. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100862static int
paul718e3742002-12-13 20:15:29 +0000863smux_read (struct thread *t)
864{
865 int sock;
866 int len;
867 u_char buf[SMUXMAXPKTSIZE];
868 int ret;
869
870 /* Clear thread. */
871 sock = THREAD_FD (t);
872 smux_read_thread = NULL;
873
874 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000875 zlog_debug ("SMUX read start");
paul718e3742002-12-13 20:15:29 +0000876
877 /* Read message from SMUX socket. */
878 len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
879
880 if (len < 0)
881 {
ajs6099b3b2004-11-20 02:06:59 +0000882 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000883 close (sock);
884 smux_sock = -1;
885 smux_event (SMUX_CONNECT, 0);
886 return -1;
887 }
888
889 if (len == 0)
890 {
891 zlog_warn ("SMUX connection closed: %d", sock);
892 close (sock);
893 smux_sock = -1;
894 smux_event (SMUX_CONNECT, 0);
895 return -1;
896 }
897
898 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000899 zlog_debug ("SMUX read len: %d", len);
paul718e3742002-12-13 20:15:29 +0000900
901 /* Parse the message. */
902 ret = smux_parse (buf, len);
903
904 if (ret < 0)
905 {
906 close (sock);
907 smux_sock = -1;
908 smux_event (SMUX_CONNECT, 0);
909 return -1;
910 }
911
912 /* Regiser read thread. */
913 smux_event (SMUX_READ, sock);
914
915 return 0;
916}
917
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100918static int
paul718e3742002-12-13 20:15:29 +0000919smux_open (int sock)
920{
921 u_char buf[BUFSIZ];
922 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +0000923 size_t len;
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100924 long version;
Stephen Hemminger004b1232011-12-07 00:55:15 +0400925 const char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION;
paul718e3742002-12-13 20:15:29 +0000926
927 if (debug_smux)
928 {
929 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
ajs8ddca702004-12-07 18:53:52 +0000930 zlog_debug ("SMUX open progname: %s", progname);
931 zlog_debug ("SMUX open password: %s", smux_passwd);
paul718e3742002-12-13 20:15:29 +0000932 }
933
934 ptr = buf;
935 len = BUFSIZ;
936
937 /* SMUX Header. As placeholder. */
938 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
939
940 /* SMUX Open. */
941 version = 0;
942 ptr = asn_build_int (ptr, &len,
943 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +0000944 &version, sizeof (version));
paul718e3742002-12-13 20:15:29 +0000945
946 /* SMUX connection oid. */
947 ptr = asn_build_objid (ptr, &len,
948 (u_char)
949 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
950 smux_oid, smux_oid_len);
951
952 /* SMUX connection description. */
953 ptr = asn_build_string (ptr, &len,
954 (u_char)
955 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
Stephen Hemminger004b1232011-12-07 00:55:15 +0400956 (const u_char *) progname, strlen (progname));
paul718e3742002-12-13 20:15:29 +0000957
958 /* SMUX connection password. */
959 ptr = asn_build_string (ptr, &len,
960 (u_char)
961 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100962 (u_char *)smux_passwd, strlen (smux_passwd));
paul718e3742002-12-13 20:15:29 +0000963
964 /* Fill in real SMUX header. We exclude ASN header size (2). */
965 len = BUFSIZ;
966 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
967
968 return send (sock, buf, (ptr - buf), 0);
969}
970
971int
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -0700972smux_trap (const oid *name, size_t namelen,
973 const oid *iname, size_t inamelen,
974 const struct trap_object *trapobj, size_t trapobjlen,
paul020709f2003-04-04 02:44:16 +0000975 unsigned int tick, u_char sptrap)
paul718e3742002-12-13 20:15:29 +0000976{
paul9035efa2004-10-10 11:56:56 +0000977 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000978 u_char buf[BUFSIZ];
979 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +0000980 size_t len, length;
paul718e3742002-12-13 20:15:29 +0000981 struct in_addr addr;
982 unsigned long val;
983 u_char *h1, *h1e;
984
985 ptr = buf;
986 len = BUFSIZ;
987 length = len;
988
989 /* When SMUX connection is not established. */
990 if (smux_sock < 0)
991 return 0;
992
993 /* SMUX header. */
994 ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
995
996 /* Sub agent enterprise oid. */
997 ptr = asn_build_objid (ptr, &len,
998 (u_char)
999 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1000 smux_oid, smux_oid_len);
1001
1002 /* IP address. */
1003 addr.s_addr = 0;
1004 ptr = asn_build_string (ptr, &len,
1005 (u_char)
1006 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001007 (u_char *)&addr, sizeof (addr));
paul718e3742002-12-13 20:15:29 +00001008
1009 /* Generic trap integer. */
1010 val = SNMP_TRAP_ENTERPRISESPECIFIC;
1011 ptr = asn_build_int (ptr, &len,
1012 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001013 (long *)&val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001014
1015 /* Specific trap integer. */
paul020709f2003-04-04 02:44:16 +00001016 val = sptrap;
paul718e3742002-12-13 20:15:29 +00001017 ptr = asn_build_int (ptr, &len,
1018 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001019 (long *)&val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001020
1021 /* Timeticks timestamp. */
1022 val = 0;
1023 ptr = asn_build_unsigned_int (ptr, &len,
1024 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001025 &val, sizeof (val));
paul718e3742002-12-13 20:15:29 +00001026
1027 /* Variables. */
1028 h1 = ptr;
1029 ptr = asn_build_sequence (ptr, &len,
1030 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1031 0);
1032
1033
1034 /* Iteration for each objects. */
1035 h1e = ptr;
1036 for (i = 0; i < trapobjlen; i++)
1037 {
1038 int ret;
1039 oid oid[MAX_OID_LEN];
1040 size_t oid_len;
1041 void *val;
1042 size_t val_len;
1043 u_char val_type;
1044
1045 /* Make OID. */
vincent5e4914c2005-09-29 16:34:30 +00001046 if (trapobj[i].namelen > 0)
1047 {
1048 oid_copy (oid, name, namelen);
1049 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen);
1050 oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen);
1051 oid_len = namelen + trapobj[i].namelen + inamelen;
1052 }
1053 else
1054 {
1055 oid_copy (oid, name, namelen);
1056 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen * (-1));
1057 oid_len = namelen + trapobj[i].namelen * (-1) ;
1058 }
paul718e3742002-12-13 20:15:29 +00001059
vincent5e4914c2005-09-29 16:34:30 +00001060 if (debug_smux)
1061 {
1062 smux_oid_dump ("Trap", name, namelen);
1063 if (trapobj[i].namelen < 0)
1064 smux_oid_dump ("Trap",
1065 trapobj[i].name, (- 1) * (trapobj[i].namelen));
1066 else
1067 {
1068 smux_oid_dump ("Trap", trapobj[i].name, (trapobj[i].namelen));
1069 smux_oid_dump ("Trap", iname, inamelen);
1070 }
1071 smux_oid_dump ("Trap", oid, oid_len);
Andrew J. Schorreda9ba72007-04-27 18:13:15 +00001072 zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ, (u_long)oid_len);
vincent5e4914c2005-09-29 16:34:30 +00001073 }
paul718e3742002-12-13 20:15:29 +00001074
1075 ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
1076
1077 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +00001078 zlog_debug ("smux_get result %d", ret);
paul718e3742002-12-13 20:15:29 +00001079
1080 if (ret == 0)
1081 ptr = snmp_build_var_op (ptr, oid, &oid_len,
1082 val_type, val_len, val, &len);
1083 }
1084
1085 /* Now variable size is known, fill in size */
1086 asn_build_sequence(h1, &length,
1087 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1088 ptr - h1e);
1089
1090 /* Fill in size of whole sequence */
1091 len = BUFSIZ;
1092 asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
1093
1094 return send (smux_sock, buf, (ptr - buf), 0);
1095}
1096
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001097static int
paul718e3742002-12-13 20:15:29 +00001098smux_register (int sock)
1099{
1100 u_char buf[BUFSIZ];
1101 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +00001102 int ret;
1103 size_t len;
paul718e3742002-12-13 20:15:29 +00001104 long priority;
1105 long operation;
1106 struct subtree *subtree;
paul1eb8ef22005-04-07 07:30:20 +00001107 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00001108
1109 ret = 0;
1110
paul1eb8ef22005-04-07 07:30:20 +00001111 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +00001112 {
1113 ptr = buf;
1114 len = BUFSIZ;
1115
paul718e3742002-12-13 20:15:29 +00001116 /* SMUX RReq Header. */
1117 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
1118
1119 /* Register MIB tree. */
1120 ptr = asn_build_objid (ptr, &len,
1121 (u_char)
1122 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1123 subtree->name, subtree->name_len);
1124
1125 /* Priority. */
1126 priority = -1;
1127 ptr = asn_build_int (ptr, &len,
1128 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001129 &priority, sizeof (priority));
paul718e3742002-12-13 20:15:29 +00001130
1131 /* Operation. */
1132 operation = 2; /* Register R/W */
1133 ptr = asn_build_int (ptr, &len,
1134 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
Andrew J. Schorr965b83f2006-09-26 15:30:43 +00001135 &operation, sizeof (operation));
paul718e3742002-12-13 20:15:29 +00001136
1137 if (debug_smux)
1138 {
1139 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
ajs8ddca702004-12-07 18:53:52 +00001140 zlog_debug ("SMUX register priority: %ld", priority);
1141 zlog_debug ("SMUX register operation: %ld", operation);
paul718e3742002-12-13 20:15:29 +00001142 }
1143
1144 len = BUFSIZ;
1145 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
1146 ret = send (sock, buf, (ptr - buf), 0);
1147 if (ret < 0)
1148 return ret;
1149 }
1150 return ret;
1151}
1152
1153/* Try to connect to SNMP agent. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001154static int
paul718e3742002-12-13 20:15:29 +00001155smux_connect (struct thread *t)
1156{
1157 int ret;
1158
1159 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +00001160 zlog_debug ("SMUX connect try %d", fail + 1);
paul718e3742002-12-13 20:15:29 +00001161
1162 /* Clear thread poner of myself. */
1163 smux_connect_thread = NULL;
1164
1165 /* Make socket. Try to connect. */
1166 smux_sock = smux_socket ();
1167 if (smux_sock < 0)
1168 {
1169 if (++fail < SMUX_MAX_FAILURE)
1170 smux_event (SMUX_CONNECT, 0);
1171 return 0;
1172 }
1173
1174 /* Send OPEN PDU. */
1175 ret = smux_open (smux_sock);
1176 if (ret < 0)
1177 {
ajs6099b3b2004-11-20 02:06:59 +00001178 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001179 close (smux_sock);
1180 smux_sock = -1;
1181 if (++fail < SMUX_MAX_FAILURE)
1182 smux_event (SMUX_CONNECT, 0);
1183 return -1;
1184 }
1185
1186 /* Send any outstanding register PDUs. */
1187 ret = smux_register (smux_sock);
1188 if (ret < 0)
1189 {
ajs6099b3b2004-11-20 02:06:59 +00001190 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001191 close (smux_sock);
1192 smux_sock = -1;
1193 if (++fail < SMUX_MAX_FAILURE)
1194 smux_event (SMUX_CONNECT, 0);
1195 return -1;
1196 }
1197
1198 /* Everything goes fine. */
1199 smux_event (SMUX_READ, smux_sock);
1200
1201 return 0;
1202}
1203
1204/* Clear all SMUX related resources. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001205static void
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -07001206smux_stop (void)
paul718e3742002-12-13 20:15:29 +00001207{
1208 if (smux_read_thread)
Paul Jakmaa56ef882007-10-22 15:53:17 +00001209 {
1210 thread_cancel (smux_read_thread);
1211 smux_read_thread = NULL;
1212 }
1213
paul718e3742002-12-13 20:15:29 +00001214 if (smux_connect_thread)
Paul Jakmaa56ef882007-10-22 15:53:17 +00001215 {
1216 thread_cancel (smux_connect_thread);
1217 smux_connect_thread = NULL;
1218 }
paul718e3742002-12-13 20:15:29 +00001219
1220 if (smux_sock >= 0)
1221 {
1222 close (smux_sock);
1223 smux_sock = -1;
1224 }
1225}
1226
pauldd488a72003-06-19 01:21:07 +00001227
paul718e3742002-12-13 20:15:29 +00001228
1229void
1230smux_event (enum smux_event event, int sock)
1231{
1232 switch (event)
1233 {
1234 case SMUX_SCHEDULE:
1235 smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
1236 break;
1237 case SMUX_CONNECT:
1238 smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
1239 break;
1240 case SMUX_READ:
1241 smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
1242 break;
1243 default:
1244 break;
1245 }
1246}
1247
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001248static int
paul9035efa2004-10-10 11:56:56 +00001249smux_str2oid (const char *str, oid *oid, size_t *oid_len)
paul718e3742002-12-13 20:15:29 +00001250{
1251 int len;
1252 int val;
1253
1254 len = 0;
1255 val = 0;
1256 *oid_len = 0;
1257
1258 if (*str == '.')
1259 str++;
1260 if (*str == '\0')
1261 return 0;
1262
1263 while (1)
1264 {
1265 if (! isdigit (*str))
1266 return -1;
1267
1268 while (isdigit (*str))
1269 {
1270 val *= 10;
1271 val += (*str - '0');
1272 str++;
1273 }
1274
1275 if (*str == '\0')
1276 break;
1277 if (*str != '.')
1278 return -1;
1279
1280 oid[len++] = val;
1281 val = 0;
1282 str++;
1283 }
1284
1285 oid[len++] = val;
1286 *oid_len = len;
1287
1288 return 0;
1289}
1290
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001291static oid *
paul718e3742002-12-13 20:15:29 +00001292smux_oid_dup (oid *objid, size_t objid_len)
1293{
1294 oid *new;
1295
1296 new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
1297 oid_copy (new, objid, objid_len);
1298
1299 return new;
1300}
1301
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001302static int
paul9035efa2004-10-10 11:56:56 +00001303smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str)
paul718e3742002-12-13 20:15:29 +00001304{
1305 int ret;
1306 oid oid[MAX_OID_LEN];
1307 size_t oid_len;
1308
1309 ret = smux_str2oid (oid_str, oid, &oid_len);
1310 if (ret != 0)
1311 {
1312 vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
1313 return CMD_WARNING;
1314 }
1315
hassoc75105a2004-10-13 10:33:26 +00001316 if (smux_oid)
1317 {
1318 free (smux_oid);
1319 smux_oid = NULL;
1320 }
paul718e3742002-12-13 20:15:29 +00001321
paul9035efa2004-10-10 11:56:56 +00001322 /* careful, smux_passwd might point to string constant */
hassoc75105a2004-10-13 10:33:26 +00001323 if (smux_passwd)
paul718e3742002-12-13 20:15:29 +00001324 {
1325 free (smux_passwd);
1326 smux_passwd = NULL;
1327 }
1328
1329 smux_oid = smux_oid_dup (oid, oid_len);
1330 smux_oid_len = oid_len;
1331
1332 if (passwd_str)
1333 smux_passwd = strdup (passwd_str);
hassoc75105a2004-10-13 10:33:26 +00001334 else
1335 smux_passwd = strdup ("");
paul718e3742002-12-13 20:15:29 +00001336
hassoc75105a2004-10-13 10:33:26 +00001337 return 0;
paul718e3742002-12-13 20:15:29 +00001338}
1339
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001340static int
Stephen Hemminger65d3fbb2009-05-15 09:59:03 -07001341smux_peer_default (void)
paul718e3742002-12-13 20:15:29 +00001342{
hassoc75105a2004-10-13 10:33:26 +00001343 if (smux_oid)
paul718e3742002-12-13 20:15:29 +00001344 {
1345 free (smux_oid);
hassoc75105a2004-10-13 10:33:26 +00001346 smux_oid = NULL;
paul718e3742002-12-13 20:15:29 +00001347 }
paul9035efa2004-10-10 11:56:56 +00001348
1349 /* careful, smux_passwd might be pointing at string constant */
hassoc75105a2004-10-13 10:33:26 +00001350 if (smux_passwd)
paul718e3742002-12-13 20:15:29 +00001351 {
1352 free (smux_passwd);
hassoc75105a2004-10-13 10:33:26 +00001353 smux_passwd = NULL;
paul718e3742002-12-13 20:15:29 +00001354 }
hassoc75105a2004-10-13 10:33:26 +00001355
paul718e3742002-12-13 20:15:29 +00001356 return CMD_SUCCESS;
1357}
1358
1359DEFUN (smux_peer,
1360 smux_peer_cmd,
1361 "smux peer OID",
1362 "SNMP MUX protocol settings\n"
1363 "SNMP MUX peer settings\n"
1364 "Object ID used in SMUX peering\n")
1365{
hassoc75105a2004-10-13 10:33:26 +00001366 if (smux_peer_oid (vty, argv[0], NULL) == 0)
1367 {
1368 smux_start();
1369 return CMD_SUCCESS;
1370 }
1371 else
1372 return CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00001373}
1374
1375DEFUN (smux_peer_password,
1376 smux_peer_password_cmd,
1377 "smux peer OID PASSWORD",
1378 "SNMP MUX protocol settings\n"
1379 "SNMP MUX peer settings\n"
1380 "SMUX peering object ID\n"
1381 "SMUX peering password\n")
1382{
hassoc75105a2004-10-13 10:33:26 +00001383 if (smux_peer_oid (vty, argv[0], argv[1]) == 0)
1384 {
1385 smux_start();
1386 return CMD_SUCCESS;
1387 }
1388 else
1389 return CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00001390}
1391
1392DEFUN (no_smux_peer,
1393 no_smux_peer_cmd,
hassoc75105a2004-10-13 10:33:26 +00001394 "no smux peer",
1395 NO_STR
1396 "SNMP MUX protocol settings\n"
1397 "SNMP MUX peer settings\n")
1398{
1399 smux_stop();
1400 return smux_peer_default ();
1401}
1402
1403ALIAS (no_smux_peer,
1404 no_smux_peer_oid_cmd,
paul718e3742002-12-13 20:15:29 +00001405 "no smux peer OID",
1406 NO_STR
1407 "SNMP MUX protocol settings\n"
1408 "SNMP MUX peer settings\n"
hassoc75105a2004-10-13 10:33:26 +00001409 "SMUX peering object ID\n")
paul718e3742002-12-13 20:15:29 +00001410
hassoc75105a2004-10-13 10:33:26 +00001411ALIAS (no_smux_peer,
1412 no_smux_peer_oid_password_cmd,
paul718e3742002-12-13 20:15:29 +00001413 "no smux peer OID PASSWORD",
1414 NO_STR
1415 "SNMP MUX protocol settings\n"
1416 "SNMP MUX peer settings\n"
1417 "SMUX peering object ID\n"
1418 "SMUX peering password\n")
paul718e3742002-12-13 20:15:29 +00001419
Chris Caputo0be8dfb2009-06-02 18:40:07 +01001420static int
paul718e3742002-12-13 20:15:29 +00001421config_write_smux (struct vty *vty)
1422{
1423 int first = 1;
paul9035efa2004-10-10 11:56:56 +00001424 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001425
hassoc75105a2004-10-13 10:33:26 +00001426 if (smux_oid)
paul718e3742002-12-13 20:15:29 +00001427 {
1428 vty_out (vty, "smux peer ");
1429 for (i = 0; i < smux_oid_len; i++)
1430 {
1431 vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
1432 first = 0;
1433 }
1434 vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
1435 }
1436 return 0;
1437}
1438
1439/* Register subtree to smux master tree. */
1440void
paulc9eca012004-10-11 11:28:44 +00001441smux_register_mib (const char *descr, struct variable *var,
1442 size_t width, int num,
paul718e3742002-12-13 20:15:29 +00001443 oid name[], size_t namelen)
1444{
1445 struct subtree *tree;
1446
1447 tree = (struct subtree *)malloc(sizeof(struct subtree));
1448 oid_copy (tree->name, name, namelen);
1449 tree->name_len = namelen;
1450 tree->variables = var;
1451 tree->variables_num = num;
1452 tree->variables_width = width;
1453 tree->registered = 0;
1454 listnode_add_sort(treelist, tree);
1455}
1456
paul718e3742002-12-13 20:15:29 +00001457/* Compare function to keep treelist sorted */
1458static int
1459smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
1460{
1461 return oid_compare(tree1->name, tree1->name_len,
1462 tree2->name, tree2->name_len);
1463}
1464
1465/* Initialize some values then schedule first SMUX connection. */
1466void
hassoc75105a2004-10-13 10:33:26 +00001467smux_init (struct thread_master *tm)
paul718e3742002-12-13 20:15:29 +00001468{
pauldd488a72003-06-19 01:21:07 +00001469 /* copy callers thread master */
1470 master = tm;
paul718e3742002-12-13 20:15:29 +00001471
1472 /* Make MIB tree. */
1473 treelist = list_new();
1474 treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
1475
1476 /* Install commands. */
1477 install_node (&smux_node, config_write_smux);
1478
1479 install_element (CONFIG_NODE, &smux_peer_cmd);
1480 install_element (CONFIG_NODE, &smux_peer_password_cmd);
1481 install_element (CONFIG_NODE, &no_smux_peer_cmd);
hassoc75105a2004-10-13 10:33:26 +00001482 install_element (CONFIG_NODE, &no_smux_peer_oid_cmd);
1483 install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd);
paul718e3742002-12-13 20:15:29 +00001484}
1485
1486void
1487smux_start(void)
1488{
Paul Jakmaa56ef882007-10-22 15:53:17 +00001489 /* Close any existing connections. */
1490 smux_stop();
1491
paul718e3742002-12-13 20:15:29 +00001492 /* Schedule first connection. */
1493 smux_event (SMUX_SCHEDULE, 0);
1494}
1495#endif /* HAVE_SNMP */