Merged own patch for bug #390 (rewrite zebra/zebra_rib.c:nexthop_active_update())
[jleu-quagga.git] / lib / smux.c
blob8218c44081e44c907c10e369ba1dc3b49d607a08
1 /* SNMP support
2 * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
22 #include <zebra.h>
24 #ifdef HAVE_SNMP
25 #ifdef HAVE_NETSNMP
26 #include <net-snmp/net-snmp-config.h>
27 #endif
28 #include <asn1.h>
29 #include <snmp.h>
30 #include <snmp_impl.h>
32 #include "log.h"
33 #include "thread.h"
34 #include "linklist.h"
35 #include "command.h"
36 #include <lib/version.h>
37 #include "memory.h"
38 #include "sockunion.h"
39 #include "smux.h"
41 #define min(A,B) ((A) < (B) ? (A) : (B))
43 enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
45 void smux_event (enum smux_event, int);
48 /* SMUX socket. */
49 int smux_sock = -1;
51 /* SMUX subtree list. */
52 struct list *treelist;
54 /* SMUX oid. */
55 oid *smux_oid = NULL;
56 size_t smux_oid_len;
58 /* SMUX password. */
59 char *smux_passwd = NULL;
61 /* SMUX read threads. */
62 struct thread *smux_read_thread;
64 /* SMUX connect thrads. */
65 struct thread *smux_connect_thread;
67 /* SMUX debug flag. */
68 int debug_smux = 0;
70 /* SMUX failure count. */
71 int fail = 0;
73 /* SMUX node. */
74 struct cmd_node smux_node =
76 SMUX_NODE,
77 "" /* SMUX has no interface. */
80 /* thread master */
81 static struct thread_master *master;
83 void *
84 oid_copy (void *dest, void *src, size_t size)
86 return memcpy (dest, src, size * sizeof (oid));
89 void
90 oid2in_addr (oid oid[], int len, struct in_addr *addr)
92 int i;
93 u_char *pnt;
95 if (len == 0)
96 return;
98 pnt = (u_char *) addr;
100 for (i = 0; i < len; i++)
101 *pnt++ = oid[i];
104 void
105 oid_copy_addr (oid oid[], struct in_addr *addr, int len)
107 int i;
108 u_char *pnt;
110 if (len == 0)
111 return;
113 pnt = (u_char *) addr;
115 for (i = 0; i < len; i++)
116 oid[i] = *pnt++;
120 oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
122 int i;
124 for (i = 0; i < min (o1_len, o2_len); i++)
126 if (o1[i] < o2[i])
127 return -1;
128 else if (o1[i] > o2[i])
129 return 1;
131 if (o1_len < o2_len)
132 return -1;
133 if (o1_len > o2_len)
134 return 1;
136 return 0;
140 oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
142 int i;
144 for (i = 0; i < min (o1_len, o2_len); i++)
146 if (o1[i] < o2[i])
147 return -1;
148 else if (o1[i] > o2[i])
149 return 1;
151 if (o1_len < o2_len)
152 return -1;
154 return 0;
157 void
158 smux_oid_dump (const char *prefix, oid *oid, size_t oid_len)
160 unsigned int i;
161 int first = 1;
162 char buf[MAX_OID_LEN * 3];
164 buf[0] = '\0';
166 for (i = 0; i < oid_len; i++)
168 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
169 first = 0;
171 zlog_debug ("%s: %s", prefix, buf);
175 smux_socket ()
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;
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)
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);
199 if (gai)
201 zlog_warn("Cannot locate loopback service smux");
202 return -1;
204 for(res=res0; res; res=res->ai_next)
206 if (res->ai_family != AF_INET
207 #ifdef HAVE_IPV6
208 && res->ai_family != AF_INET6
209 #endif /* HAVE_IPV6 */
211 continue;
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)
221 close(sock);
222 sock = -1;
223 continue;
225 break;
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)
234 zlog_warn ("Can't make socket for SNMP");
235 return -1;
238 memset (&serv, 0, sizeof (struct sockaddr_in));
239 serv.sin_family = AF_INET;
240 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
241 serv.sin_len = sizeof (struct sockaddr_in);
242 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
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);
250 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
252 sockopt_reuseaddr (sock);
253 sockopt_reuseport (sock);
255 ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
256 if (ret < 0)
258 close (sock);
259 smux_sock = -1;
260 zlog_warn ("Can't connect to SNMP agent with SMUX");
261 return -1;
263 #endif
264 return sock;
267 void
268 smux_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)
271 int ret;
272 u_char buf[BUFSIZ];
273 u_char *ptr, *h1, *h1e, *h2, *h2e;
274 size_t len, length;
276 ptr = buf;
277 len = BUFSIZ;
278 length = len;
280 if (debug_smux)
282 zlog_debug ("SMUX GETRSP send");
283 zlog_debug ("SMUX GETRSP reqid: %ld", reqid);
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;
291 ptr = asn_build_int (ptr, &len,
292 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
293 &reqid, sizeof (reqid));
295 if (debug_smux)
296 zlog_debug ("SMUX GETRSP errstat: %ld", errstat);
298 ptr = asn_build_int (ptr, &len,
299 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
300 &errstat, sizeof (errstat));
301 if (debug_smux)
302 zlog_debug ("SMUX GETRSP errindex: %ld", errindex);
304 ptr = asn_build_int (ptr, &len,
305 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
306 &errindex, sizeof (errindex));
308 h2 = ptr;
309 /* Place holder h2 for one variable */
310 ptr = asn_build_sequence (ptr, &len,
311 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
313 h2e = ptr;
315 ptr = snmp_build_var_op (ptr, objid, &objid_len,
316 val_type, arg_len, arg, &len);
318 /* Now variable size is known, fill in size */
319 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
321 /* Fill in size of whole sequence */
322 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
324 if (debug_smux)
325 zlog_debug ("SMUX getresp send: %ld", (ptr - buf));
327 ret = send (smux_sock, buf, (ptr - buf), 0);
330 char *
331 smux_var (char *ptr, size_t len, oid objid[], size_t *objid_len,
332 size_t *var_val_len,
333 u_char *var_val_type,
334 void **var_value)
336 u_char type;
337 u_char val_type;
338 size_t val_len;
339 u_char *val;
341 if (debug_smux)
342 zlog_debug ("SMUX var parse: len %ld", len);
344 /* Parse header. */
345 ptr = asn_parse_header (ptr, &len, &type);
347 if (debug_smux)
349 zlog_debug ("SMUX var parse: type %d len %ld", type, len);
350 zlog_debug ("SMUX var parse: type must be %d",
351 (ASN_SEQUENCE | ASN_CONSTRUCTOR));
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);
359 if (var_val_len)
360 *var_val_len = val_len;
362 if (var_value)
363 *var_value = (void*) val;
365 if (var_val_type)
366 *var_val_type = val_type;
368 /* Requested object id length is objid_len. */
369 if (debug_smux)
370 smux_oid_dump ("Request OID", objid, *objid_len);
372 if (debug_smux)
373 zlog_debug ("SMUX val_type: %d", val_type);
375 /* Check request value type. */
376 if (debug_smux)
377 switch (val_type)
379 case ASN_NULL:
380 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
381 ASN_NULL. */
382 zlog_debug ("ASN_NULL");
383 break;
385 case ASN_INTEGER:
386 zlog_debug ("ASN_INTEGER");
387 break;
388 case ASN_COUNTER:
389 case ASN_GAUGE:
390 case ASN_TIMETICKS:
391 case ASN_UINTEGER:
392 zlog_debug ("ASN_COUNTER");
393 break;
394 case ASN_COUNTER64:
395 zlog_debug ("ASN_COUNTER64");
396 break;
397 case ASN_IPADDRESS:
398 zlog_debug ("ASN_IPADDRESS");
399 break;
400 case ASN_OCTET_STR:
401 zlog_debug ("ASN_OCTET_STR");
402 break;
403 case ASN_OPAQUE:
404 case ASN_NSAP:
405 case ASN_OBJECT_ID:
406 zlog_debug ("ASN_OPAQUE");
407 break;
408 case SNMP_NOSUCHOBJECT:
409 zlog_debug ("SNMP_NOSUCHOBJECT");
410 break;
411 case SNMP_NOSUCHINSTANCE:
412 zlog_debug ("SNMP_NOSUCHINSTANCE");
413 break;
414 case SNMP_ENDOFMIBVIEW:
415 zlog_debug ("SNMP_ENDOFMIBVIEW");
416 break;
417 case ASN_BIT_STR:
418 zlog_debug ("ASN_BIT_STR");
419 break;
420 default:
421 zlog_debug ("Unknown type");
422 break;
424 return ptr;
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. */
432 smux_set (oid *reqid, size_t *reqid_len,
433 u_char val_type, void *val, size_t val_len, int action)
435 int j;
436 struct subtree *subtree;
437 struct variable *v;
438 int subresult;
439 oid *suffix;
440 size_t suffix_len;
441 int result;
442 u_char *statP = NULL;
443 WriteMethod *write_method = NULL;
444 struct listnode *node, *nnode;
446 /* Check */
447 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
449 subresult = oid_compare_part (reqid, *reqid_len,
450 subtree->name, subtree->name_len);
452 /* Subtree matched. */
453 if (subresult == 0)
455 /* Prepare suffix. */
456 suffix = reqid + subtree->name_len;
457 suffix_len = *reqid_len - subtree->name_len;
458 result = subresult;
460 /* Check variables. */
461 for (j = 0; j < subtree->variables_num; j++)
463 v = &subtree->variables[j];
465 /* Always check suffix */
466 result = oid_compare_part (suffix, suffix_len,
467 v->name, v->namelen);
469 /* This is exact match so result must be zero. */
470 if (result == 0)
472 if (debug_smux)
473 zlog_debug ("SMUX function call index is %d", v->magic);
475 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
476 &val_len, &write_method);
478 if (write_method)
480 return (*write_method)(action, val, val_type, val_len,
481 statP, suffix, suffix_len, v);
483 else
485 return SNMP_ERR_READONLY;
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;
496 return SNMP_ERR_NOSUCHNAME;
500 smux_get (oid *reqid, size_t *reqid_len, int exact,
501 u_char *val_type,void **val, size_t *val_len)
503 int j;
504 struct subtree *subtree;
505 struct variable *v;
506 int subresult;
507 oid *suffix;
508 size_t suffix_len;
509 int result;
510 WriteMethod *write_method=NULL;
511 struct listnode *node, *nnode;
513 /* Check */
514 for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree))
516 subresult = oid_compare_part (reqid, *reqid_len,
517 subtree->name, subtree->name_len);
519 /* Subtree matched. */
520 if (subresult == 0)
522 /* Prepare suffix. */
523 suffix = reqid + subtree->name_len;
524 suffix_len = *reqid_len - subtree->name_len;
525 result = subresult;
527 /* Check variables. */
528 for (j = 0; j < subtree->variables_num; j++)
530 v = &subtree->variables[j];
532 /* Always check suffix */
533 result = oid_compare_part (suffix, suffix_len,
534 v->name, v->namelen);
536 /* This is exact match so result must be zero. */
537 if (result == 0)
539 if (debug_smux)
540 zlog_debug ("SMUX function call index is %d", v->magic);
542 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
543 val_len, &write_method);
545 /* There is no instance. */
546 if (*val == NULL)
547 return SNMP_NOSUCHINSTANCE;
549 /* Call is suceed. */
550 *val_type = v->type;
552 return 0;
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;
562 return SNMP_ERR_NOSUCHNAME;
566 smux_getnext (oid *reqid, size_t *reqid_len, int exact,
567 u_char *val_type,void **val, size_t *val_len)
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;
576 size_t suffix_len;
577 int result;
578 WriteMethod *write_method=NULL;
579 struct listnode *node, *nnode;
582 /* Save incoming request. */
583 oid_copy (save, reqid, *reqid_len);
584 savelen = *reqid_len;
586 /* Check */
587 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
589 subresult = oid_compare_part (reqid, *reqid_len,
590 subtree->name, subtree->name_len);
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 */
603 if (subresult <= 0)
605 /* Prepare suffix. */
606 suffix = reqid + subtree->name_len;
607 suffix_len = *reqid_len - subtree->name_len;
608 if (subresult < 0)
610 oid_copy(reqid, subtree->name, subtree->name_len);
611 *reqid_len = subtree->name_len;
613 for (j = 0; j < subtree->variables_num; j++)
615 result = subresult;
616 v = &subtree->variables[j];
618 /* Next then check result >= 0. */
619 if (result == 0)
620 result = oid_compare_part (suffix, suffix_len,
621 v->name, v->namelen);
623 if (result <= 0)
625 if (debug_smux)
626 zlog_debug ("SMUX function call index is %d", v->magic);
627 if(result<0)
629 oid_copy(suffix, v->name, v->namelen);
630 suffix_len = v->namelen;
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)
637 *val_type = v->type;
638 return 0;
644 memcpy (reqid, save, savelen * sizeof(oid));
645 *reqid_len = savelen;
647 return SNMP_ERR_NOSUCHNAME;
650 /* GET message header. */
651 char *
652 smux_parse_get_header (char *ptr, size_t *len, long *reqid)
654 u_char type;
655 long errstat;
656 long errindex;
658 /* Request ID. */
659 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
661 if (debug_smux)
662 zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
664 /* Error status. */
665 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
667 if (debug_smux)
668 zlog_debug ("SMUX GET errstat %ld len: %ld", errstat, *len);
670 /* Error index. */
671 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
673 if (debug_smux)
674 zlog_debug ("SMUX GET errindex %ld len: %ld", errindex, *len);
676 return ptr;
679 void
680 smux_parse_set (char *ptr, size_t len, int action)
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;
690 if (debug_smux)
691 zlog_debug ("SMUX SET(%s) message parse: len %ld",
692 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
693 len);
695 /* Parse SET message header. */
696 ptr = smux_parse_get_header (ptr, &len, &reqid);
698 /* Parse SET message object ID. */
699 ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
701 ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
702 if (debug_smux)
703 zlog_debug ("SMUX SET ret %d", ret);
705 /* Return result. */
706 if (RESERVE1 == action)
707 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
710 void
711 smux_parse_get (char *ptr, size_t len, int exact)
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;
721 if (debug_smux)
722 zlog_debug ("SMUX GET message parse: len %ld", len);
724 /* Parse GET message header. */
725 ptr = smux_parse_get_header (ptr, &len, &reqid);
727 /* Parse GET message object ID. We needn't the value come */
728 ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
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);
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);
743 /* Parse SMUX_CLOSE message. */
744 void
745 smux_parse_close (char *ptr, int len)
747 long reason = 0;
749 while (len--)
751 reason = (reason << 8) | (long) *ptr;
752 ptr++;
754 zlog_info ("SMUX_CLOSE with reason: %ld", reason);
757 /* SMUX_RRSP message. */
758 void
759 smux_parse_rrsp (char *ptr, size_t len)
761 char val;
762 long errstat;
764 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
766 if (debug_smux)
767 zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
770 /* Parse SMUX message. */
772 smux_parse (char *ptr, size_t len)
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;
780 int len_income = len; /* see note below: YYY */
781 u_char type;
782 u_char rollback;
784 rollback = ptr[2]; /* important only for SMUX_SOUT */
786 process_rest: /* see note below: YYY */
788 /* Parse SMUX message type and subsequent length. */
789 ptr = asn_parse_header (ptr, &len, &type);
791 if (debug_smux)
792 zlog_debug ("SMUX message received type: %d rest len: %ld", type, len);
794 switch (type)
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)
809 zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
811 if (sout_save_len > 0)
813 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
814 sout_save_len = 0;
816 else
817 zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
819 if (len_income > 3)
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;
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)
844 zlog_debug ("SMUX_CLOSE");
845 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)
851 zlog_debug ("SMUX_RRSP");
852 smux_parse_rrsp (ptr, len);
853 break;
854 case SMUX_GET:
855 /* Exact request for object id. */
856 if (debug_smux)
857 zlog_debug ("SMUX_GET");
858 smux_parse_get (ptr, len, 1);
859 break;
860 case SMUX_GETNEXT:
861 /* Next request for object id. */
862 if (debug_smux)
863 zlog_debug ("SMUX_GETNEXT");
864 smux_parse_get (ptr, len, 0);
865 break;
866 case SMUX_SET:
867 /* SMUX_SET is supported with some limitations. */
868 if (debug_smux)
869 zlog_debug ("SMUX_SET");
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;
880 return 0;
883 /* SMUX message read function. */
885 smux_read (struct thread *t)
887 int sock;
888 int len;
889 u_char buf[SMUXMAXPKTSIZE];
890 int ret;
892 /* Clear thread. */
893 sock = THREAD_FD (t);
894 smux_read_thread = NULL;
896 if (debug_smux)
897 zlog_debug ("SMUX read start");
899 /* Read message from SMUX socket. */
900 len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
902 if (len < 0)
904 zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno));
905 close (sock);
906 smux_sock = -1;
907 smux_event (SMUX_CONNECT, 0);
908 return -1;
911 if (len == 0)
913 zlog_warn ("SMUX connection closed: %d", sock);
914 close (sock);
915 smux_sock = -1;
916 smux_event (SMUX_CONNECT, 0);
917 return -1;
920 if (debug_smux)
921 zlog_debug ("SMUX read len: %d", len);
923 /* Parse the message. */
924 ret = smux_parse (buf, len);
926 if (ret < 0)
928 close (sock);
929 smux_sock = -1;
930 smux_event (SMUX_CONNECT, 0);
931 return -1;
934 /* Regiser read thread. */
935 smux_event (SMUX_READ, sock);
937 return 0;
941 smux_open (int sock)
943 u_char buf[BUFSIZ];
944 u_char *ptr;
945 size_t len;
946 u_long version;
947 u_char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION;
949 if (debug_smux)
951 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
952 zlog_debug ("SMUX open progname: %s", progname);
953 zlog_debug ("SMUX open password: %s", smux_passwd);
956 ptr = buf;
957 len = BUFSIZ;
959 /* SMUX Header. As placeholder. */
960 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
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 (version));
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);
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));
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));
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);
990 return send (sock, buf, (ptr - buf), 0);
994 smux_trap (oid *name, size_t namelen,
995 oid *iname, size_t inamelen,
996 struct trap_object *trapobj, size_t trapobjlen,
997 unsigned int tick, u_char sptrap)
999 unsigned int i;
1000 u_char buf[BUFSIZ];
1001 u_char *ptr;
1002 size_t len, length;
1003 struct in_addr addr;
1004 unsigned long val;
1005 u_char *h1, *h1e;
1007 ptr = buf;
1008 len = BUFSIZ;
1009 length = len;
1011 /* When SMUX connection is not established. */
1012 if (smux_sock < 0)
1013 return 0;
1015 /* SMUX header. */
1016 ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
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);
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 (addr));
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 (val));
1037 /* Specific trap integer. */
1038 val = sptrap;
1039 ptr = asn_build_int (ptr, &len,
1040 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1041 &val, sizeof (val));
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 (val));
1049 /* Variables. */
1050 h1 = ptr;
1051 ptr = asn_build_sequence (ptr, &len,
1052 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1056 /* Iteration for each objects. */
1057 h1e = ptr;
1058 for (i = 0; i < trapobjlen; i++)
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;
1067 /* Make OID. */
1068 if (trapobj[i].namelen > 0)
1070 oid_copy (oid, name, namelen);
1071 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen);
1072 oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen);
1073 oid_len = namelen + trapobj[i].namelen + inamelen;
1075 else
1077 oid_copy (oid, name, namelen);
1078 oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen * (-1));
1079 oid_len = namelen + trapobj[i].namelen * (-1) ;
1082 if (debug_smux)
1084 smux_oid_dump ("Trap", name, namelen);
1085 if (trapobj[i].namelen < 0)
1086 smux_oid_dump ("Trap",
1087 trapobj[i].name, (- 1) * (trapobj[i].namelen));
1088 else
1090 smux_oid_dump ("Trap", trapobj[i].name, (trapobj[i].namelen));
1091 smux_oid_dump ("Trap", iname, inamelen);
1093 smux_oid_dump ("Trap", oid, oid_len);
1094 zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ, (u_long)oid_len);
1097 ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
1099 if (debug_smux)
1100 zlog_debug ("smux_get result %d", ret);
1102 if (ret == 0)
1103 ptr = snmp_build_var_op (ptr, oid, &oid_len,
1104 val_type, val_len, val, &len);
1107 /* Now variable size is known, fill in size */
1108 asn_build_sequence(h1, &length,
1109 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1110 ptr - h1e);
1112 /* Fill in size of whole sequence */
1113 len = BUFSIZ;
1114 asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
1116 return send (smux_sock, buf, (ptr - buf), 0);
1120 smux_register (int sock)
1122 u_char buf[BUFSIZ];
1123 u_char *ptr;
1124 int ret;
1125 size_t len;
1126 long priority;
1127 long operation;
1128 struct subtree *subtree;
1129 struct listnode *node, *nnode;
1131 ret = 0;
1133 for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
1135 ptr = buf;
1136 len = BUFSIZ;
1138 /* SMUX RReq Header. */
1139 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
1141 /* Register MIB tree. */
1142 ptr = asn_build_objid (ptr, &len,
1143 (u_char)
1144 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
1145 subtree->name, subtree->name_len);
1147 /* Priority. */
1148 priority = -1;
1149 ptr = asn_build_int (ptr, &len,
1150 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1151 &priority, sizeof (priority));
1153 /* Operation. */
1154 operation = 2; /* Register R/W */
1155 ptr = asn_build_int (ptr, &len,
1156 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1157 &operation, sizeof (operation));
1159 if (debug_smux)
1161 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
1162 zlog_debug ("SMUX register priority: %ld", priority);
1163 zlog_debug ("SMUX register operation: %ld", operation);
1166 len = BUFSIZ;
1167 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
1168 ret = send (sock, buf, (ptr - buf), 0);
1169 if (ret < 0)
1170 return ret;
1172 return ret;
1175 /* Try to connect to SNMP agent. */
1177 smux_connect (struct thread *t)
1179 int ret;
1181 if (debug_smux)
1182 zlog_debug ("SMUX connect try %d", fail + 1);
1184 /* Clear thread poner of myself. */
1185 smux_connect_thread = NULL;
1187 /* Make socket. Try to connect. */
1188 smux_sock = smux_socket ();
1189 if (smux_sock < 0)
1191 if (++fail < SMUX_MAX_FAILURE)
1192 smux_event (SMUX_CONNECT, 0);
1193 return 0;
1196 /* Send OPEN PDU. */
1197 ret = smux_open (smux_sock);
1198 if (ret < 0)
1200 zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno));
1201 close (smux_sock);
1202 smux_sock = -1;
1203 if (++fail < SMUX_MAX_FAILURE)
1204 smux_event (SMUX_CONNECT, 0);
1205 return -1;
1208 /* Send any outstanding register PDUs. */
1209 ret = smux_register (smux_sock);
1210 if (ret < 0)
1212 zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno));
1213 close (smux_sock);
1214 smux_sock = -1;
1215 if (++fail < SMUX_MAX_FAILURE)
1216 smux_event (SMUX_CONNECT, 0);
1217 return -1;
1220 /* Everything goes fine. */
1221 smux_event (SMUX_READ, smux_sock);
1223 return 0;
1226 /* Clear all SMUX related resources. */
1227 void
1228 smux_stop ()
1230 if (smux_read_thread)
1231 thread_cancel (smux_read_thread);
1232 if (smux_connect_thread)
1233 thread_cancel (smux_connect_thread);
1235 if (smux_sock >= 0)
1237 close (smux_sock);
1238 smux_sock = -1;
1244 void
1245 smux_event (enum smux_event event, int sock)
1247 switch (event)
1249 case SMUX_SCHEDULE:
1250 smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
1251 break;
1252 case SMUX_CONNECT:
1253 smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
1254 break;
1255 case SMUX_READ:
1256 smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
1257 break;
1258 default:
1259 break;
1264 smux_str2oid (const char *str, oid *oid, size_t *oid_len)
1266 int len;
1267 int val;
1269 len = 0;
1270 val = 0;
1271 *oid_len = 0;
1273 if (*str == '.')
1274 str++;
1275 if (*str == '\0')
1276 return 0;
1278 while (1)
1280 if (! isdigit (*str))
1281 return -1;
1283 while (isdigit (*str))
1285 val *= 10;
1286 val += (*str - '0');
1287 str++;
1290 if (*str == '\0')
1291 break;
1292 if (*str != '.')
1293 return -1;
1295 oid[len++] = val;
1296 val = 0;
1297 str++;
1300 oid[len++] = val;
1301 *oid_len = len;
1303 return 0;
1306 oid *
1307 smux_oid_dup (oid *objid, size_t objid_len)
1309 oid *new;
1311 new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
1312 oid_copy (new, objid, objid_len);
1314 return new;
1318 smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str)
1320 int ret;
1321 oid oid[MAX_OID_LEN];
1322 size_t oid_len;
1324 ret = smux_str2oid (oid_str, oid, &oid_len);
1325 if (ret != 0)
1327 vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
1328 return CMD_WARNING;
1331 if (smux_oid)
1333 free (smux_oid);
1334 smux_oid = NULL;
1337 /* careful, smux_passwd might point to string constant */
1338 if (smux_passwd)
1340 free (smux_passwd);
1341 smux_passwd = NULL;
1344 smux_oid = smux_oid_dup (oid, oid_len);
1345 smux_oid_len = oid_len;
1347 if (passwd_str)
1348 smux_passwd = strdup (passwd_str);
1349 else
1350 smux_passwd = strdup ("");
1352 return 0;
1356 smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1357 size_t *var_len, WriteMethod **write_method)
1359 oid fulloid[MAX_OID_LEN];
1360 int ret;
1362 oid_copy (fulloid, v->name, v->namelen);
1363 fulloid[v->namelen] = 0;
1364 /* Check against full instance. */
1365 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1367 /* Check single instance. */
1368 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1369 return MATCH_FAILED;
1371 /* In case of getnext, fill in full instance. */
1372 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1373 *length = v->namelen + 1;
1375 *write_method = 0;
1376 *var_len = sizeof(long); /* default to 'long' results */
1378 return MATCH_SUCCEEDED;
1382 smux_peer_default ()
1384 if (smux_oid)
1386 free (smux_oid);
1387 smux_oid = NULL;
1390 /* careful, smux_passwd might be pointing at string constant */
1391 if (smux_passwd)
1393 free (smux_passwd);
1394 smux_passwd = NULL;
1397 return CMD_SUCCESS;
1400 DEFUN (smux_peer,
1401 smux_peer_cmd,
1402 "smux peer OID",
1403 "SNMP MUX protocol settings\n"
1404 "SNMP MUX peer settings\n"
1405 "Object ID used in SMUX peering\n")
1407 if (smux_peer_oid (vty, argv[0], NULL) == 0)
1409 smux_start();
1410 return CMD_SUCCESS;
1412 else
1413 return CMD_WARNING;
1416 DEFUN (smux_peer_password,
1417 smux_peer_password_cmd,
1418 "smux peer OID PASSWORD",
1419 "SNMP MUX protocol settings\n"
1420 "SNMP MUX peer settings\n"
1421 "SMUX peering object ID\n"
1422 "SMUX peering password\n")
1424 if (smux_peer_oid (vty, argv[0], argv[1]) == 0)
1426 smux_start();
1427 return CMD_SUCCESS;
1429 else
1430 return CMD_WARNING;
1433 DEFUN (no_smux_peer,
1434 no_smux_peer_cmd,
1435 "no smux peer",
1436 NO_STR
1437 "SNMP MUX protocol settings\n"
1438 "SNMP MUX peer settings\n")
1440 smux_stop();
1441 return smux_peer_default ();
1444 ALIAS (no_smux_peer,
1445 no_smux_peer_oid_cmd,
1446 "no smux peer OID",
1447 NO_STR
1448 "SNMP MUX protocol settings\n"
1449 "SNMP MUX peer settings\n"
1450 "SMUX peering object ID\n")
1452 ALIAS (no_smux_peer,
1453 no_smux_peer_oid_password_cmd,
1454 "no smux peer OID PASSWORD",
1455 NO_STR
1456 "SNMP MUX protocol settings\n"
1457 "SNMP MUX peer settings\n"
1458 "SMUX peering object ID\n"
1459 "SMUX peering password\n")
1462 config_write_smux (struct vty *vty)
1464 int first = 1;
1465 unsigned int i;
1467 if (smux_oid)
1469 vty_out (vty, "smux peer ");
1470 for (i = 0; i < smux_oid_len; i++)
1472 vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
1473 first = 0;
1475 vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
1477 return 0;
1480 /* Register subtree to smux master tree. */
1481 void
1482 smux_register_mib (const char *descr, struct variable *var,
1483 size_t width, int num,
1484 oid name[], size_t namelen)
1486 struct subtree *tree;
1488 tree = (struct subtree *)malloc(sizeof(struct subtree));
1489 oid_copy (tree->name, name, namelen);
1490 tree->name_len = namelen;
1491 tree->variables = var;
1492 tree->variables_num = num;
1493 tree->variables_width = width;
1494 tree->registered = 0;
1495 listnode_add_sort(treelist, tree);
1498 void
1499 smux_reset ()
1501 /* Setting configuration to default. */
1502 smux_peer_default ();
1505 /* Compare function to keep treelist sorted */
1506 static int
1507 smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
1509 return oid_compare(tree1->name, tree1->name_len,
1510 tree2->name, tree2->name_len);
1513 /* Initialize some values then schedule first SMUX connection. */
1514 void
1515 smux_init (struct thread_master *tm)
1517 /* copy callers thread master */
1518 master = tm;
1520 /* Make MIB tree. */
1521 treelist = list_new();
1522 treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
1524 /* Install commands. */
1525 install_node (&smux_node, config_write_smux);
1527 install_element (CONFIG_NODE, &smux_peer_cmd);
1528 install_element (CONFIG_NODE, &smux_peer_password_cmd);
1529 install_element (CONFIG_NODE, &no_smux_peer_cmd);
1530 install_element (CONFIG_NODE, &no_smux_peer_oid_cmd);
1531 install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd);
1534 void
1535 smux_start(void)
1537 /* Schedule first connection. */
1538 smux_event (SMUX_SCHEDULE, 0);
1540 #endif /* HAVE_SNMP */