blob: 28f402d886180cfefefb696189bfa0a8f9c1ad54 [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#ifdef HAVE_NETSNMP
26#include <net-snmp/net-snmp-config.h>
27#endif
paul718e3742002-12-13 20:15:29 +000028#include <asn1.h>
29#include <snmp.h>
30#include <snmp_impl.h>
31
paul718e3742002-12-13 20:15:29 +000032#include "log.h"
33#include "thread.h"
34#include "linklist.h"
35#include "command.h"
gdt5e4fa162004-03-16 14:38:36 +000036#include <lib/version.h>
paul718e3742002-12-13 20:15:29 +000037#include "memory.h"
38#include "sockunion.h"
pauldd488a72003-06-19 01:21:07 +000039#include "smux.h"
paul718e3742002-12-13 20:15:29 +000040
41#define min(A,B) ((A) < (B) ? (A) : (B))
42
43enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
44
45void smux_event (enum smux_event, int);
46
47
48/* SMUX socket. */
49int smux_sock = -1;
50
51/* SMUX subtree list. */
52struct list *treelist;
53
54/* SMUX oid. */
hassoc75105a2004-10-13 10:33:26 +000055oid *smux_oid = NULL;
paul718e3742002-12-13 20:15:29 +000056size_t smux_oid_len;
57
paul718e3742002-12-13 20:15:29 +000058/* SMUX password. */
hassoc75105a2004-10-13 10:33:26 +000059char *smux_passwd = NULL;
paul718e3742002-12-13 20:15:29 +000060
61/* SMUX read threads. */
62struct thread *smux_read_thread;
63
64/* SMUX connect thrads. */
65struct thread *smux_connect_thread;
66
67/* SMUX debug flag. */
68int debug_smux = 0;
69
70/* SMUX failure count. */
71int fail = 0;
72
73/* SMUX node. */
74struct cmd_node smux_node =
75{
76 SMUX_NODE,
77 "" /* SMUX has no interface. */
78};
pauldd488a72003-06-19 01:21:07 +000079
80/* thread master */
81static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +000082
83void *
84oid_copy (void *dest, void *src, size_t size)
85{
86 return memcpy (dest, src, size * sizeof (oid));
87}
88
89void
90oid2in_addr (oid oid[], int len, struct in_addr *addr)
91{
92 int i;
93 u_char *pnt;
94
95 if (len == 0)
96 return;
97
98 pnt = (u_char *) addr;
99
100 for (i = 0; i < len; i++)
101 *pnt++ = oid[i];
102}
103
104void
105oid_copy_addr (oid oid[], struct in_addr *addr, int len)
106{
107 int i;
108 u_char *pnt;
109
110 if (len == 0)
111 return;
112
113 pnt = (u_char *) addr;
114
115 for (i = 0; i < len; i++)
116 oid[i] = *pnt++;
117}
118
119int
120oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
121{
122 int i;
123
124 for (i = 0; i < min (o1_len, o2_len); i++)
125 {
126 if (o1[i] < o2[i])
127 return -1;
128 else if (o1[i] > o2[i])
129 return 1;
130 }
131 if (o1_len < o2_len)
132 return -1;
133 if (o1_len > o2_len)
134 return 1;
135
136 return 0;
137}
138
139int
140oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
141{
142 int i;
143
144 for (i = 0; i < min (o1_len, o2_len); i++)
145 {
146 if (o1[i] < o2[i])
147 return -1;
148 else if (o1[i] > o2[i])
149 return 1;
150 }
151 if (o1_len < o2_len)
152 return -1;
153
154 return 0;
155}
156
157void
paul9035efa2004-10-10 11:56:56 +0000158smux_oid_dump (const char *prefix, oid *oid, size_t oid_len)
paul718e3742002-12-13 20:15:29 +0000159{
paul9035efa2004-10-10 11:56:56 +0000160 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000161 int first = 1;
162 char buf[MAX_OID_LEN * 3];
163
164 buf[0] = '\0';
165
166 for (i = 0; i < oid_len; i++)
167 {
168 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
169 first = 0;
170 }
ajs8ddca702004-12-07 18:53:52 +0000171 zlog_debug ("%s: %s", prefix, buf);
paul718e3742002-12-13 20:15:29 +0000172}
173
174int
175smux_socket ()
176{
177 int ret;
178#ifdef HAVE_IPV6
179 struct addrinfo hints, *res0, *res;
180 int gai;
181#else
182 struct sockaddr_in serv;
183 struct servent *sp;
184#endif
185 int sock = 0;
186
187#ifdef HAVE_IPV6
188 memset(&hints, 0, sizeof(hints));
189 hints.ai_family = PF_UNSPEC;
190 hints.ai_socktype = SOCK_STREAM;
191 gai = getaddrinfo(NULL, "smux", &hints, &res0);
192 if (gai == EAI_SERVICE)
193 {
194 char servbuf[NI_MAXSERV];
195 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
196 servbuf[sizeof (servbuf) - 1] = '\0';
197 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
198 }
199 if (gai)
200 {
201 zlog_warn("Cannot locate loopback service smux");
202 return -1;
203 }
204 for(res=res0; res; res=res->ai_next)
205 {
206 if (res->ai_family != AF_INET
207#ifdef HAVE_IPV6
208 && res->ai_family != AF_INET6
209#endif /* HAVE_IPV6 */
210 )
211 continue;
212
213 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
214 if (sock < 0)
215 continue;
216 sockopt_reuseaddr (sock);
217 sockopt_reuseport (sock);
218 ret = connect (sock, res->ai_addr, res->ai_addrlen);
219 if (ret < 0)
220 {
221 close(sock);
222 sock = -1;
223 continue;
224 }
225 break;
226 }
227 freeaddrinfo(res0);
228 if (sock < 0)
229 zlog_warn ("Can't connect to SNMP agent with SMUX");
230#else
231 sock = socket (AF_INET, SOCK_STREAM, 0);
232 if (sock < 0)
233 {
234 zlog_warn ("Can't make socket for SNMP");
235 return -1;
236 }
237
238 memset (&serv, 0, sizeof (struct sockaddr_in));
239 serv.sin_family = AF_INET;
240#ifdef HAVE_SIN_LEN
241 serv.sin_len = sizeof (struct sockaddr_in);
242#endif /* HAVE_SIN_LEN */
243
244 sp = getservbyname ("smux", "tcp");
245 if (sp != NULL)
246 serv.sin_port = sp->s_port;
247 else
248 serv.sin_port = htons (SMUX_PORT_DEFAULT);
249
250 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
251
252 sockopt_reuseaddr (sock);
253 sockopt_reuseport (sock);
254
255 ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
256 if (ret < 0)
257 {
258 close (sock);
259 smux_sock = -1;
260 zlog_warn ("Can't connect to SNMP agent with SMUX");
261 return -1;
262 }
263#endif
264 return sock;
265}
266
267void
268smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
269 long errindex, u_char val_type, void *arg, size_t arg_len)
270{
271 int ret;
272 u_char buf[BUFSIZ];
273 u_char *ptr, *h1, *h1e, *h2, *h2e;
paul70e149e2004-10-31 16:29:50 +0000274 size_t len, length;
paul718e3742002-12-13 20:15:29 +0000275
276 ptr = buf;
277 len = BUFSIZ;
278 length = len;
279
280 if (debug_smux)
281 {
ajs8ddca702004-12-07 18:53:52 +0000282 zlog_debug ("SMUX GETRSP send");
283 zlog_debug ("SMUX GETRSP reqid: %ld", reqid);
paul718e3742002-12-13 20:15:29 +0000284 }
285
286 h1 = ptr;
287 /* Place holder h1 for complete sequence */
288 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
289 h1e = ptr;
290
291 ptr = asn_build_int (ptr, &len,
292 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
293 &reqid, sizeof (reqid));
294
295 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000296 zlog_debug ("SMUX GETRSP errstat: %ld", errstat);
paul718e3742002-12-13 20:15:29 +0000297
298 ptr = asn_build_int (ptr, &len,
299 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
300 &errstat, sizeof (errstat));
301 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000302 zlog_debug ("SMUX GETRSP errindex: %ld", errindex);
paul718e3742002-12-13 20:15:29 +0000303
304 ptr = asn_build_int (ptr, &len,
305 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
306 &errindex, sizeof (errindex));
307
308 h2 = ptr;
309 /* Place holder h2 for one variable */
310 ptr = asn_build_sequence (ptr, &len,
311 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
312 0);
313 h2e = ptr;
314
315 ptr = snmp_build_var_op (ptr, objid, &objid_len,
316 val_type, arg_len, arg, &len);
317
318 /* Now variable size is known, fill in size */
319 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
320
321 /* Fill in size of whole sequence */
322 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
323
324 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000325 zlog_debug ("SMUX getresp send: %ld", (ptr - buf));
paul718e3742002-12-13 20:15:29 +0000326
327 ret = send (smux_sock, buf, (ptr - buf), 0);
328}
329
330char *
paul70e149e2004-10-31 16:29:50 +0000331smux_var (char *ptr, size_t len, oid objid[], size_t *objid_len,
paul718e3742002-12-13 20:15:29 +0000332 size_t *var_val_len,
333 u_char *var_val_type,
334 void **var_value)
335{
336 u_char type;
337 u_char val_type;
338 size_t val_len;
339 u_char *val;
340
341 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000342 zlog_debug ("SMUX var parse: len %ld", len);
paul718e3742002-12-13 20:15:29 +0000343
344 /* Parse header. */
345 ptr = asn_parse_header (ptr, &len, &type);
346
347 if (debug_smux)
348 {
ajs8ddca702004-12-07 18:53:52 +0000349 zlog_debug ("SMUX var parse: type %d len %ld", type, len);
350 zlog_debug ("SMUX var parse: type must be %d",
paul718e3742002-12-13 20:15:29 +0000351 (ASN_SEQUENCE | ASN_CONSTRUCTOR));
352 }
353
354 /* Parse var option. */
355 *objid_len = MAX_OID_LEN;
356 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
357 &val_len, &val, &len);
358
359 if (var_val_len)
360 *var_val_len = val_len;
361
362 if (var_value)
363 *var_value = (void*) val;
364
365 if (var_val_type)
366 *var_val_type = val_type;
367
368 /* Requested object id length is objid_len. */
369 if (debug_smux)
370 smux_oid_dump ("Request OID", objid, *objid_len);
371
372 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000373 zlog_debug ("SMUX val_type: %d", val_type);
paul718e3742002-12-13 20:15:29 +0000374
375 /* Check request value type. */
376 if (debug_smux)
377 switch (val_type)
378 {
379 case ASN_NULL:
380 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
381 ASN_NULL. */
ajs8ddca702004-12-07 18:53:52 +0000382 zlog_debug ("ASN_NULL");
paul718e3742002-12-13 20:15:29 +0000383 break;
384
385 case ASN_INTEGER:
ajs8ddca702004-12-07 18:53:52 +0000386 zlog_debug ("ASN_INTEGER");
paul718e3742002-12-13 20:15:29 +0000387 break;
388 case ASN_COUNTER:
389 case ASN_GAUGE:
390 case ASN_TIMETICKS:
391 case ASN_UINTEGER:
ajs8ddca702004-12-07 18:53:52 +0000392 zlog_debug ("ASN_COUNTER");
paul718e3742002-12-13 20:15:29 +0000393 break;
394 case ASN_COUNTER64:
ajs8ddca702004-12-07 18:53:52 +0000395 zlog_debug ("ASN_COUNTER64");
paul718e3742002-12-13 20:15:29 +0000396 break;
397 case ASN_IPADDRESS:
ajs8ddca702004-12-07 18:53:52 +0000398 zlog_debug ("ASN_IPADDRESS");
paul718e3742002-12-13 20:15:29 +0000399 break;
400 case ASN_OCTET_STR:
ajs8ddca702004-12-07 18:53:52 +0000401 zlog_debug ("ASN_OCTET_STR");
paul718e3742002-12-13 20:15:29 +0000402 break;
403 case ASN_OPAQUE:
404 case ASN_NSAP:
405 case ASN_OBJECT_ID:
ajs8ddca702004-12-07 18:53:52 +0000406 zlog_debug ("ASN_OPAQUE");
paul718e3742002-12-13 20:15:29 +0000407 break;
408 case SNMP_NOSUCHOBJECT:
ajs8ddca702004-12-07 18:53:52 +0000409 zlog_debug ("SNMP_NOSUCHOBJECT");
paul718e3742002-12-13 20:15:29 +0000410 break;
411 case SNMP_NOSUCHINSTANCE:
ajs8ddca702004-12-07 18:53:52 +0000412 zlog_debug ("SNMP_NOSUCHINSTANCE");
paul718e3742002-12-13 20:15:29 +0000413 break;
414 case SNMP_ENDOFMIBVIEW:
ajs8ddca702004-12-07 18:53:52 +0000415 zlog_debug ("SNMP_ENDOFMIBVIEW");
paul718e3742002-12-13 20:15:29 +0000416 break;
417 case ASN_BIT_STR:
ajs8ddca702004-12-07 18:53:52 +0000418 zlog_debug ("ASN_BIT_STR");
paul718e3742002-12-13 20:15:29 +0000419 break;
420 default:
ajs8ddca702004-12-07 18:53:52 +0000421 zlog_debug ("Unknown type");
paul718e3742002-12-13 20:15:29 +0000422 break;
423 }
424 return ptr;
425}
426
427/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
428 ucd-snmp smux and as such suppose, that the peer receives in the message
429 only one variable. Fortunately, IBM seems to do the same in AIX. */
430
431int
432smux_set (oid *reqid, size_t *reqid_len,
433 u_char val_type, void *val, size_t val_len, int action)
434{
435 int j;
436 struct subtree *subtree;
437 struct variable *v;
438 int subresult;
439 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000440 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000441 int result;
442 u_char *statP = NULL;
443 WriteMethod *write_method = NULL;
paul1eb8ef22005-04-07 07:30:20 +0000444 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000445
446 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000447 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +0000448 {
paul718e3742002-12-13 20:15:29 +0000449 subresult = oid_compare_part (reqid, *reqid_len,
450 subtree->name, subtree->name_len);
451
452 /* Subtree matched. */
453 if (subresult == 0)
454 {
455 /* Prepare suffix. */
456 suffix = reqid + subtree->name_len;
457 suffix_len = *reqid_len - subtree->name_len;
458 result = subresult;
459
460 /* Check variables. */
461 for (j = 0; j < subtree->variables_num; j++)
462 {
463 v = &subtree->variables[j];
464
465 /* Always check suffix */
466 result = oid_compare_part (suffix, suffix_len,
467 v->name, v->namelen);
468
469 /* This is exact match so result must be zero. */
470 if (result == 0)
471 {
472 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000473 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000474
475 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
476 &val_len, &write_method);
477
478 if (write_method)
479 {
480 return (*write_method)(action, val, val_type, val_len,
481 statP, suffix, suffix_len, v);
482 }
483 else
484 {
485 return SNMP_ERR_READONLY;
486 }
487 }
488
489 /* If above execution is failed or oid is small (so
490 there is no further match). */
491 if (result < 0)
492 return SNMP_ERR_NOSUCHNAME;
493 }
494 }
495 }
496 return SNMP_ERR_NOSUCHNAME;
497}
498
499int
500smux_get (oid *reqid, size_t *reqid_len, int exact,
501 u_char *val_type,void **val, size_t *val_len)
502{
503 int j;
504 struct subtree *subtree;
505 struct variable *v;
506 int subresult;
507 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000508 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000509 int result;
510 WriteMethod *write_method=NULL;
paul1eb8ef22005-04-07 07:30:20 +0000511 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000512
513 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000514 for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree))
paul718e3742002-12-13 20:15:29 +0000515 {
paul718e3742002-12-13 20:15:29 +0000516 subresult = oid_compare_part (reqid, *reqid_len,
517 subtree->name, subtree->name_len);
518
519 /* Subtree matched. */
520 if (subresult == 0)
521 {
522 /* Prepare suffix. */
523 suffix = reqid + subtree->name_len;
524 suffix_len = *reqid_len - subtree->name_len;
525 result = subresult;
526
527 /* Check variables. */
528 for (j = 0; j < subtree->variables_num; j++)
529 {
530 v = &subtree->variables[j];
531
532 /* Always check suffix */
533 result = oid_compare_part (suffix, suffix_len,
534 v->name, v->namelen);
535
536 /* This is exact match so result must be zero. */
537 if (result == 0)
538 {
539 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000540 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000541
542 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
543 val_len, &write_method);
544
545 /* There is no instance. */
546 if (*val == NULL)
547 return SNMP_NOSUCHINSTANCE;
548
549 /* Call is suceed. */
550 *val_type = v->type;
551
552 return 0;
553 }
554
555 /* If above execution is failed or oid is small (so
556 there is no further match). */
557 if (result < 0)
558 return SNMP_ERR_NOSUCHNAME;
559 }
560 }
561 }
562 return SNMP_ERR_NOSUCHNAME;
563}
564
565int
566smux_getnext (oid *reqid, size_t *reqid_len, int exact,
567 u_char *val_type,void **val, size_t *val_len)
568{
569 int j;
570 oid save[MAX_OID_LEN];
571 int savelen = 0;
572 struct subtree *subtree;
573 struct variable *v;
574 int subresult;
575 oid *suffix;
paul70e149e2004-10-31 16:29:50 +0000576 size_t suffix_len;
paul718e3742002-12-13 20:15:29 +0000577 int result;
578 WriteMethod *write_method=NULL;
paul1eb8ef22005-04-07 07:30:20 +0000579 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000580
581
582 /* Save incoming request. */
583 oid_copy (save, reqid, *reqid_len);
584 savelen = *reqid_len;
585
586 /* Check */
paul1eb8ef22005-04-07 07:30:20 +0000587 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +0000588 {
paul718e3742002-12-13 20:15:29 +0000589 subresult = oid_compare_part (reqid, *reqid_len,
590 subtree->name, subtree->name_len);
591
592 /* If request is in the tree. The agent has to make sure we
593 only receive requests we have registered for. */
594 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
595 behave as if it manages the whole SNMP MIB tree itself. It's the
596 duty of the master agent to collect the best answer and return it
597 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
598 :-). ucd-snmp really behaves bad here as it actually might ask
599 multiple times for the same GETNEXT request as it throws away the
600 answer when it expects it in a different subtree and might come
601 back later with the very same request. --jochen */
602
603 if (subresult <= 0)
604 {
605 /* Prepare suffix. */
606 suffix = reqid + subtree->name_len;
607 suffix_len = *reqid_len - subtree->name_len;
608 if (subresult < 0)
609 {
610 oid_copy(reqid, subtree->name, subtree->name_len);
611 *reqid_len = subtree->name_len;
612 }
613 for (j = 0; j < subtree->variables_num; j++)
614 {
615 result = subresult;
616 v = &subtree->variables[j];
617
618 /* Next then check result >= 0. */
619 if (result == 0)
620 result = oid_compare_part (suffix, suffix_len,
621 v->name, v->namelen);
622
623 if (result <= 0)
624 {
625 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000626 zlog_debug ("SMUX function call index is %d", v->magic);
paul718e3742002-12-13 20:15:29 +0000627 if(result<0)
628 {
629 oid_copy(suffix, v->name, v->namelen);
630 suffix_len = v->namelen;
631 }
632 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
633 val_len, &write_method);
634 *reqid_len = suffix_len + subtree->name_len;
635 if (*val)
636 {
637 *val_type = v->type;
638 return 0;
639 }
640 }
641 }
642 }
643 }
644 memcpy (reqid, save, savelen * sizeof(oid));
645 *reqid_len = savelen;
646
647 return SNMP_ERR_NOSUCHNAME;
648}
649
650/* GET message header. */
651char *
652smux_parse_get_header (char *ptr, size_t *len, long *reqid)
653{
654 u_char type;
655 long errstat;
656 long errindex;
657
658 /* Request ID. */
659 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
660
661 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000662 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
paul718e3742002-12-13 20:15:29 +0000663
664 /* Error status. */
665 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
666
667 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000668 zlog_debug ("SMUX GET errstat %ld len: %ld", errstat, *len);
paul718e3742002-12-13 20:15:29 +0000669
670 /* Error index. */
671 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
672
673 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000674 zlog_debug ("SMUX GET errindex %ld len: %ld", errindex, *len);
paul718e3742002-12-13 20:15:29 +0000675
676 return ptr;
677}
678
679void
680smux_parse_set (char *ptr, size_t len, int action)
681{
682 long reqid;
683 oid oid[MAX_OID_LEN];
684 size_t oid_len;
685 u_char val_type;
686 void *val;
687 size_t val_len;
688 int ret;
689
690 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000691 zlog_debug ("SMUX SET(%s) message parse: len %ld",
paul718e3742002-12-13 20:15:29 +0000692 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
693 len);
694
695 /* Parse SET message header. */
696 ptr = smux_parse_get_header (ptr, &len, &reqid);
697
698 /* Parse SET message object ID. */
699 ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
700
701 ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
702 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000703 zlog_debug ("SMUX SET ret %d", ret);
paul718e3742002-12-13 20:15:29 +0000704
705 /* Return result. */
706 if (RESERVE1 == action)
707 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
708}
709
710void
711smux_parse_get (char *ptr, size_t len, int exact)
712{
713 long reqid;
714 oid oid[MAX_OID_LEN];
715 size_t oid_len;
716 u_char val_type;
717 void *val;
718 size_t val_len;
719 int ret;
720
721 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000722 zlog_debug ("SMUX GET message parse: len %ld", len);
paul718e3742002-12-13 20:15:29 +0000723
724 /* Parse GET message header. */
725 ptr = smux_parse_get_header (ptr, &len, &reqid);
726
727 /* Parse GET message object ID. We needn't the value come */
728 ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
729
730 /* Traditional getstatptr. */
731 if (exact)
732 ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
733 else
734 ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
735
736 /* Return result. */
737 if (ret == 0)
738 smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
739 else
740 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
741}
742
743/* Parse SMUX_CLOSE message. */
744void
745smux_parse_close (char *ptr, int len)
746{
747 long reason = 0;
748
749 while (len--)
750 {
751 reason = (reason << 8) | (long) *ptr;
752 ptr++;
753 }
754 zlog_info ("SMUX_CLOSE with reason: %ld", reason);
755}
756
757/* SMUX_RRSP message. */
758void
paul70e149e2004-10-31 16:29:50 +0000759smux_parse_rrsp (char *ptr, size_t len)
paul718e3742002-12-13 20:15:29 +0000760{
761 char val;
762 long errstat;
763
764 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
765
766 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000767 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
paul718e3742002-12-13 20:15:29 +0000768}
769
770/* Parse SMUX message. */
771int
paul70e149e2004-10-31 16:29:50 +0000772smux_parse (char *ptr, size_t len)
paul718e3742002-12-13 20:15:29 +0000773{
774 /* This buffer we'll use for SOUT message. We could allocate it with
775 malloc and save only static pointer/lenght, but IMHO static
776 buffer is a faster solusion. */
777 static u_char sout_save_buff[SMUXMAXPKTSIZE];
778 static int sout_save_len = 0;
779
780 int len_income = len; /* see note below: YYY */
781 u_char type;
782 u_char rollback;
783
784 rollback = ptr[2]; /* important only for SMUX_SOUT */
785
786process_rest: /* see note below: YYY */
787
788 /* Parse SMUX message type and subsequent length. */
789 ptr = asn_parse_header (ptr, &len, &type);
790
791 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000792 zlog_debug ("SMUX message received type: %d rest len: %ld", type, len);
paul718e3742002-12-13 20:15:29 +0000793
794 switch (type)
795 {
796 case SMUX_OPEN:
797 /* Open must be not send from SNMP agent. */
798 zlog_warn ("SMUX_OPEN received: resetting connection.");
799 return -1;
800 break;
801 case SMUX_RREQ:
802 /* SMUX_RREQ message is invalid for us. */
803 zlog_warn ("SMUX_RREQ received: resetting connection.");
804 return -1;
805 break;
806 case SMUX_SOUT:
807 /* SMUX_SOUT message is now valied for us. */
808 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000809 zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
paul718e3742002-12-13 20:15:29 +0000810
811 if (sout_save_len > 0)
812 {
813 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
814 sout_save_len = 0;
815 }
816 else
817 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
818
819 if (len_income > 3)
820 {
821 /* YYY: this strange code has to solve the "slow peer"
822 problem: When agent sends SMUX_SOUT message it doesn't
823 wait any responce and may send some next message to
824 subagent. Then the peer in 'smux_read()' will recieve
825 from socket the 'concatenated' buffer, contaning both
826 SMUX_SOUT message and the next one
827 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
828 the buffer is longer than 3 ( length of SMUX_SOUT ), we
829 must process the rest of it. This effect may be observed
830 if 'debug_smux' is set to '1' */
831 ptr++;
832 len = len_income - 3;
833 goto process_rest;
834 }
835 break;
836 case SMUX_GETRSP:
837 /* SMUX_GETRSP message is invalid for us. */
838 zlog_warn ("SMUX_GETRSP received: resetting connection.");
839 return -1;
840 break;
841 case SMUX_CLOSE:
842 /* Close SMUX connection. */
843 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000844 zlog_debug ("SMUX_CLOSE");
paul718e3742002-12-13 20:15:29 +0000845 smux_parse_close (ptr, len);
846 return -1;
847 break;
848 case SMUX_RRSP:
849 /* This is response for register message. */
850 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000851 zlog_debug ("SMUX_RRSP");
paul718e3742002-12-13 20:15:29 +0000852 smux_parse_rrsp (ptr, len);
853 break;
854 case SMUX_GET:
855 /* Exact request for object id. */
856 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000857 zlog_debug ("SMUX_GET");
paul718e3742002-12-13 20:15:29 +0000858 smux_parse_get (ptr, len, 1);
859 break;
860 case SMUX_GETNEXT:
861 /* Next request for object id. */
862 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000863 zlog_debug ("SMUX_GETNEXT");
paul718e3742002-12-13 20:15:29 +0000864 smux_parse_get (ptr, len, 0);
865 break;
866 case SMUX_SET:
867 /* SMUX_SET is supported with some limitations. */
868 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000869 zlog_debug ("SMUX_SET");
paul718e3742002-12-13 20:15:29 +0000870
871 /* save the data for future SMUX_SOUT */
872 memcpy (sout_save_buff, ptr, len);
873 sout_save_len = len;
874 smux_parse_set (ptr, len, RESERVE1);
875 break;
876 default:
877 zlog_info ("Unknown type: %d", type);
878 break;
879 }
880 return 0;
881}
882
883/* SMUX message read function. */
884int
885smux_read (struct thread *t)
886{
887 int sock;
888 int len;
889 u_char buf[SMUXMAXPKTSIZE];
890 int ret;
891
892 /* Clear thread. */
893 sock = THREAD_FD (t);
894 smux_read_thread = NULL;
895
896 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000897 zlog_debug ("SMUX read start");
paul718e3742002-12-13 20:15:29 +0000898
899 /* Read message from SMUX socket. */
900 len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
901
902 if (len < 0)
903 {
ajs6099b3b2004-11-20 02:06:59 +0000904 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000905 close (sock);
906 smux_sock = -1;
907 smux_event (SMUX_CONNECT, 0);
908 return -1;
909 }
910
911 if (len == 0)
912 {
913 zlog_warn ("SMUX connection closed: %d", sock);
914 close (sock);
915 smux_sock = -1;
916 smux_event (SMUX_CONNECT, 0);
917 return -1;
918 }
919
920 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +0000921 zlog_debug ("SMUX read len: %d", len);
paul718e3742002-12-13 20:15:29 +0000922
923 /* Parse the message. */
924 ret = smux_parse (buf, len);
925
926 if (ret < 0)
927 {
928 close (sock);
929 smux_sock = -1;
930 smux_event (SMUX_CONNECT, 0);
931 return -1;
932 }
933
934 /* Regiser read thread. */
935 smux_event (SMUX_READ, sock);
936
937 return 0;
938}
939
940int
941smux_open (int sock)
942{
943 u_char buf[BUFSIZ];
944 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +0000945 size_t len;
paul718e3742002-12-13 20:15:29 +0000946 u_long version;
paul42053f42003-08-13 02:54:44 +0000947 u_char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION;
paul718e3742002-12-13 20:15:29 +0000948
949 if (debug_smux)
950 {
951 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
ajs8ddca702004-12-07 18:53:52 +0000952 zlog_debug ("SMUX open progname: %s", progname);
953 zlog_debug ("SMUX open password: %s", smux_passwd);
paul718e3742002-12-13 20:15:29 +0000954 }
955
956 ptr = buf;
957 len = BUFSIZ;
958
959 /* SMUX Header. As placeholder. */
960 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
961
962 /* SMUX Open. */
963 version = 0;
964 ptr = asn_build_int (ptr, &len,
965 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
966 &version, sizeof (u_long));
967
968 /* SMUX connection oid. */
969 ptr = asn_build_objid (ptr, &len,
970 (u_char)
971 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
972 smux_oid, smux_oid_len);
973
974 /* SMUX connection description. */
975 ptr = asn_build_string (ptr, &len,
976 (u_char)
977 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
978 progname, strlen (progname));
979
980 /* SMUX connection password. */
981 ptr = asn_build_string (ptr, &len,
982 (u_char)
983 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
984 smux_passwd, strlen (smux_passwd));
985
986 /* Fill in real SMUX header. We exclude ASN header size (2). */
987 len = BUFSIZ;
988 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
989
990 return send (sock, buf, (ptr - buf), 0);
991}
992
993int
994smux_trap (oid *name, size_t namelen,
995 oid *iname, size_t inamelen,
996 struct trap_object *trapobj, size_t trapobjlen,
paul020709f2003-04-04 02:44:16 +0000997 unsigned int tick, u_char sptrap)
paul718e3742002-12-13 20:15:29 +0000998{
paul9035efa2004-10-10 11:56:56 +0000999 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001000 u_char buf[BUFSIZ];
1001 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +00001002 size_t len, length;
paul718e3742002-12-13 20:15:29 +00001003 struct in_addr addr;
1004 unsigned long val;
1005 u_char *h1, *h1e;
1006
1007 ptr = buf;
1008 len = BUFSIZ;
1009 length = len;
1010
1011 /* When SMUX connection is not established. */
1012 if (smux_sock < 0)
1013 return 0;
1014
1015 /* SMUX header. */
1016 ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
1017
1018 /* Sub agent enterprise oid. */
1019 ptr = asn_build_objid (ptr, &len,
1020 (u_char)
1021 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1022 smux_oid, smux_oid_len);
1023
1024 /* IP address. */
1025 addr.s_addr = 0;
1026 ptr = asn_build_string (ptr, &len,
1027 (u_char)
1028 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
1029 (u_char *)&addr, sizeof (struct in_addr));
1030
1031 /* Generic trap integer. */
1032 val = SNMP_TRAP_ENTERPRISESPECIFIC;
1033 ptr = asn_build_int (ptr, &len,
1034 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1035 &val, sizeof (int));
1036
1037 /* Specific trap integer. */
paul020709f2003-04-04 02:44:16 +00001038 val = sptrap;
paul718e3742002-12-13 20:15:29 +00001039 ptr = asn_build_int (ptr, &len,
1040 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1041 &val, sizeof (int));
1042
1043 /* Timeticks timestamp. */
1044 val = 0;
1045 ptr = asn_build_unsigned_int (ptr, &len,
1046 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS),
1047 &val, sizeof (int));
1048
1049 /* Variables. */
1050 h1 = ptr;
1051 ptr = asn_build_sequence (ptr, &len,
1052 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1053 0);
1054
1055
1056 /* Iteration for each objects. */
1057 h1e = ptr;
1058 for (i = 0; i < trapobjlen; i++)
1059 {
1060 int ret;
1061 oid oid[MAX_OID_LEN];
1062 size_t oid_len;
1063 void *val;
1064 size_t val_len;
1065 u_char val_type;
1066
1067 /* Make OID. */
1068 oid_copy (oid, name, namelen);
1069 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen);
1070 oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen);
1071 oid_len = namelen + trapobj[i].namelen + inamelen;
1072
1073 if (debug_smux)
1074 smux_oid_dump ("Trap", oid, oid_len);
1075
1076 ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
1077
1078 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +00001079 zlog_debug ("smux_get result %d", ret);
paul718e3742002-12-13 20:15:29 +00001080
1081 if (ret == 0)
1082 ptr = snmp_build_var_op (ptr, oid, &oid_len,
1083 val_type, val_len, val, &len);
1084 }
1085
1086 /* Now variable size is known, fill in size */
1087 asn_build_sequence(h1, &length,
1088 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1089 ptr - h1e);
1090
1091 /* Fill in size of whole sequence */
1092 len = BUFSIZ;
1093 asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
1094
1095 return send (smux_sock, buf, (ptr - buf), 0);
1096}
1097
1098int
1099smux_register (int sock)
1100{
1101 u_char buf[BUFSIZ];
1102 u_char *ptr;
paul70e149e2004-10-31 16:29:50 +00001103 int ret;
1104 size_t len;
paul718e3742002-12-13 20:15:29 +00001105 long priority;
1106 long operation;
1107 struct subtree *subtree;
paul1eb8ef22005-04-07 07:30:20 +00001108 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00001109
1110 ret = 0;
1111
paul1eb8ef22005-04-07 07:30:20 +00001112 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
paul718e3742002-12-13 20:15:29 +00001113 {
1114 ptr = buf;
1115 len = BUFSIZ;
1116
paul718e3742002-12-13 20:15:29 +00001117 /* SMUX RReq Header. */
1118 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
1119
1120 /* Register MIB tree. */
1121 ptr = asn_build_objid (ptr, &len,
1122 (u_char)
1123 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1124 subtree->name, subtree->name_len);
1125
1126 /* Priority. */
1127 priority = -1;
1128 ptr = asn_build_int (ptr, &len,
1129 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1130 &priority, sizeof (u_long));
1131
1132 /* Operation. */
1133 operation = 2; /* Register R/W */
1134 ptr = asn_build_int (ptr, &len,
1135 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1136 &operation, sizeof (u_long));
1137
1138 if (debug_smux)
1139 {
1140 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
ajs8ddca702004-12-07 18:53:52 +00001141 zlog_debug ("SMUX register priority: %ld", priority);
1142 zlog_debug ("SMUX register operation: %ld", operation);
paul718e3742002-12-13 20:15:29 +00001143 }
1144
1145 len = BUFSIZ;
1146 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
1147 ret = send (sock, buf, (ptr - buf), 0);
1148 if (ret < 0)
1149 return ret;
1150 }
1151 return ret;
1152}
1153
1154/* Try to connect to SNMP agent. */
1155int
1156smux_connect (struct thread *t)
1157{
1158 int ret;
1159
1160 if (debug_smux)
ajs8ddca702004-12-07 18:53:52 +00001161 zlog_debug ("SMUX connect try %d", fail + 1);
paul718e3742002-12-13 20:15:29 +00001162
1163 /* Clear thread poner of myself. */
1164 smux_connect_thread = NULL;
1165
1166 /* Make socket. Try to connect. */
1167 smux_sock = smux_socket ();
1168 if (smux_sock < 0)
1169 {
1170 if (++fail < SMUX_MAX_FAILURE)
1171 smux_event (SMUX_CONNECT, 0);
1172 return 0;
1173 }
1174
1175 /* Send OPEN PDU. */
1176 ret = smux_open (smux_sock);
1177 if (ret < 0)
1178 {
ajs6099b3b2004-11-20 02:06:59 +00001179 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001180 close (smux_sock);
1181 smux_sock = -1;
1182 if (++fail < SMUX_MAX_FAILURE)
1183 smux_event (SMUX_CONNECT, 0);
1184 return -1;
1185 }
1186
1187 /* Send any outstanding register PDUs. */
1188 ret = smux_register (smux_sock);
1189 if (ret < 0)
1190 {
ajs6099b3b2004-11-20 02:06:59 +00001191 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001192 close (smux_sock);
1193 smux_sock = -1;
1194 if (++fail < SMUX_MAX_FAILURE)
1195 smux_event (SMUX_CONNECT, 0);
1196 return -1;
1197 }
1198
1199 /* Everything goes fine. */
1200 smux_event (SMUX_READ, smux_sock);
1201
1202 return 0;
1203}
1204
1205/* Clear all SMUX related resources. */
1206void
1207smux_stop ()
1208{
1209 if (smux_read_thread)
1210 thread_cancel (smux_read_thread);
1211 if (smux_connect_thread)
1212 thread_cancel (smux_connect_thread);
1213
1214 if (smux_sock >= 0)
1215 {
1216 close (smux_sock);
1217 smux_sock = -1;
1218 }
1219}
1220
pauldd488a72003-06-19 01:21:07 +00001221
paul718e3742002-12-13 20:15:29 +00001222
1223void
1224smux_event (enum smux_event event, int sock)
1225{
1226 switch (event)
1227 {
1228 case SMUX_SCHEDULE:
1229 smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
1230 break;
1231 case SMUX_CONNECT:
1232 smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
1233 break;
1234 case SMUX_READ:
1235 smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
1236 break;
1237 default:
1238 break;
1239 }
1240}
1241
1242int
paul9035efa2004-10-10 11:56:56 +00001243smux_str2oid (const char *str, oid *oid, size_t *oid_len)
paul718e3742002-12-13 20:15:29 +00001244{
1245 int len;
1246 int val;
1247
1248 len = 0;
1249 val = 0;
1250 *oid_len = 0;
1251
1252 if (*str == '.')
1253 str++;
1254 if (*str == '\0')
1255 return 0;
1256
1257 while (1)
1258 {
1259 if (! isdigit (*str))
1260 return -1;
1261
1262 while (isdigit (*str))
1263 {
1264 val *= 10;
1265 val += (*str - '0');
1266 str++;
1267 }
1268
1269 if (*str == '\0')
1270 break;
1271 if (*str != '.')
1272 return -1;
1273
1274 oid[len++] = val;
1275 val = 0;
1276 str++;
1277 }
1278
1279 oid[len++] = val;
1280 *oid_len = len;
1281
1282 return 0;
1283}
1284
1285oid *
1286smux_oid_dup (oid *objid, size_t objid_len)
1287{
1288 oid *new;
1289
1290 new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
1291 oid_copy (new, objid, objid_len);
1292
1293 return new;
1294}
1295
1296int
paul9035efa2004-10-10 11:56:56 +00001297smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str)
paul718e3742002-12-13 20:15:29 +00001298{
1299 int ret;
1300 oid oid[MAX_OID_LEN];
1301 size_t oid_len;
1302
1303 ret = smux_str2oid (oid_str, oid, &oid_len);
1304 if (ret != 0)
1305 {
1306 vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
1307 return CMD_WARNING;
1308 }
1309
hassoc75105a2004-10-13 10:33:26 +00001310 if (smux_oid)
1311 {
1312 free (smux_oid);
1313 smux_oid = NULL;
1314 }
paul718e3742002-12-13 20:15:29 +00001315
paul9035efa2004-10-10 11:56:56 +00001316 /* careful, smux_passwd might point to string constant */
hassoc75105a2004-10-13 10:33:26 +00001317 if (smux_passwd)
paul718e3742002-12-13 20:15:29 +00001318 {
1319 free (smux_passwd);
1320 smux_passwd = NULL;
1321 }
1322
1323 smux_oid = smux_oid_dup (oid, oid_len);
1324 smux_oid_len = oid_len;
1325
1326 if (passwd_str)
1327 smux_passwd = strdup (passwd_str);
hassoc75105a2004-10-13 10:33:26 +00001328 else
1329 smux_passwd = strdup ("");
paul718e3742002-12-13 20:15:29 +00001330
hassoc75105a2004-10-13 10:33:26 +00001331 return 0;
paul718e3742002-12-13 20:15:29 +00001332}
1333
1334int
1335smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1336 size_t *var_len, WriteMethod **write_method)
1337{
1338 oid fulloid[MAX_OID_LEN];
1339 int ret;
1340
1341 oid_copy (fulloid, v->name, v->namelen);
1342 fulloid[v->namelen] = 0;
1343 /* Check against full instance. */
1344 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1345
1346 /* Check single instance. */
1347 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1348 return MATCH_FAILED;
1349
1350 /* In case of getnext, fill in full instance. */
1351 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1352 *length = v->namelen + 1;
1353
1354 *write_method = 0;
1355 *var_len = sizeof(long); /* default to 'long' results */
1356
1357 return MATCH_SUCCEEDED;
1358}
1359
1360int
1361smux_peer_default ()
1362{
hassoc75105a2004-10-13 10:33:26 +00001363 if (smux_oid)
paul718e3742002-12-13 20:15:29 +00001364 {
1365 free (smux_oid);
hassoc75105a2004-10-13 10:33:26 +00001366 smux_oid = NULL;
paul718e3742002-12-13 20:15:29 +00001367 }
paul9035efa2004-10-10 11:56:56 +00001368
1369 /* careful, smux_passwd might be pointing at string constant */
hassoc75105a2004-10-13 10:33:26 +00001370 if (smux_passwd)
paul718e3742002-12-13 20:15:29 +00001371 {
1372 free (smux_passwd);
hassoc75105a2004-10-13 10:33:26 +00001373 smux_passwd = NULL;
paul718e3742002-12-13 20:15:29 +00001374 }
hassoc75105a2004-10-13 10:33:26 +00001375
paul718e3742002-12-13 20:15:29 +00001376 return CMD_SUCCESS;
1377}
1378
1379DEFUN (smux_peer,
1380 smux_peer_cmd,
1381 "smux peer OID",
1382 "SNMP MUX protocol settings\n"
1383 "SNMP MUX peer settings\n"
1384 "Object ID used in SMUX peering\n")
1385{
hassoc75105a2004-10-13 10:33:26 +00001386 if (smux_peer_oid (vty, argv[0], NULL) == 0)
1387 {
1388 smux_start();
1389 return CMD_SUCCESS;
1390 }
1391 else
1392 return CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00001393}
1394
1395DEFUN (smux_peer_password,
1396 smux_peer_password_cmd,
1397 "smux peer OID PASSWORD",
1398 "SNMP MUX protocol settings\n"
1399 "SNMP MUX peer settings\n"
1400 "SMUX peering object ID\n"
1401 "SMUX peering password\n")
1402{
hassoc75105a2004-10-13 10:33:26 +00001403 if (smux_peer_oid (vty, argv[0], argv[1]) == 0)
1404 {
1405 smux_start();
1406 return CMD_SUCCESS;
1407 }
1408 else
1409 return CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00001410}
1411
1412DEFUN (no_smux_peer,
1413 no_smux_peer_cmd,
hassoc75105a2004-10-13 10:33:26 +00001414 "no smux peer",
1415 NO_STR
1416 "SNMP MUX protocol settings\n"
1417 "SNMP MUX peer settings\n")
1418{
1419 smux_stop();
1420 return smux_peer_default ();
1421}
1422
1423ALIAS (no_smux_peer,
1424 no_smux_peer_oid_cmd,
paul718e3742002-12-13 20:15:29 +00001425 "no smux peer OID",
1426 NO_STR
1427 "SNMP MUX protocol settings\n"
1428 "SNMP MUX peer settings\n"
hassoc75105a2004-10-13 10:33:26 +00001429 "SMUX peering object ID\n")
paul718e3742002-12-13 20:15:29 +00001430
hassoc75105a2004-10-13 10:33:26 +00001431ALIAS (no_smux_peer,
1432 no_smux_peer_oid_password_cmd,
paul718e3742002-12-13 20:15:29 +00001433 "no smux peer OID PASSWORD",
1434 NO_STR
1435 "SNMP MUX protocol settings\n"
1436 "SNMP MUX peer settings\n"
1437 "SMUX peering object ID\n"
1438 "SMUX peering password\n")
paul718e3742002-12-13 20:15:29 +00001439
1440int
1441config_write_smux (struct vty *vty)
1442{
1443 int first = 1;
paul9035efa2004-10-10 11:56:56 +00001444 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001445
hassoc75105a2004-10-13 10:33:26 +00001446 if (smux_oid)
paul718e3742002-12-13 20:15:29 +00001447 {
1448 vty_out (vty, "smux peer ");
1449 for (i = 0; i < smux_oid_len; i++)
1450 {
1451 vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
1452 first = 0;
1453 }
1454 vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
1455 }
1456 return 0;
1457}
1458
1459/* Register subtree to smux master tree. */
1460void
paulc9eca012004-10-11 11:28:44 +00001461smux_register_mib (const char *descr, struct variable *var,
1462 size_t width, int num,
paul718e3742002-12-13 20:15:29 +00001463 oid name[], size_t namelen)
1464{
1465 struct subtree *tree;
1466
1467 tree = (struct subtree *)malloc(sizeof(struct subtree));
1468 oid_copy (tree->name, name, namelen);
1469 tree->name_len = namelen;
1470 tree->variables = var;
1471 tree->variables_num = num;
1472 tree->variables_width = width;
1473 tree->registered = 0;
1474 listnode_add_sort(treelist, tree);
1475}
1476
1477void
1478smux_reset ()
1479{
1480 /* Setting configuration to default. */
1481 smux_peer_default ();
1482}
1483
1484/* Compare function to keep treelist sorted */
1485static int
1486smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
1487{
1488 return oid_compare(tree1->name, tree1->name_len,
1489 tree2->name, tree2->name_len);
1490}
1491
1492/* Initialize some values then schedule first SMUX connection. */
1493void
hassoc75105a2004-10-13 10:33:26 +00001494smux_init (struct thread_master *tm)
paul718e3742002-12-13 20:15:29 +00001495{
pauldd488a72003-06-19 01:21:07 +00001496 /* copy callers thread master */
1497 master = tm;
paul718e3742002-12-13 20:15:29 +00001498
1499 /* Make MIB tree. */
1500 treelist = list_new();
1501 treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
1502
1503 /* Install commands. */
1504 install_node (&smux_node, config_write_smux);
1505
1506 install_element (CONFIG_NODE, &smux_peer_cmd);
1507 install_element (CONFIG_NODE, &smux_peer_password_cmd);
1508 install_element (CONFIG_NODE, &no_smux_peer_cmd);
hassoc75105a2004-10-13 10:33:26 +00001509 install_element (CONFIG_NODE, &no_smux_peer_oid_cmd);
1510 install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd);
paul718e3742002-12-13 20:15:29 +00001511}
1512
1513void
1514smux_start(void)
1515{
1516 /* Schedule first connection. */
1517 smux_event (SMUX_SCHEDULE, 0);
1518}
1519#endif /* HAVE_SNMP */