~ubuntu-branches/ubuntu/warty/quagga/warty

« back to all changes in this revision

Viewing changes to lib/smux.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio M. Di Nitto
  • Date: 2004-06-29 09:50:59 UTC
  • Revision ID: james.westby@ubuntu.com-20040629095059-px1m2m108z4qw1mr
Tags: upstream-0.96.5
ImportĀ upstreamĀ versionĀ 0.96.5

Show diffs side-by-side

added added

removed removed

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