source: src/router/quagga/lib/smux.c @ 10627

Last change on this file since 10627 was 10627, checked in by BrainSlayer, 5 years ago

quagga update

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